diff options
author | Christian Grothoff <christian@grothoff.org> | 2007-09-09 03:56:10 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2007-09-09 03:56:10 +0000 |
commit | 21acb929f578eb8f876c235669b78d6b213ec315 (patch) | |
tree | 45f89714c45e2a4f0999f2601fb8df7076f5b4fd | |
parent | 5e828bda99ed11ae9f183965eece0b5931ec0270 (diff) | |
download | libmicrohttpd-21acb929f578eb8f876c235669b78d6b213ec315.tar.gz libmicrohttpd-21acb929f578eb8f876c235669b78d6b213ec315.zip |
incremental post processing API and implementation
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | README | 9 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/daemon/Makefile.am | 3 | ||||
-rw-r--r-- | src/daemon/connection.c | 299 | ||||
-rw-r--r-- | src/daemon/daemon.c | 115 | ||||
-rw-r--r-- | src/daemon/daemontest.c | 2 | ||||
-rw-r--r-- | src/daemon/daemontest_get.c | 2 | ||||
-rw-r--r-- | src/daemon/daemontest_large_put.c | 2 | ||||
-rw-r--r-- | src/daemon/daemontest_long_header.c | 2 | ||||
-rw-r--r-- | src/daemon/daemontest_post.c | 46 | ||||
-rw-r--r-- | src/daemon/daemontest_put.c | 11 | ||||
-rw-r--r-- | src/daemon/fileserver_example.c | 3 | ||||
-rw-r--r-- | src/daemon/internal.c | 23 | ||||
-rw-r--r-- | src/daemon/internal.h | 14 | ||||
-rw-r--r-- | src/daemon/minimal_example.c | 3 | ||||
-rw-r--r-- | src/include/microhttpd.h | 81 |
17 files changed, 306 insertions, 321 deletions
@@ -1,3 +1,11 @@ | |||
1 | Sat Sep 8 21:54:04 MDT 2007 | ||
2 | Extended API to allow for incremental POST | ||
3 | processing. The new API is binary-compatible | ||
4 | as long as the app does not handle POSTs, but | ||
5 | since that maybe the case, we're strictly speaking | ||
6 | breaking backwards compatibility (since url-encoded | ||
7 | POST data is no longer obtained the same way). - CG | ||
8 | |||
1 | Thu Aug 30 00:59:24 MDT 2007 | 9 | Thu Aug 30 00:59:24 MDT 2007 |
2 | Improving API to allow clients to associate state | 10 | Improving API to allow clients to associate state |
3 | with a connection and to be notified about request | 11 | with a connection and to be notified about request |
@@ -18,17 +18,8 @@ connection.c: | |||
18 | 18 | ||
19 | For POST: | 19 | For POST: |
20 | ========= | 20 | ========= |
21 | - find better way to handle POST data that does not fit into memory (#1221, API, TEST) | ||
22 | - add support to decode multipart/form-data (#1221, TEST) | 21 | - add support to decode multipart/form-data (#1221, TEST) |
23 | 22 | ||
24 | API Improvements: | ||
25 | ================= | ||
26 | - allow clients to associate a void * with each connection (for easier client state | ||
27 | management) | ||
28 | - allow clients to register callback to be invoked when connection is | ||
29 | timed out or otherwise completed / aborted / closed (for easier client | ||
30 | state clean up) | ||
31 | |||
32 | For SSL: | 23 | For SSL: |
33 | ======== | 24 | ======== |
34 | microhttpd.h: | 25 | microhttpd.h: |
diff --git a/configure.ac b/configure.ac index 44afee9e..1db29b83 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -21,8 +21,8 @@ | |||
21 | # | 21 | # |
22 | # | 22 | # |
23 | AC_PREREQ(2.57) | 23 | AC_PREREQ(2.57) |
24 | AC_INIT([libmicrohttpd], [0.0.3],[libmicrohttpd@gnunet.org]) | 24 | AC_INIT([libmicrohttpd], [0.1.0],[libmicrohttpd@gnunet.org]) |
25 | AM_INIT_AUTOMAKE([libmicrohttpd], [0.0.3]) | 25 | AM_INIT_AUTOMAKE([libmicrohttpd], [0.1.0]) |
26 | AM_CONFIG_HEADER([config.h]) | 26 | AM_CONFIG_HEADER([config.h]) |
27 | 27 | ||
28 | AH_TOP([#define _GNU_SOURCE 1]) | 28 | AH_TOP([#define _GNU_SOURCE 1]) |
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index e70583d3..3fa68c75 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am | |||
@@ -6,13 +6,14 @@ lib_LTLIBRARIES = \ | |||
6 | libmicrohttpd.la | 6 | libmicrohttpd.la |
7 | 7 | ||
8 | libmicrohttpd_la_LDFLAGS = \ | 8 | libmicrohttpd_la_LDFLAGS = \ |
9 | -export-dynamic -version-info 1:0:0 | 9 | -export-dynamic -version-info 2:0:0 |
10 | libmicrohttpd_la_SOURCES = \ | 10 | libmicrohttpd_la_SOURCES = \ |
11 | connection.c connection.h \ | 11 | connection.c connection.h \ |
12 | daemon.c \ | 12 | daemon.c \ |
13 | internal.c internal.h \ | 13 | internal.c internal.h \ |
14 | memorypool.c memorypool.h \ | 14 | memorypool.c memorypool.h \ |
15 | plibc.h \ | 15 | plibc.h \ |
16 | postprocessor.c \ | ||
16 | response.c response.h | 17 | response.c response.h |
17 | 18 | ||
18 | # example programs | 19 | # example programs |
diff --git a/src/daemon/connection.c b/src/daemon/connection.c index eef9e9e8..476d1c89 100644 --- a/src/daemon/connection.c +++ b/src/daemon/connection.c | |||
@@ -57,7 +57,7 @@ | |||
57 | /** | 57 | /** |
58 | * Add extra debug messages with reasons for closing connections | 58 | * Add extra debug messages with reasons for closing connections |
59 | * (non-error reasons). | 59 | * (non-error reasons). |
60 | */ | 60 | */ |
61 | #define DEBUG_CLOSE 0 | 61 | #define DEBUG_CLOSE 0 |
62 | 62 | ||
63 | 63 | ||
@@ -184,17 +184,17 @@ MHD_need_100_continue (struct MHD_Connection *connection) | |||
184 | * A serious error occured, close the | 184 | * A serious error occured, close the |
185 | * connection (and notify the application). | 185 | * connection (and notify the application). |
186 | */ | 186 | */ |
187 | static void | 187 | static void |
188 | connection_close_error(struct MHD_Connection * connection) | 188 | connection_close_error (struct MHD_Connection *connection) |
189 | { | 189 | { |
190 | SHUTDOWN (connection->socket_fd, SHUT_RDWR); | 190 | SHUTDOWN (connection->socket_fd, SHUT_RDWR); |
191 | CLOSE (connection->socket_fd); | 191 | CLOSE (connection->socket_fd); |
192 | connection->socket_fd = -1; | 192 | connection->socket_fd = -1; |
193 | if (connection->daemon->notify_completed != NULL) | 193 | if (connection->daemon->notify_completed != NULL) |
194 | connection->daemon->notify_completed(connection->daemon->notify_completed_cls, | 194 | connection->daemon->notify_completed (connection->daemon-> |
195 | connection, | 195 | notify_completed_cls, connection, |
196 | &connection->client_context, | 196 | &connection->client_context, |
197 | MHD_REQUEST_TERMINATED_WITH_ERROR); | 197 | MHD_REQUEST_TERMINATED_WITH_ERROR); |
198 | } | 198 | } |
199 | 199 | ||
200 | /** | 200 | /** |
@@ -222,11 +222,10 @@ ready_response (struct MHD_Connection *connection) | |||
222 | { | 222 | { |
223 | /* end of message, signal other side by closing! */ | 223 | /* end of message, signal other side by closing! */ |
224 | #if DEBUG_CLOSE | 224 | #if DEBUG_CLOSE |
225 | MHD_DLOG (connection->daemon, | 225 | MHD_DLOG (connection->daemon, "Closing connection (end of response)\n"); |
226 | "Closing connection (end of response)\n"); | ||
227 | #endif | 226 | #endif |
228 | response->total_size = connection->messagePos; | 227 | response->total_size = connection->messagePos; |
229 | connection_close_error(connection); | 228 | connection_close_error (connection); |
230 | return MHD_NO; | 229 | return MHD_NO; |
231 | } | 230 | } |
232 | response->data_start = connection->messagePos; | 231 | response->data_start = connection->messagePos; |
@@ -281,7 +280,6 @@ MHD_connection_get_fdset (struct MHD_Connection *connection, | |||
281 | { | 280 | { |
282 | if ((connection->read_close == MHD_NO) && | 281 | if ((connection->read_close == MHD_NO) && |
283 | ((connection->headersReceived == 1) && | 282 | ((connection->headersReceived == 1) && |
284 | (connection->post_processed == MHD_NO) && | ||
285 | (connection->readLoc == connection->read_buffer_size))) | 283 | (connection->readLoc == connection->read_buffer_size))) |
286 | { | 284 | { |
287 | /* try growing the read buffer, just in case */ | 285 | /* try growing the read buffer, just in case */ |
@@ -297,7 +295,7 @@ MHD_connection_get_fdset (struct MHD_Connection *connection, | |||
297 | connection->read_buffer_size = | 295 | connection->read_buffer_size = |
298 | connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; | 296 | connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; |
299 | FD_SET (fd, read_fd_set); | 297 | FD_SET (fd, read_fd_set); |
300 | if (fd > *max_fd) | 298 | if (fd > *max_fd) |
301 | *max_fd = fd; | 299 | *max_fd = fd; |
302 | } | 300 | } |
303 | } | 301 | } |
@@ -430,29 +428,6 @@ MHD_connection_add_header (struct MHD_Connection *connection, | |||
430 | } | 428 | } |
431 | 429 | ||
432 | /** | 430 | /** |
433 | * Process escape sequences ('+'=space, %HH) | ||
434 | */ | ||
435 | static void | ||
436 | MHD_http_unescape (char *val) | ||
437 | { | ||
438 | char *esc; | ||
439 | unsigned int num; | ||
440 | |||
441 | while (NULL != (esc = strstr (val, "+"))) | ||
442 | *esc = ' '; | ||
443 | while (NULL != (esc = strstr (val, "%"))) | ||
444 | { | ||
445 | if ((1 == sscanf (&esc[1], | ||
446 | "%2x", &num)) || (1 == sscanf (&esc[1], "%2X", &num))) | ||
447 | { | ||
448 | esc[0] = (unsigned char) num; | ||
449 | memmove (&esc[1], &esc[3], strlen (&esc[3])); | ||
450 | } | ||
451 | val = esc + 1; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * @return MHD_NO on failure (out of memory), MHD_YES for success | 431 | * @return MHD_NO on failure (out of memory), MHD_YES for success |
457 | */ | 432 | */ |
458 | static int | 433 | static int |
@@ -615,10 +590,11 @@ MHD_parse_connection_headers (struct MHD_Connection *connection) | |||
615 | const char *clen; | 590 | const char *clen; |
616 | const char *end; | 591 | const char *end; |
617 | unsigned long long cval; | 592 | unsigned long long cval; |
618 | struct MHD_Response * response; | 593 | struct MHD_Response *response; |
619 | 594 | ||
620 | if (connection->bodyReceived == 1) | 595 | if (connection->bodyReceived == 1) |
621 | abort (); | 596 | abort (); |
597 | colon = NULL; /* make gcc happy */ | ||
622 | last = NULL; | 598 | last = NULL; |
623 | while (NULL != (line = MHD_get_next_header_line (connection))) | 599 | while (NULL != (line = MHD_get_next_header_line (connection))) |
624 | { | 600 | { |
@@ -707,29 +683,28 @@ MHD_parse_connection_headers (struct MHD_Connection *connection) | |||
707 | this request */ | 683 | this request */ |
708 | connection->read_close = MHD_YES; | 684 | connection->read_close = MHD_YES; |
709 | } | 685 | } |
710 | 686 | ||
711 | if ( (0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) && | 687 | if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) |
712 | (NULL != connection->version) && | 688 | && (NULL != connection->version) |
713 | (0 == strcasecmp(MHD_HTTP_VERSION_1_1, | 689 | && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) |
714 | connection->version)) && | 690 | && (NULL == |
715 | (NULL == MHD_lookup_connection_value(connection, | 691 | MHD_lookup_connection_value (connection, MHD_HEADER_KIND, |
716 | MHD_HEADER_KIND, | 692 | MHD_HTTP_HEADER_HOST))) |
717 | MHD_HTTP_HEADER_HOST)) ) { | 693 | { |
718 | /* die, http 1.1 request without host and we are pedantic */ | 694 | /* die, http 1.1 request without host and we are pedantic */ |
719 | connection->bodyReceived = MHD_YES; | 695 | connection->bodyReceived = MHD_YES; |
720 | connection->read_close = MHD_YES; | 696 | connection->read_close = MHD_YES; |
721 | MHD_DLOG (connection->daemon, | 697 | MHD_DLOG (connection->daemon, |
722 | "Received `%s' request without `%s' header.\n", | 698 | "Received `%s' request without `%s' header.\n", |
723 | MHD_HTTP_VERSION_1_1, | 699 | MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST); |
724 | MHD_HTTP_HEADER_HOST); | 700 | response = |
725 | response = MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST), | 701 | MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST), |
726 | REQUEST_LACKS_HOST, MHD_NO, MHD_NO); | 702 | REQUEST_LACKS_HOST, MHD_NO, |
727 | MHD_queue_response (connection, | 703 | MHD_NO); |
728 | MHD_HTTP_BAD_REQUEST, | 704 | MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response); |
729 | response); | 705 | MHD_destroy_response (response); |
730 | MHD_destroy_response (response); | 706 | } |
731 | } | 707 | |
732 | |||
733 | break; | 708 | break; |
734 | } | 709 | } |
735 | /* line should be normal header line, find colon */ | 710 | /* line should be normal header line, find colon */ |
@@ -761,8 +736,8 @@ MHD_parse_connection_headers (struct MHD_Connection *connection) | |||
761 | return; | 736 | return; |
762 | DIE: | 737 | DIE: |
763 | MHD_DLOG (connection->daemon, | 738 | MHD_DLOG (connection->daemon, |
764 | "Closing connection (problem parsing headers)\n"); | 739 | "Closing connection (problem parsing headers)\n"); |
765 | connection_close_error(connection); | 740 | connection_close_error (connection); |
766 | } | 741 | } |
767 | 742 | ||
768 | 743 | ||
@@ -784,107 +759,6 @@ MHD_find_access_handler (struct MHD_Connection *connection) | |||
784 | return &connection->daemon->default_handler; | 759 | return &connection->daemon->default_handler; |
785 | } | 760 | } |
786 | 761 | ||
787 | /** | ||
788 | * Test if we are able to process the POST data. | ||
789 | * This depends on available memory (enough to load | ||
790 | * all of the POST data into the pool) and the | ||
791 | * content encoding of the POST data. And of course, | ||
792 | * this requires that the request is actually a | ||
793 | * POST request. | ||
794 | * | ||
795 | * @return MHD_YES if so | ||
796 | */ | ||
797 | static int | ||
798 | MHD_test_post_data (struct MHD_Connection *connection) | ||
799 | { | ||
800 | const char *encoding; | ||
801 | void *buf; | ||
802 | |||
803 | if ((connection->method == NULL) || | ||
804 | (connection->response != NULL) || | ||
805 | (0 != strcasecmp (connection->method, MHD_HTTP_METHOD_POST))) | ||
806 | return MHD_NO; | ||
807 | encoding = MHD_lookup_connection_value (connection, | ||
808 | MHD_HEADER_KIND, | ||
809 | MHD_HTTP_HEADER_CONTENT_TYPE); | ||
810 | if (encoding == NULL) | ||
811 | return MHD_NO; | ||
812 | if ((0 == strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, | ||
813 | encoding)) && (connection->uploadSize != -1)) | ||
814 | { | ||
815 | buf = MHD_pool_reallocate (connection->pool, | ||
816 | connection->read_buffer, | ||
817 | (connection->read_buffer == NULL) ? 0 : connection->read_buffer_size + 1, | ||
818 | connection->uploadSize + 1); | ||
819 | if (buf == NULL) | ||
820 | return MHD_NO; | ||
821 | connection->read_buffer_size = connection->uploadSize; | ||
822 | connection->read_buffer = buf; | ||
823 | return MHD_YES; | ||
824 | } | ||
825 | return MHD_NO; | ||
826 | } | ||
827 | |||
828 | /** | ||
829 | * Process the POST data here (adding to headers). | ||
830 | * | ||
831 | * Needs to first check POST encoding and then do | ||
832 | * the right thing (TM). The POST data is in the | ||
833 | * connection's post_data buffer between the postPos | ||
834 | * and postLoc offsets. The POST message maybe | ||
835 | * incomplete. The existing buffer (allocated from | ||
836 | * the pool) can be used and modified but must then | ||
837 | * be properly removed from the struct. | ||
838 | * | ||
839 | * @return MHD_YES on success, MHD_NO on error (i.e. out of | ||
840 | * memory). | ||
841 | */ | ||
842 | static int | ||
843 | MHD_parse_post_data (struct MHD_Connection *connection) | ||
844 | { | ||
845 | const char *encoding; | ||
846 | int ret; | ||
847 | |||
848 | encoding = MHD_lookup_connection_value (connection, | ||
849 | MHD_HEADER_KIND, | ||
850 | MHD_HTTP_HEADER_CONTENT_TYPE); | ||
851 | if (encoding == NULL) | ||
852 | return MHD_NO; | ||
853 | if (0 == strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding)) | ||
854 | { | ||
855 | /* add 0-termination, that's why the actual buffer size | ||
856 | is always 1 more than what is actually required for the data! */ | ||
857 | connection->read_buffer[connection->readLoc] = '\0'; | ||
858 | ret = parse_arguments (MHD_POSTDATA_KIND, | ||
859 | connection, connection->read_buffer); | ||
860 | /* invalidate read buffer for other uses -- | ||
861 | in particular, do not give it to the | ||
862 | client; if this were to be needed, we would | ||
863 | have to make a copy, which would double memory | ||
864 | requirements */ | ||
865 | connection->read_buffer_size = 0; | ||
866 | connection->readLoc = 0; | ||
867 | connection->uploadSize = 0; | ||
868 | connection->read_buffer = NULL; | ||
869 | return ret; | ||
870 | } | ||
871 | if (0 == strcasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding)) | ||
872 | { | ||
873 | /* this code should never been reached right now, | ||
874 | since the test_post_data function would already | ||
875 | return MHD_NO; code is here only for future | ||
876 | extensions... */ | ||
877 | /* see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 */ | ||
878 | MHD_DLOG (connection->daemon, | ||
879 | "Unsupported multipart encoding of POST data specified, not processing POST data.\n"); | ||
880 | return MHD_NO; | ||
881 | } | ||
882 | /* this should never be reached, just here for | ||
883 | error checking */ | ||
884 | MHD_DLOG (connection->daemon, | ||
885 | "Unknown encoding of POST data specified, not processing POST data.\n"); | ||
886 | return MHD_NO; | ||
887 | } | ||
888 | 762 | ||
889 | /** | 763 | /** |
890 | * Call the handler of the application for this | 764 | * Call the handler of the application for this |
@@ -908,12 +782,12 @@ MHD_call_connection_handler (struct MHD_Connection *connection) | |||
908 | connection->method, | 782 | connection->method, |
909 | connection->version, | 783 | connection->version, |
910 | connection->read_buffer, &processed, | 784 | connection->read_buffer, &processed, |
911 | &connection->client_context)) | 785 | &connection->client_context)) |
912 | { | 786 | { |
913 | /* serios internal error, close connection */ | 787 | /* serios internal error, close connection */ |
914 | MHD_DLOG (connection->daemon, | 788 | MHD_DLOG (connection->daemon, |
915 | "Internal application error, closing connection.\n"); | 789 | "Internal application error, closing connection.\n"); |
916 | connection_close_error(connection); | 790 | connection_close_error (connection); |
917 | return; | 791 | return; |
918 | } | 792 | } |
919 | /* dh left "processed" bytes in buffer for next time... */ | 793 | /* dh left "processed" bytes in buffer for next time... */ |
@@ -929,10 +803,11 @@ MHD_call_connection_handler (struct MHD_Connection *connection) | |||
929 | { | 803 | { |
930 | connection->bodyReceived = 1; | 804 | connection->bodyReceived = 1; |
931 | if (connection->read_buffer != NULL) | 805 | if (connection->read_buffer != NULL) |
932 | MHD_pool_reallocate(connection->pool, | 806 | MHD_pool_reallocate (connection->pool, |
933 | connection->read_buffer, | 807 | connection->read_buffer, |
934 | (connection->read_buffer == NULL) ? 0 : connection->read_buffer_size + 1, | 808 | (connection->read_buffer == |
935 | 0); | 809 | NULL) ? 0 : connection->read_buffer_size + 1, |
810 | 0); | ||
936 | connection->readLoc = 0; | 811 | connection->readLoc = 0; |
937 | connection->read_buffer_size = 0; | 812 | connection->read_buffer_size = 0; |
938 | connection->read_buffer = NULL; | 813 | connection->read_buffer = NULL; |
@@ -957,7 +832,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
957 | if (connection->pool == NULL) | 832 | if (connection->pool == NULL) |
958 | { | 833 | { |
959 | MHD_DLOG (connection->daemon, "Failed to create memory pool!\n"); | 834 | MHD_DLOG (connection->daemon, "Failed to create memory pool!\n"); |
960 | connection_close_error(connection); | 835 | connection_close_error (connection); |
961 | return MHD_NO; | 836 | return MHD_NO; |
962 | } | 837 | } |
963 | if ((connection->readLoc >= connection->read_buffer_size) && | 838 | if ((connection->readLoc >= connection->read_buffer_size) && |
@@ -995,15 +870,14 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
995 | return MHD_NO; | 870 | return MHD_NO; |
996 | MHD_DLOG (connection->daemon, | 871 | MHD_DLOG (connection->daemon, |
997 | "Failed to receive data: %s\n", STRERROR (errno)); | 872 | "Failed to receive data: %s\n", STRERROR (errno)); |
998 | connection_close_error(connection); | 873 | connection_close_error (connection); |
999 | return MHD_YES; | 874 | return MHD_YES; |
1000 | } | 875 | } |
1001 | if (bytes_read == 0) | 876 | if (bytes_read == 0) |
1002 | { | 877 | { |
1003 | /* other side closed connection */ | 878 | /* other side closed connection */ |
1004 | connection->read_close = MHD_YES; | 879 | connection->read_close = MHD_YES; |
1005 | if ( (connection->headersReceived == 1) && | 880 | if ((connection->headersReceived == 1) && (connection->readLoc > 0)) |
1006 | (connection->readLoc > 0) ) | ||
1007 | MHD_call_connection_handler (connection); | 881 | MHD_call_connection_handler (connection); |
1008 | #if DEBUG_CLOSE | 882 | #if DEBUG_CLOSE |
1009 | MHD_DLOG (connection->daemon, | 883 | MHD_DLOG (connection->daemon, |
@@ -1014,24 +888,9 @@ MHD_connection_handle_read (struct MHD_Connection *connection) | |||
1014 | } | 888 | } |
1015 | connection->readLoc += bytes_read; | 889 | connection->readLoc += bytes_read; |
1016 | if (connection->headersReceived == 0) | 890 | if (connection->headersReceived == 0) |
1017 | { | 891 | MHD_parse_connection_headers (connection); |
1018 | MHD_parse_connection_headers (connection); | 892 | if ((connection->headersReceived == 1) && (connection->method != NULL)) |
1019 | if (connection->headersReceived == 1) | 893 | MHD_call_connection_handler (connection); |
1020 | { | ||
1021 | connection->post_processed = MHD_test_post_data (connection); | ||
1022 | } | ||
1023 | } | ||
1024 | if (connection->headersReceived == 1) | ||
1025 | { | ||
1026 | if ((connection->post_processed == MHD_YES) && | ||
1027 | (connection->uploadSize == connection->readLoc)) | ||
1028 | if (MHD_NO == MHD_parse_post_data (connection)) | ||
1029 | connection->post_processed = MHD_NO; | ||
1030 | if (((connection->post_processed == MHD_NO) || | ||
1031 | (connection->read_buffer_size == connection->readLoc)) && | ||
1032 | (connection->method != NULL)) | ||
1033 | MHD_call_connection_handler (connection); | ||
1034 | } | ||
1035 | return MHD_YES; | 894 | return MHD_YES; |
1036 | } | 895 | } |
1037 | 896 | ||
@@ -1171,14 +1030,13 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1171 | return MHD_YES; | 1030 | return MHD_YES; |
1172 | MHD_DLOG (connection->daemon, | 1031 | MHD_DLOG (connection->daemon, |
1173 | "Failed to send data: %s\n", STRERROR (errno)); | 1032 | "Failed to send data: %s\n", STRERROR (errno)); |
1174 | connection_close_error(connection); | 1033 | connection_close_error (connection); |
1175 | return MHD_YES; | 1034 | return MHD_YES; |
1176 | } | 1035 | } |
1177 | #if DEBUG_SEND_DATA | 1036 | #if DEBUG_SEND_DATA |
1178 | fprintf(stderr, | 1037 | fprintf (stderr, |
1179 | "Sent 100 continue response: `%.*s'\n", | 1038 | "Sent 100 continue response: `%.*s'\n", |
1180 | ret, | 1039 | ret, &HTTP_100_CONTINUE[connection->continuePos]); |
1181 | &HTTP_100_CONTINUE[connection->continuePos]); | ||
1182 | #endif | 1040 | #endif |
1183 | connection->continuePos += ret; | 1041 | connection->continuePos += ret; |
1184 | return MHD_YES; | 1042 | return MHD_YES; |
@@ -1195,9 +1053,9 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1195 | (MHD_NO == MHD_build_header_response (connection))) | 1053 | (MHD_NO == MHD_build_header_response (connection))) |
1196 | { | 1054 | { |
1197 | /* oops - close! */ | 1055 | /* oops - close! */ |
1198 | MHD_DLOG (connection->daemon, | 1056 | MHD_DLOG (connection->daemon, |
1199 | "Closing connection (failed to create response header)\n"); | 1057 | "Closing connection (failed to create response header)\n"); |
1200 | connection_close_error(connection); | 1058 | connection_close_error (connection); |
1201 | return MHD_NO; | 1059 | return MHD_NO; |
1202 | } | 1060 | } |
1203 | ret = SEND (connection->socket_fd, | 1061 | ret = SEND (connection->socket_fd, |
@@ -1209,14 +1067,13 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1209 | return MHD_YES; | 1067 | return MHD_YES; |
1210 | MHD_DLOG (connection->daemon, | 1068 | MHD_DLOG (connection->daemon, |
1211 | "Failed to send data: %s\n", STRERROR (errno)); | 1069 | "Failed to send data: %s\n", STRERROR (errno)); |
1212 | connection_close_error(connection); | 1070 | connection_close_error (connection); |
1213 | return MHD_YES; | 1071 | return MHD_YES; |
1214 | } | 1072 | } |
1215 | #if DEBUG_SEND_DATA | 1073 | #if DEBUG_SEND_DATA |
1216 | fprintf(stderr, | 1074 | fprintf (stderr, |
1217 | "Sent HEADER response: `%.*s'\n", | 1075 | "Sent HEADER response: `%.*s'\n", |
1218 | ret, | 1076 | ret, &connection->write_buffer[connection->writePos]); |
1219 | &connection->write_buffer[connection->writePos]); | ||
1220 | #endif | 1077 | #endif |
1221 | connection->writePos += ret; | 1078 | connection->writePos += ret; |
1222 | if (connection->writeLoc == connection->writePos) | 1079 | if (connection->writeLoc == connection->writePos) |
@@ -1259,14 +1116,14 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1259 | return MHD_YES; | 1116 | return MHD_YES; |
1260 | MHD_DLOG (connection->daemon, | 1117 | MHD_DLOG (connection->daemon, |
1261 | "Failed to send data: %s\n", STRERROR (errno)); | 1118 | "Failed to send data: %s\n", STRERROR (errno)); |
1262 | connection_close_error(connection); | 1119 | connection_close_error (connection); |
1263 | return MHD_YES; | 1120 | return MHD_YES; |
1264 | } | 1121 | } |
1265 | #if DEBUG_SEND_DATA | 1122 | #if DEBUG_SEND_DATA |
1266 | fprintf(stderr, | 1123 | fprintf (stderr, |
1267 | "Sent DATA response: `%.*s'\n", | 1124 | "Sent DATA response: `%.*s'\n", |
1268 | ret, | 1125 | ret, |
1269 | &response->data[connection->messagePos - response->data_start]); | 1126 | &response->data[connection->messagePos - response->data_start]); |
1270 | #endif | 1127 | #endif |
1271 | connection->messagePos += ret; | 1128 | connection->messagePos += ret; |
1272 | if (connection->messagePos > response->total_size) | 1129 | if (connection->messagePos > response->total_size) |
@@ -1277,11 +1134,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1277 | (connection->headersReceived == 0)) | 1134 | (connection->headersReceived == 0)) |
1278 | abort (); /* internal error */ | 1135 | abort (); /* internal error */ |
1279 | MHD_destroy_response (response); | 1136 | MHD_destroy_response (response); |
1280 | if (connection->daemon->notify_completed != NULL) | 1137 | if (connection->daemon->notify_completed != NULL) |
1281 | connection->daemon->notify_completed(connection->daemon->notify_completed_cls, | 1138 | connection->daemon->notify_completed (connection->daemon-> |
1282 | connection, | 1139 | notify_completed_cls, |
1283 | &connection->client_context, | 1140 | connection, |
1284 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | 1141 | &connection->client_context, |
1142 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | ||
1285 | connection->client_context = NULL; | 1143 | connection->client_context = NULL; |
1286 | connection->continuePos = 0; | 1144 | connection->continuePos = 0; |
1287 | connection->responseCode = 0; | 1145 | connection->responseCode = 0; |
@@ -1297,14 +1155,15 @@ MHD_connection_handle_write (struct MHD_Connection *connection) | |||
1297 | (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) | 1155 | (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) |
1298 | { | 1156 | { |
1299 | /* closed for reading => close for good! */ | 1157 | /* closed for reading => close for good! */ |
1300 | if (connection->socket_fd != -1) { | 1158 | if (connection->socket_fd != -1) |
1159 | { | ||
1301 | #if DEBUG_CLOSE | 1160 | #if DEBUG_CLOSE |
1302 | MHD_DLOG (connection->daemon, | 1161 | MHD_DLOG (connection->daemon, |
1303 | "Closing connection (http 1.0 or end-of-stream for unknown content length)\n"); | 1162 | "Closing connection (http 1.0 or end-of-stream for unknown content length)\n"); |
1304 | #endif | 1163 | #endif |
1305 | SHUTDOWN (connection->socket_fd, SHUT_RDWR); | 1164 | SHUTDOWN (connection->socket_fd, SHUT_RDWR); |
1306 | CLOSE (connection->socket_fd); | 1165 | CLOSE (connection->socket_fd); |
1307 | } | 1166 | } |
1308 | connection->socket_fd = -1; | 1167 | connection->socket_fd = -1; |
1309 | } | 1168 | } |
1310 | connection->version = NULL; | 1169 | connection->version = NULL; |
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index 3b8b1111..346abedf 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c | |||
@@ -225,8 +225,8 @@ MHD_handle_connection (void *data) | |||
225 | if (con->socket_fd != -1) | 225 | if (con->socket_fd != -1) |
226 | { | 226 | { |
227 | #if DEBUG_CLOSE | 227 | #if DEBUG_CLOSE |
228 | MHD_DLOG (con->daemon, | 228 | MHD_DLOG (con->daemon, |
229 | "Processing thread terminating, closing connection\n"); | 229 | "Processing thread terminating, closing connection\n"); |
230 | #endif | 230 | #endif |
231 | SHUTDOWN (con->socket_fd, SHUT_RDWR); | 231 | SHUTDOWN (con->socket_fd, SHUT_RDWR); |
232 | CLOSE (con->socket_fd); | 232 | CLOSE (con->socket_fd); |
@@ -259,10 +259,11 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
259 | if ((s < 0) || (addrlen <= 0)) | 259 | if ((s < 0) || (addrlen <= 0)) |
260 | { | 260 | { |
261 | MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); | 261 | MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); |
262 | if (s != -1) { | 262 | if (s != -1) |
263 | SHUTDOWN (s, SHUT_RDWR); | 263 | { |
264 | CLOSE (s); /* just in case */ | 264 | SHUTDOWN (s, SHUT_RDWR); |
265 | } | 265 | CLOSE (s); /* just in case */ |
266 | } | ||
266 | return MHD_NO; | 267 | return MHD_NO; |
267 | } | 268 | } |
268 | if (daemon->max_connections == 0) | 269 | if (daemon->max_connections == 0) |
@@ -278,8 +279,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
278 | (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen))) | 279 | (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen))) |
279 | { | 280 | { |
280 | #if DEBUG_CLOSE | 281 | #if DEBUG_CLOSE |
281 | MHD_DLOG (daemon, | 282 | MHD_DLOG (daemon, "Connection rejected, closing connection\n"); |
282 | "Connection rejected, closing connection\n"); | ||
283 | #endif | 283 | #endif |
284 | SHUTDOWN (s, SHUT_RDWR); | 284 | SHUTDOWN (s, SHUT_RDWR); |
285 | CLOSE (s); | 285 | CLOSE (s); |
@@ -357,17 +357,16 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
357 | if ((pos->last_activity < timeout) && (pos->socket_fd != -1)) | 357 | if ((pos->last_activity < timeout) && (pos->socket_fd != -1)) |
358 | { | 358 | { |
359 | #if DEBUG_CLOSE | 359 | #if DEBUG_CLOSE |
360 | MHD_DLOG (daemon, | 360 | MHD_DLOG (daemon, "Connection timed out, closing connection\n"); |
361 | "Connection timed out, closing connection\n"); | ||
362 | #endif | 361 | #endif |
363 | SHUTDOWN (pos->socket_fd, SHUT_RDWR); | 362 | SHUTDOWN (pos->socket_fd, SHUT_RDWR); |
364 | CLOSE (pos->socket_fd); | 363 | CLOSE (pos->socket_fd); |
365 | pos->socket_fd = -1; | 364 | pos->socket_fd = -1; |
366 | if (pos->daemon->notify_completed != NULL) | 365 | if (pos->daemon->notify_completed != NULL) |
367 | pos->daemon->notify_completed(pos->daemon->notify_completed_cls, | 366 | pos->daemon->notify_completed (pos->daemon->notify_completed_cls, |
368 | pos, | 367 | pos, |
369 | &pos->client_context, | 368 | &pos->client_context, |
370 | MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | 369 | MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); |
371 | } | 370 | } |
372 | if (pos->socket_fd == -1) | 371 | if (pos->socket_fd == -1) |
373 | { | 372 | { |
@@ -472,19 +471,19 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
472 | FD_ZERO (&ws); | 471 | FD_ZERO (&ws); |
473 | FD_ZERO (&es); | 472 | FD_ZERO (&es); |
474 | max = 0; | 473 | max = 0; |
475 | 474 | ||
476 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 475 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
477 | { | 476 | { |
478 | /* single-threaded, go over everything */ | 477 | /* single-threaded, go over everything */ |
479 | if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max)) | 478 | if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max)) |
480 | return MHD_NO; | 479 | return MHD_NO; |
481 | } | 480 | } |
482 | else | 481 | else |
483 | { | 482 | { |
484 | /* accept only, have one thread per connection */ | 483 | /* accept only, have one thread per connection */ |
485 | max = daemon->socket_fd; | 484 | max = daemon->socket_fd; |
486 | if (max == -1) | 485 | if (max == -1) |
487 | return MHD_NO; | 486 | return MHD_NO; |
488 | FD_SET (max, &rs); | 487 | FD_SET (max, &rs); |
489 | } | 488 | } |
490 | if (may_block == MHD_NO) | 489 | if (may_block == MHD_NO) |
@@ -496,21 +495,20 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
496 | { | 495 | { |
497 | /* ltimeout is in ms */ | 496 | /* ltimeout is in ms */ |
498 | if (MHD_YES == MHD_get_timeout (daemon, <imeout)) | 497 | if (MHD_YES == MHD_get_timeout (daemon, <imeout)) |
499 | { | 498 | { |
500 | timeout.tv_usec = (ltimeout % 1000) * 1000; | 499 | timeout.tv_usec = (ltimeout % 1000) * 1000; |
501 | timeout.tv_sec = ltimeout / 1000; | 500 | timeout.tv_sec = ltimeout / 1000; |
502 | may_block = MHD_NO; | 501 | may_block = MHD_NO; |
503 | } | 502 | } |
504 | } | 503 | } |
505 | num_ready = SELECT (max + 1, | 504 | num_ready = SELECT (max + 1, |
506 | &rs, &ws, &es, | 505 | &rs, &ws, &es, may_block == MHD_NO ? &timeout : NULL); |
507 | may_block == MHD_NO ? &timeout : NULL); | ||
508 | if (daemon->shutdown == MHD_YES) | 506 | if (daemon->shutdown == MHD_YES) |
509 | return MHD_NO; | 507 | return MHD_NO; |
510 | if (num_ready < 0) | 508 | if (num_ready < 0) |
511 | { | 509 | { |
512 | if (errno == EINTR) | 510 | if (errno == EINTR) |
513 | return MHD_YES; | 511 | return MHD_YES; |
514 | MHD_DLOG (daemon, "Select failed: %s\n", STRERROR (errno)); | 512 | MHD_DLOG (daemon, "Select failed: %s\n", STRERROR (errno)); |
515 | return MHD_NO; | 513 | return MHD_NO; |
516 | } | 514 | } |
@@ -525,23 +523,23 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
525 | now = time (NULL); | 523 | now = time (NULL); |
526 | pos = daemon->connections; | 524 | pos = daemon->connections; |
527 | while (pos != NULL) | 525 | while (pos != NULL) |
528 | { | 526 | { |
529 | ds = pos->socket_fd; | 527 | ds = pos->socket_fd; |
530 | if (ds != -1) | 528 | if (ds != -1) |
531 | { | 529 | { |
532 | if (FD_ISSET (ds, &rs)) | 530 | if (FD_ISSET (ds, &rs)) |
533 | { | 531 | { |
534 | pos->last_activity = now; | 532 | pos->last_activity = now; |
535 | MHD_connection_handle_read (pos); | 533 | MHD_connection_handle_read (pos); |
536 | } | 534 | } |
537 | if (FD_ISSET (ds, &ws)) | 535 | if (FD_ISSET (ds, &ws)) |
538 | { | 536 | { |
539 | pos->last_activity = now; | 537 | pos->last_activity = now; |
540 | MHD_connection_handle_write (pos); | 538 | MHD_connection_handle_write (pos); |
541 | } | 539 | } |
542 | } | 540 | } |
543 | pos = pos->next; | 541 | pos = pos->next; |
544 | } | 542 | } |
545 | } | 543 | } |
546 | return MHD_YES; | 544 | return MHD_YES; |
547 | } | 545 | } |
@@ -694,10 +692,11 @@ MHD_start_daemon (unsigned int options, | |||
694 | case MHD_OPTION_CONNECTION_TIMEOUT: | 692 | case MHD_OPTION_CONNECTION_TIMEOUT: |
695 | retVal->connection_timeout = va_arg (ap, unsigned int); | 693 | retVal->connection_timeout = va_arg (ap, unsigned int); |
696 | break; | 694 | break; |
697 | case MHD_OPTION_NOTIFY_COMPLETED: | 695 | case MHD_OPTION_NOTIFY_COMPLETED: |
698 | retVal->notify_completed = va_arg(ap, MHD_RequestCompletedCallback); | 696 | retVal->notify_completed = |
699 | retVal->notify_completed_cls = va_arg(ap, void *); | 697 | va_arg (ap, MHD_RequestCompletedCallback); |
700 | break; | 698 | retVal->notify_completed_cls = va_arg (ap, void *); |
699 | break; | ||
701 | default: | 700 | default: |
702 | fprintf (stderr, | 701 | fprintf (stderr, |
703 | "Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n"); | 702 | "Invalid MHD_OPTION argument! (Did you terminate the list with MHD_OPTION_END?)\n"); |
@@ -733,8 +732,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
733 | fd = daemon->socket_fd; | 732 | fd = daemon->socket_fd; |
734 | daemon->socket_fd = -1; | 733 | daemon->socket_fd = -1; |
735 | #if DEBUG_CLOSE | 734 | #if DEBUG_CLOSE |
736 | MHD_DLOG (daemon, | 735 | MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); |
737 | "MHD shutdown, closing listen socket\n"); | ||
738 | #endif | 736 | #endif |
739 | CLOSE (fd); | 737 | CLOSE (fd); |
740 | if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || | 738 | if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || |
@@ -748,16 +746,15 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
748 | if (-1 != daemon->connections->socket_fd) | 746 | if (-1 != daemon->connections->socket_fd) |
749 | { | 747 | { |
750 | #if DEBUG_CLOSE | 748 | #if DEBUG_CLOSE |
751 | MHD_DLOG (daemon, | 749 | MHD_DLOG (daemon, "MHD shutdown, closing active connections\n"); |
752 | "MHD shutdown, closing active connections\n"); | ||
753 | #endif | 750 | #endif |
754 | if (daemon->notify_completed != NULL) | 751 | if (daemon->notify_completed != NULL) |
755 | daemon->notify_completed(daemon->notify_completed_cls, | 752 | daemon->notify_completed (daemon->notify_completed_cls, |
756 | daemon->connections, | 753 | daemon->connections, |
757 | &daemon->connections->client_context, | 754 | &daemon->connections->client_context, |
758 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); | 755 | MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); |
759 | SHUTDOWN (daemon->connections->socket_fd, SHUT_RDWR); | 756 | SHUTDOWN (daemon->connections->socket_fd, SHUT_RDWR); |
760 | CLOSE (daemon->connections->socket_fd); | 757 | CLOSE (daemon->connections->socket_fd); |
761 | daemon->connections->socket_fd = -1; | 758 | daemon->connections->socket_fd = -1; |
762 | } | 759 | } |
763 | MHD_cleanup_connections (daemon); | 760 | MHD_cleanup_connections (daemon); |
diff --git a/src/daemon/daemontest.c b/src/daemon/daemontest.c index 2ecb87f2..8048b438 100644 --- a/src/daemon/daemontest.c +++ b/src/daemon/daemontest.c | |||
@@ -65,7 +65,7 @@ ahc_nothing (void *cls, | |||
65 | const char *method, | 65 | const char *method, |
66 | const char *version, | 66 | const char *version, |
67 | const char *upload_data, unsigned int *upload_data_size, | 67 | const char *upload_data, unsigned int *upload_data_size, |
68 | void ** unused) | 68 | void **unused) |
69 | { | 69 | { |
70 | return MHD_NO; | 70 | return MHD_NO; |
71 | } | 71 | } |
diff --git a/src/daemon/daemontest_get.c b/src/daemon/daemontest_get.c index 79726a11..3f0b36ba 100644 --- a/src/daemon/daemontest_get.c +++ b/src/daemon/daemontest_get.c | |||
@@ -64,7 +64,7 @@ ahc_echo (void *cls, | |||
64 | const char *method, | 64 | const char *method, |
65 | const char *version, | 65 | const char *version, |
66 | const char *upload_data, unsigned int *upload_data_size, | 66 | const char *upload_data, unsigned int *upload_data_size, |
67 | void ** unused) | 67 | void **unused) |
68 | { | 68 | { |
69 | const char *me = cls; | 69 | const char *me = cls; |
70 | struct MHD_Response *response; | 70 | struct MHD_Response *response; |
diff --git a/src/daemon/daemontest_large_put.c b/src/daemon/daemontest_large_put.c index f4ae5583..2a9ad4fa 100644 --- a/src/daemon/daemontest_large_put.c +++ b/src/daemon/daemontest_large_put.c | |||
@@ -86,7 +86,7 @@ ahc_echo (void *cls, | |||
86 | const char *method, | 86 | const char *method, |
87 | const char *version, | 87 | const char *version, |
88 | const char *upload_data, unsigned int *upload_data_size, | 88 | const char *upload_data, unsigned int *upload_data_size, |
89 | void ** unused) | 89 | void **unused) |
90 | { | 90 | { |
91 | int *done = cls; | 91 | int *done = cls; |
92 | struct MHD_Response *response; | 92 | struct MHD_Response *response; |
diff --git a/src/daemon/daemontest_long_header.c b/src/daemon/daemontest_long_header.c index 6a451136..22368e9c 100644 --- a/src/daemon/daemontest_long_header.c +++ b/src/daemon/daemontest_long_header.c | |||
@@ -70,7 +70,7 @@ ahc_echo (void *cls, | |||
70 | const char *method, | 70 | const char *method, |
71 | const char *version, | 71 | const char *version, |
72 | const char *upload_data, unsigned int *upload_data_size, | 72 | const char *upload_data, unsigned int *upload_data_size, |
73 | void ** unused) | 73 | void **unused) |
74 | { | 74 | { |
75 | const char *me = cls; | 75 | const char *me = cls; |
76 | struct MHD_Response *response; | 76 | struct MHD_Response *response; |
diff --git a/src/daemon/daemontest_post.c b/src/daemon/daemontest_post.c index 10f6ea97..00bec910 100644 --- a/src/daemon/daemontest_post.c +++ b/src/daemon/daemontest_post.c | |||
@@ -63,6 +63,27 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | |||
63 | return size * nmemb; | 63 | return size * nmemb; |
64 | } | 64 | } |
65 | 65 | ||
66 | /** | ||
67 | * Note that this post_iterator is not perfect | ||
68 | * in that it fails to support incremental processing. | ||
69 | * (to be fixed in the future) | ||
70 | */ | ||
71 | static int | ||
72 | post_iterator (void *cls, | ||
73 | enum MHD_ValueKind kind, | ||
74 | const char *key, const char *value, size_t off, size_t size) | ||
75 | { | ||
76 | int *eok = cls; | ||
77 | |||
78 | if ((0 == strcmp (key, "name")) && | ||
79 | (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size))) | ||
80 | (*eok) |= 1; | ||
81 | if ((0 == strcmp (key, "project")) && | ||
82 | (size == strlen ("curl")) && (0 == strncmp (value, "curl", size))) | ||
83 | (*eok) |= 2; | ||
84 | return MHD_YES; | ||
85 | } | ||
86 | |||
66 | static int | 87 | static int |
67 | ahc_echo (void *cls, | 88 | ahc_echo (void *cls, |
68 | struct MHD_Connection *connection, | 89 | struct MHD_Connection *connection, |
@@ -70,31 +91,38 @@ ahc_echo (void *cls, | |||
70 | const char *method, | 91 | const char *method, |
71 | const char *version, | 92 | const char *version, |
72 | const char *upload_data, unsigned int *upload_data_size, | 93 | const char *upload_data, unsigned int *upload_data_size, |
73 | void ** unused) | 94 | void **unused) |
74 | { | 95 | { |
96 | static int eok; | ||
75 | struct MHD_Response *response; | 97 | struct MHD_Response *response; |
98 | struct MHD_PostProcessor *pp; | ||
76 | int ret; | 99 | int ret; |
77 | const char *r1; | ||
78 | const char *r2; | ||
79 | 100 | ||
80 | if (0 != strcmp ("POST", method)) | 101 | if (0 != strcmp ("POST", method)) |
81 | { | 102 | { |
82 | printf ("METHOD: %s\n", method); | 103 | printf ("METHOD: %s\n", method); |
83 | return MHD_NO; /* unexpected method */ | 104 | return MHD_NO; /* unexpected method */ |
84 | } | 105 | } |
85 | r1 = MHD_lookup_connection_value (connection, MHD_POSTDATA_KIND, "name"); | 106 | pp = *unused; |
86 | r2 = MHD_lookup_connection_value (connection, MHD_POSTDATA_KIND, "project"); | 107 | if (pp == NULL) |
87 | if ((r1 != NULL) && | 108 | { |
88 | (r2 != NULL) && | 109 | eok = 0; |
89 | (0 == strcmp ("daniel", r1)) && (0 == strcmp ("curl", r2))) | 110 | pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok); |
111 | *unused = pp; | ||
112 | } | ||
113 | MHD_post_process (pp, upload_data, *upload_data_size); | ||
114 | if ((eok == 3) && (0 == *upload_data_size)) | ||
90 | { | 115 | { |
91 | response = MHD_create_response_from_data (strlen (url), | 116 | response = MHD_create_response_from_data (strlen (url), |
92 | (void *) url, | 117 | (void *) url, |
93 | MHD_NO, MHD_YES); | 118 | MHD_NO, MHD_YES); |
94 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | 119 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); |
95 | MHD_destroy_response (response); | 120 | MHD_destroy_response (response); |
96 | return MHD_YES; /* done */ | 121 | MHD_destroy_post_processor (pp); |
122 | *unused = NULL; | ||
123 | return ret; | ||
97 | } | 124 | } |
125 | *upload_data_size = 0; | ||
98 | return MHD_YES; | 126 | return MHD_YES; |
99 | } | 127 | } |
100 | 128 | ||
diff --git a/src/daemon/daemontest_put.c b/src/daemon/daemontest_put.c index ad761025..2c3acfdb 100644 --- a/src/daemon/daemontest_put.c +++ b/src/daemon/daemontest_put.c | |||
@@ -77,7 +77,7 @@ ahc_echo (void *cls, | |||
77 | const char *method, | 77 | const char *method, |
78 | const char *version, | 78 | const char *version, |
79 | const char *upload_data, unsigned int *upload_data_size, | 79 | const char *upload_data, unsigned int *upload_data_size, |
80 | void ** unused) | 80 | void **unused) |
81 | { | 81 | { |
82 | int *done = cls; | 82 | int *done = cls; |
83 | struct MHD_Response *response; | 83 | struct MHD_Response *response; |
@@ -363,10 +363,11 @@ main (int argc, char *const *argv) | |||
363 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | 363 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) |
364 | return 2; | 364 | return 2; |
365 | errorCount += testInternalPut (); | 365 | errorCount += testInternalPut (); |
366 | if (0) { | 366 | if (0) |
367 | errorCount += testMultithreadedPut (); | 367 | { |
368 | errorCount += testExternalPut (); | 368 | errorCount += testMultithreadedPut (); |
369 | } | 369 | errorCount += testExternalPut (); |
370 | } | ||
370 | if (errorCount != 0) | 371 | if (errorCount != 0) |
371 | fprintf (stderr, "Error (code: %u)\n", errorCount); | 372 | fprintf (stderr, "Error (code: %u)\n", errorCount); |
372 | curl_global_cleanup (); | 373 | curl_global_cleanup (); |
diff --git a/src/daemon/fileserver_example.c b/src/daemon/fileserver_example.c index 15b6aa24..c5bf762b 100644 --- a/src/daemon/fileserver_example.c +++ b/src/daemon/fileserver_example.c | |||
@@ -52,8 +52,7 @@ ahc_echo (void *cls, | |||
52 | const char *url, | 52 | const char *url, |
53 | const char *method, | 53 | const char *method, |
54 | const char *upload_data, | 54 | const char *upload_data, |
55 | const char *version, unsigned int *upload_data_size, | 55 | const char *version, unsigned int *upload_data_size, void **unused) |
56 | void ** unused) | ||
57 | { | 56 | { |
58 | struct MHD_Response *response; | 57 | struct MHD_Response *response; |
59 | int ret; | 58 | int ret; |
diff --git a/src/daemon/internal.c b/src/daemon/internal.c index 0407cfa9..85c17b16 100644 --- a/src/daemon/internal.c +++ b/src/daemon/internal.c | |||
@@ -42,3 +42,26 @@ MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...) | |||
42 | VFPRINTF (stderr, format, va); | 42 | VFPRINTF (stderr, format, va); |
43 | va_end (va); | 43 | va_end (va); |
44 | } | 44 | } |
45 | |||
46 | /** | ||
47 | * Process escape sequences ('+'=space, %HH) | ||
48 | */ | ||
49 | void | ||
50 | MHD_http_unescape (char *val) | ||
51 | { | ||
52 | char *esc; | ||
53 | unsigned int num; | ||
54 | |||
55 | while (NULL != (esc = strstr (val, "+"))) | ||
56 | *esc = ' '; | ||
57 | while (NULL != (esc = strstr (val, "%"))) | ||
58 | { | ||
59 | if ((1 == sscanf (&esc[1], | ||
60 | "%2x", &num)) || (1 == sscanf (&esc[1], "%2X", &num))) | ||
61 | { | ||
62 | esc[0] = (unsigned char) num; | ||
63 | memmove (&esc[1], &esc[3], strlen (&esc[3])); | ||
64 | } | ||
65 | val = esc + 1; | ||
66 | } | ||
67 | } | ||
diff --git a/src/daemon/internal.h b/src/daemon/internal.h index 125755d2..3f3f91b0 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h | |||
@@ -65,6 +65,11 @@ | |||
65 | */ | 65 | */ |
66 | void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); | 66 | void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); |
67 | 67 | ||
68 | /** | ||
69 | * Process escape sequences ('+'=space, %HH). | ||
70 | * Updates val in place. | ||
71 | */ | ||
72 | void MHD_http_unescape (char *val); | ||
68 | 73 | ||
69 | /** | 74 | /** |
70 | * Header or cookie in HTTP request or response. | 75 | * Header or cookie in HTTP request or response. |
@@ -208,7 +213,7 @@ struct MHD_Connection | |||
208 | * store it. (MHD does not know or care what it | 213 | * store it. (MHD does not know or care what it |
209 | * is). | 214 | * is). |
210 | */ | 215 | */ |
211 | void * client_context; | 216 | void *client_context; |
212 | 217 | ||
213 | /** | 218 | /** |
214 | * Request method. Should be GET/POST/etc. Allocated | 219 | * Request method. Should be GET/POST/etc. Allocated |
@@ -350,11 +355,6 @@ struct MHD_Connection | |||
350 | int headersSent; | 355 | int headersSent; |
351 | 356 | ||
352 | /** | 357 | /** |
353 | * Are we processing the POST data? | ||
354 | */ | ||
355 | int post_processed; | ||
356 | |||
357 | /** | ||
358 | * HTTP response code. Only valid if response object | 358 | * HTTP response code. Only valid if response object |
359 | * is already set. | 359 | * is already set. |
360 | */ | 360 | */ |
@@ -391,7 +391,7 @@ struct MHD_Daemon | |||
391 | 391 | ||
392 | MHD_RequestCompletedCallback notify_completed; | 392 | MHD_RequestCompletedCallback notify_completed; |
393 | 393 | ||
394 | void * notify_completed_cls; | 394 | void *notify_completed_cls; |
395 | 395 | ||
396 | /** | 396 | /** |
397 | * PID of the select thread (if we have internal select) | 397 | * PID of the select thread (if we have internal select) |
diff --git a/src/daemon/minimal_example.c b/src/daemon/minimal_example.c index 80442072..62ee5ae5 100644 --- a/src/daemon/minimal_example.c +++ b/src/daemon/minimal_example.c | |||
@@ -41,8 +41,7 @@ ahc_echo (void *cls, | |||
41 | const char *url, | 41 | const char *url, |
42 | const char *method, | 42 | const char *method, |
43 | const char *upload_data, | 43 | const char *upload_data, |
44 | const char *version, unsigned int *upload_data_size, | 44 | const char *version, unsigned int *upload_data_size, void **unused) |
45 | void ** unused) | ||
46 | { | 45 | { |
47 | const char *me = cls; | 46 | const char *me = cls; |
48 | struct MHD_Response *response; | 47 | struct MHD_Response *response; |
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 3a46c085..c77ea6b9 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -84,7 +84,7 @@ extern "C" | |||
84 | /** | 84 | /** |
85 | * Current version of the library. | 85 | * Current version of the library. |
86 | */ | 86 | */ |
87 | #define MHD_VERSION 0x00000004 | 87 | #define MHD_VERSION 0x00000005 |
88 | 88 | ||
89 | /** | 89 | /** |
90 | * MHD-internal return codes. | 90 | * MHD-internal return codes. |
@@ -428,6 +428,11 @@ struct MHD_Connection; | |||
428 | struct MHD_Response; | 428 | struct MHD_Response; |
429 | 429 | ||
430 | /** | 430 | /** |
431 | * Handle for POST processing. | ||
432 | */ | ||
433 | struct MHD_PostProcessor; | ||
434 | |||
435 | /** | ||
431 | * Allow or deny a client to connect. | 436 | * Allow or deny a client to connect. |
432 | * | 437 | * |
433 | * | 438 | * |
@@ -555,6 +560,29 @@ typedef int | |||
555 | typedef void (*MHD_ContentReaderFreeCallback) (void *cls); | 560 | typedef void (*MHD_ContentReaderFreeCallback) (void *cls); |
556 | 561 | ||
557 | /** | 562 | /** |
563 | * Iterator over key-value pairs where the value | ||
564 | * maybe made available in increments and/or may | ||
565 | * not be zero-terminated. | ||
566 | * | ||
567 | * @param cls user-specified closure | ||
568 | * @param kind type of the value | ||
569 | * @param 0-terminated key for the value | ||
570 | * @param value pointer to size bytes of data at the | ||
571 | * specified offset | ||
572 | * @param off offset of value in the overall data | ||
573 | * @param size number of bytes in value available | ||
574 | * @return MHD_YES to continue iterating, | ||
575 | * MHD_NO to abort the iteration | ||
576 | */ | ||
577 | typedef int | ||
578 | (*MHD_IncrementalKeyValueIterator) (void *cls, | ||
579 | enum MHD_ValueKind kind, | ||
580 | const char *key, | ||
581 | const char *value, | ||
582 | size_t off, | ||
583 | size_t size); | ||
584 | |||
585 | /** | ||
558 | * Start a webserver on the given port. | 586 | * Start a webserver on the given port. |
559 | * @param flags combination of MHD_FLAG values | 587 | * @param flags combination of MHD_FLAG values |
560 | * @param port port to bind to | 588 | * @param port port to bind to |
@@ -776,6 +804,57 @@ const char *MHD_get_response_header (struct MHD_Response *response, | |||
776 | const char *key); | 804 | const char *key); |
777 | 805 | ||
778 | 806 | ||
807 | /** | ||
808 | * Create a PostProcessor. | ||
809 | * | ||
810 | * A PostProcessor can be used to (incrementally) | ||
811 | * parse the data portion of a POST request. | ||
812 | * | ||
813 | * @param connection the connection on which the POST is | ||
814 | * happening (used to determine the POST format) | ||
815 | * @param buffer_size maximum number of bytes to use for | ||
816 | * internal buffering (used only for the parsing, | ||
817 | * specifically the parsing of the keys). A | ||
818 | * tiny value (256-1024) should be sufficient. | ||
819 | * Do NOT use 0. | ||
820 | * @param ikvi iterator to be called with the parsed data, | ||
821 | * Must NOT be NULL. | ||
822 | * @param cls first argument to ikvi | ||
823 | * @return NULL on error (out of memory, unsupported encoding), | ||
824 | otherwise a PP handle | ||
825 | */ | ||
826 | struct MHD_PostProcessor * | ||
827 | MHD_create_post_processor(struct MHD_Connection * connection, | ||
828 | unsigned int buffer_size, | ||
829 | MHD_IncrementalKeyValueIterator ikvi, | ||
830 | void * cls); | ||
831 | |||
832 | /** | ||
833 | * Parse and process POST data. | ||
834 | * Call this function when POST data is available | ||
835 | * (usually during an MHD_AccessHandlerCallback) | ||
836 | * with the upload_data and upload_data_size. | ||
837 | * Whenever possible, this will then cause calls | ||
838 | * to the MHD_IncrementalKeyValueIterator. | ||
839 | * | ||
840 | * @param pp the post processor | ||
841 | * @param post_data post_data_len bytes of POST data | ||
842 | * @param post_data_len length of post_data | ||
843 | * @return MHD_YES on success, MHD_NO on error | ||
844 | * (out-of-memory, iterator aborted, parse error) | ||
845 | */ | ||
846 | int | ||
847 | MHD_post_process(struct MHD_PostProcessor * pp, | ||
848 | const char * post_data, | ||
849 | unsigned int post_data_len); | ||
850 | |||
851 | /** | ||
852 | * Release PostProcessor resources. | ||
853 | */ | ||
854 | void | ||
855 | MHD_destroy_post_processor(struct MHD_PostProcessor * pp); | ||
856 | |||
857 | |||
779 | #if 0 /* keep Emacsens' auto-indent happy */ | 858 | #if 0 /* keep Emacsens' auto-indent happy */ |
780 | { | 859 | { |
781 | #endif | 860 | #endif |