aboutsummaryrefslogtreecommitdiff
path: root/src/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon')
-rw-r--r--src/daemon/Makefile.am3
-rw-r--r--src/daemon/connection.c299
-rw-r--r--src/daemon/daemon.c115
-rw-r--r--src/daemon/daemontest.c2
-rw-r--r--src/daemon/daemontest_get.c2
-rw-r--r--src/daemon/daemontest_large_put.c2
-rw-r--r--src/daemon/daemontest_long_header.c2
-rw-r--r--src/daemon/daemontest_post.c46
-rw-r--r--src/daemon/daemontest_put.c11
-rw-r--r--src/daemon/fileserver_example.c3
-rw-r--r--src/daemon/internal.c23
-rw-r--r--src/daemon/internal.h14
-rw-r--r--src/daemon/minimal_example.c3
13 files changed, 216 insertions, 309 deletions
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
8libmicrohttpd_la_LDFLAGS = \ 8libmicrohttpd_la_LDFLAGS = \
9 -export-dynamic -version-info 1:0:0 9 -export-dynamic -version-info 2:0:0
10libmicrohttpd_la_SOURCES = \ 10libmicrohttpd_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 */
187static void 187static void
188connection_close_error(struct MHD_Connection * connection) 188connection_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 */
435static void
436MHD_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 */
458static int 433static 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;
762DIE: 737DIE:
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 */
797static int
798MHD_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 */
842static int
843MHD_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, &ltimeout)) 497 if (MHD_YES == MHD_get_timeout (daemon, &ltimeout))
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 */
71static int
72post_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
66static int 87static int
67ahc_echo (void *cls, 88ahc_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 */
49void
50MHD_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 */
66void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); 66void 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 */
72void 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;