aboutsummaryrefslogtreecommitdiff
path: root/src/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon')
-rw-r--r--src/daemon/Makefile.am7
-rw-r--r--src/daemon/connection.c380
-rw-r--r--src/daemon/daemon.c4
-rw-r--r--src/daemon/daemontest_put_chunked.c382
-rw-r--r--src/daemon/internal.h44
5 files changed, 686 insertions, 131 deletions
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 3ac9f312..4902dc52 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -48,6 +48,7 @@ check_PROGRAMS = \
48 daemontest_postform \ 48 daemontest_postform \
49 daemontest_post_loop \ 49 daemontest_post_loop \
50 daemontest_put \ 50 daemontest_put \
51 daemontest_put_chunked \
51 daemontest_large_put \ 52 daemontest_large_put \
52 daemontest_get11 \ 53 daemontest_get11 \
53 daemontest_post11 \ 54 daemontest_post11 \
@@ -94,6 +95,12 @@ daemontest_put_LDADD = \
94 $(top_builddir)/src/daemon/libmicrohttpd.la \ 95 $(top_builddir)/src/daemon/libmicrohttpd.la \
95 @LIBCURL@ 96 @LIBCURL@
96 97
98daemontest_put_chunked_SOURCES = \
99 daemontest_put_chunked.c
100daemontest_put_chunked_LDADD = \
101 $(top_builddir)/src/daemon/libmicrohttpd.la \
102 @LIBCURL@
103
97daemontest_get11_SOURCES = \ 104daemontest_get11_SOURCES = \
98 daemontest_get.c 105 daemontest_get.c
99daemontest_get11_LDADD = \ 106daemontest_get11_LDADD = \
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 39e00dd7..83540622 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -152,7 +152,7 @@ MHD_queue_response (struct MHD_Connection *connection,
152 if ((connection == NULL) || 152 if ((connection == NULL) ||
153 (response == NULL) || 153 (response == NULL) ||
154 (connection->response != NULL) || 154 (connection->response != NULL) ||
155 (connection->bodyReceived == MHD_NO) || (connection->headersReceived == MHD_NO)) 155 (connection->have_received_body == MHD_NO) || (connection->have_received_headers == MHD_NO))
156 return MHD_NO; 156 return MHD_NO;
157 MHD_increment_response_rc (response); 157 MHD_increment_response_rc (response);
158 connection->response = response; 158 connection->response = response;
@@ -162,7 +162,7 @@ MHD_queue_response (struct MHD_Connection *connection,
162 { 162 {
163 /* if this is a "HEAD" request, pretend that we 163 /* if this is a "HEAD" request, pretend that we
164 have already sent the full message body */ 164 have already sent the full message body */
165 connection->messagePos = response->total_size; 165 connection->response_write_position = response->total_size;
166 } 166 }
167 return MHD_YES; 167 return MHD_YES;
168} 168}
@@ -179,12 +179,12 @@ MHD_need_100_continue (struct MHD_Connection *connection)
179 return ((connection->version != NULL) && 179 return ((connection->version != NULL) &&
180 (0 == strcasecmp (connection->version, 180 (0 == strcasecmp (connection->version,
181 MHD_HTTP_VERSION_1_1)) && 181 MHD_HTTP_VERSION_1_1)) &&
182 (connection->headersReceived == MHD_YES) && 182 (connection->have_received_headers == MHD_YES) &&
183 (NULL != (expect = MHD_lookup_connection_value (connection, 183 (NULL != (expect = MHD_lookup_connection_value (connection,
184 MHD_HEADER_KIND, 184 MHD_HEADER_KIND,
185 MHD_HTTP_HEADER_EXPECT))) 185 MHD_HTTP_HEADER_EXPECT)))
186 && (0 == strcasecmp (expect, "100-continue")) 186 && (0 == strcasecmp (expect, "100-continue"))
187 && (connection->continuePos < strlen (HTTP_100_CONTINUE))); 187 && (connection->continue_message_write_offset < strlen (HTTP_100_CONTINUE)));
188} 188}
189 189
190/** 190/**
@@ -221,10 +221,10 @@ ready_response (struct MHD_Connection *connection)
221 221
222 response = connection->response; 222 response = connection->response;
223 ret = response->crc (response->crc_cls, 223 ret = response->crc (response->crc_cls,
224 connection->messagePos, 224 connection->response_write_position,
225 response->data, 225 response->data,
226 MIN (response->data_buffer_size, 226 MIN (response->data_buffer_size,
227 response->total_size - connection->messagePos)); 227 response->total_size - connection->response_write_position));
228 if (ret == -1) 228 if (ret == -1)
229 { 229 {
230 /* end of message, signal other side by closing! */ 230 /* end of message, signal other side by closing! */
@@ -233,11 +233,11 @@ ready_response (struct MHD_Connection *connection)
233 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n"); 233 MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
234#endif 234#endif
235#endif 235#endif
236 response->total_size = connection->messagePos; 236 response->total_size = connection->response_write_position;
237 connection_close_error (connection); 237 connection_close_error (connection);
238 return MHD_NO; 238 return MHD_NO;
239 } 239 }
240 response->data_start = connection->messagePos; 240 response->data_start = connection->response_write_position;
241 response->data_size = ret; 241 response->data_size = ret;
242 if (ret == 0) 242 if (ret == 0)
243 { 243 {
@@ -278,8 +278,8 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
278 if (fd == -1) 278 if (fd == -1)
279 return MHD_YES; 279 return MHD_YES;
280 if ((connection->read_close == MHD_NO) && 280 if ((connection->read_close == MHD_NO) &&
281 ((connection->headersReceived == MHD_NO) || 281 ((connection->have_received_headers == MHD_NO) ||
282 (connection->readLoc < connection->read_buffer_size))) 282 (connection->read_buffer_offset < connection->read_buffer_size)))
283 { 283 {
284 FD_SET (fd, read_fd_set); 284 FD_SET (fd, read_fd_set);
285 if (fd > *max_fd) 285 if (fd > *max_fd)
@@ -288,8 +288,8 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
288 else 288 else
289 { 289 {
290 if ((connection->read_close == MHD_NO) && 290 if ((connection->read_close == MHD_NO) &&
291 ((connection->headersReceived == MHD_YES) && 291 ((connection->have_received_headers == MHD_YES) &&
292 (connection->readLoc == connection->read_buffer_size))) 292 (connection->read_buffer_offset == connection->read_buffer_size)))
293 { 293 {
294 /* try growing the read buffer, just in case */ 294 /* try growing the read buffer, just in case */
295 buf = MHD_pool_reallocate (connection->pool, 295 buf = MHD_pool_reallocate (connection->pool,
@@ -342,8 +342,8 @@ MHD_excessive_data_handler (struct MHD_Connection *connection,
342 342
343 /* die, header far too long to be reasonable */ 343 /* die, header far too long to be reasonable */
344 connection->read_close = MHD_YES; 344 connection->read_close = MHD_YES;
345 connection->headersReceived = MHD_YES; 345 connection->have_received_headers = MHD_YES;
346 connection->bodyReceived = MHD_YES; 346 connection->have_received_body = MHD_YES;
347#if HAVE_MESSAGES 347#if HAVE_MESSAGES
348 MHD_DLOG (connection->daemon, 348 MHD_DLOG (connection->daemon,
349 "Received excessively long header, closing connection.\n"); 349 "Received excessively long header, closing connection.\n");
@@ -368,17 +368,17 @@ MHD_get_next_header_line (struct MHD_Connection *connection)
368 char *rbuf; 368 char *rbuf;
369 size_t pos; 369 size_t pos;
370 370
371 if (connection->readLoc == 0) 371 if (connection->read_buffer_offset == 0)
372 return NULL; 372 return NULL;
373 pos = 0; 373 pos = 0;
374 rbuf = connection->read_buffer; 374 rbuf = connection->read_buffer;
375 while ((pos < connection->readLoc - 1) && 375 while ((pos < connection->read_buffer_offset - 1) &&
376 (rbuf[pos] != '\r') && (rbuf[pos] != '\n')) 376 (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
377 pos++; 377 pos++;
378 if (pos == connection->readLoc - 1) 378 if (pos == connection->read_buffer_offset - 1)
379 { 379 {
380 /* not found, consider growing... */ 380 /* not found, consider growing... */
381 if (connection->readLoc == connection->read_buffer_size) 381 if (connection->read_buffer_offset == connection->read_buffer_size)
382 { 382 {
383 rbuf = MHD_pool_reallocate (connection->pool, 383 rbuf = MHD_pool_reallocate (connection->pool,
384 connection->read_buffer, 384 connection->read_buffer,
@@ -407,7 +407,7 @@ MHD_get_next_header_line (struct MHD_Connection *connection)
407 rbuf[pos++] = '\0'; 407 rbuf[pos++] = '\0';
408 connection->read_buffer += pos; 408 connection->read_buffer += pos;
409 connection->read_buffer_size -= pos; 409 connection->read_buffer_size -= pos;
410 connection->readLoc -= pos; 410 connection->read_buffer_offset -= pos;
411 return rbuf; 411 return rbuf;
412} 412}
413 413
@@ -586,14 +586,16 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line)
586 586
587 587
588/** 588/**
589 * This function is designed to parse the input buffer of a given connection. 589 * This function is designed to parse the input buffer of a given
590 * connection for HTTP headers -- and in the case of chunked encoding,
591 * also for HTTP "footers".
590 * 592 *
591 * Once the header is complete, it should have set the 593 * Once the header is complete, it should have set the
592 * headers_received, url and method values and set 594 * headers_received, url and method values and set
593 * headersReceived to MHD_YES. If no body is expected, it should 595 * have_received_headers to MHD_YES. If no body is expected, it
594 * also set "bodyReceived" to MHD_YES. Otherwise, it should 596 * should also set "have_received_body" to MHD_YES. Otherwise, it
595 * set "uploadSize" to the expected size of the body. If the 597 * should set "remaining_upload_size" to the expected size of the
596 * size of the body is unknown, it should be set to -1. 598 * body. If the size of the body is unknown, it should be set to -1.
597 */ 599 */
598static void 600static void
599MHD_parse_connection_headers (struct MHD_Connection *connection) 601MHD_parse_connection_headers (struct MHD_Connection *connection)
@@ -606,8 +608,9 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
606 unsigned long long cval; 608 unsigned long long cval;
607 struct MHD_Response *response; 609 struct MHD_Response *response;
608 610
609 if ( (connection->bodyReceived == MHD_YES) || 611 if ( ( (connection->have_received_body == MHD_YES) &&
610 (connection->headersReceived == MHD_YES) ) 612 (connection->have_chunked_upload == MHD_NO) ) ||
613 (connection->have_received_headers == MHD_YES) )
611 abort (); 614 abort ();
612 colon = NULL; /* make gcc happy */ 615 colon = NULL; /* make gcc happy */
613 last = NULL; 616 last = NULL;
@@ -656,7 +659,7 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
656 if (strlen (line) == 0) 659 if (strlen (line) == 0)
657 { 660 {
658 /* end of header */ 661 /* end of header */
659 connection->headersReceived = MHD_YES; 662 connection->have_received_headers = MHD_YES;
660 clen = MHD_lookup_connection_value (connection, 663 clen = MHD_lookup_connection_value (connection,
661 MHD_HEADER_KIND, 664 MHD_HEADER_KIND,
662 MHD_HTTP_HEADER_CONTENT_LENGTH); 665 MHD_HTTP_HEADER_CONTENT_LENGTH);
@@ -671,8 +674,8 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
671#endif 674#endif
672 goto DIE; 675 goto DIE;
673 } 676 }
674 connection->uploadSize = cval; 677 connection->remaining_upload_size = cval;
675 connection->bodyReceived = cval == 0 ? MHD_YES : MHD_NO; 678 connection->have_received_body = cval == 0 ? MHD_YES : MHD_NO;
676 } 679 }
677 else 680 else
678 { 681 {
@@ -681,14 +684,29 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
681 MHD_HTTP_HEADER_TRANSFER_ENCODING)) 684 MHD_HTTP_HEADER_TRANSFER_ENCODING))
682 { 685 {
683 /* this request does not have a body */ 686 /* this request does not have a body */
684 connection->uploadSize = 0; 687 connection->remaining_upload_size = 0;
685 connection->bodyReceived = MHD_YES; 688 connection->have_received_body = MHD_YES;
686 } 689 }
687 else 690 else
688 { 691 {
689 connection->uploadSize = -1; /* unknown size */ 692 if (connection->have_chunked_upload == MHD_NO)
690 connection->bodyReceived = MHD_NO; 693 {
691 } 694 connection->remaining_upload_size = -1; /* unknown size */
695 if (0 == strcasecmp(MHD_lookup_connection_value(connection,
696 MHD_HEADER_KIND,
697 MHD_HTTP_HEADER_TRANSFER_ENCODING),
698 "chunked"))
699 connection->have_chunked_upload = MHD_YES;
700 }
701 else
702 {
703 /* we were actually processing the footers at the
704 END of a chunked encoding; give connection
705 handler an extra chance... */
706 connection->have_chunked_upload = MHD_NO; /* no more! */
707 MHD_call_connection_handler(connection);
708 }
709 }
692 } 710 }
693 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) 711 if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
694 && (NULL != connection->version) 712 && (NULL != connection->version)
@@ -698,7 +716,7 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
698 MHD_HTTP_HEADER_HOST))) 716 MHD_HTTP_HEADER_HOST)))
699 { 717 {
700 /* die, http 1.1 request without host and we are pedantic */ 718 /* die, http 1.1 request without host and we are pedantic */
701 connection->bodyReceived = MHD_YES; 719 connection->have_received_body = MHD_YES;
702 connection->read_close = MHD_YES; 720 connection->read_close = MHD_YES;
703#if HAVE_MESSAGES 721#if HAVE_MESSAGES
704 MHD_DLOG (connection->daemon, 722 MHD_DLOG (connection->daemon,
@@ -780,54 +798,177 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
780{ 798{
781 struct MHD_Access_Handler *ah; 799 struct MHD_Access_Handler *ah;
782 unsigned int processed; 800 unsigned int processed;
801 unsigned int available;
802 unsigned int used;
803 int instant_retry;
804 unsigned int i;
783 805
784 if (connection->response != NULL) 806 if (connection->response != NULL)
785 return; /* already queued a response */ 807 return; /* already queued a response */
786 if (connection->headersReceived == MHD_NO) 808 if (connection->have_received_headers == MHD_NO)
787 abort (); /* bad timing... */ 809 abort (); /* bad timing... */
788 ah = MHD_find_access_handler (connection); 810 do
789 processed = connection->readLoc;
790 if (MHD_NO == ah->dh (ah->dh_cls,
791 connection,
792 connection->url,
793 connection->method,
794 connection->version,
795 connection->read_buffer, &processed,
796 &connection->client_context))
797 { 811 {
798 /* serious internal error, close connection */ 812 instant_retry = MHD_NO;
813 available = connection->read_buffer_offset;
814 if (connection->have_chunked_upload == MHD_YES)
815 {
816 if ( (connection->current_chunk_offset == connection->current_chunk_size) &&
817 (connection->current_chunk_offset != 0) &&
818 (available >= 2) )
819 {
820 /* skip new line at the *end* of a chunk */
821 i = 0;
822 if ( (connection->read_buffer[i] == '\r') ||
823 (connection->read_buffer[i] == '\n') )
824 i++; /* skip 1st part of line feed */
825 if ( (connection->read_buffer[i] == '\r') ||
826 (connection->read_buffer[i] == '\n') )
827 i++; /* skip 2nd part of line feed */
828 if (i == 0)
829 {
830 /* malformed encoding */
799#if HAVE_MESSAGES 831#if HAVE_MESSAGES
800 MHD_DLOG (connection->daemon, 832 MHD_DLOG (connection->daemon,
801 "Internal application error, closing connection.\n"); 833 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
802#endif 834#endif
803 connection_close_error (connection); 835 connection_close_error (connection);
804 return; 836 return;
805 } 837 }
806 /* dh left "processed" bytes in buffer for next time... */ 838 connection->read_buffer_offset -= i;
807 memmove (connection->read_buffer, 839 available -= i;
808 &connection->read_buffer[connection->readLoc - processed], 840 memmove(connection->read_buffer,
809 processed); 841 &connection->read_buffer[i],
810 if (connection->uploadSize != -1) 842 available);
811 connection->uploadSize -= (connection->readLoc - processed); 843 connection->current_chunk_offset = 0;
812 connection->readLoc = processed; 844 connection->current_chunk_size = 0;
813 if ((connection->uploadSize == 0) || 845 }
814 ((connection->readLoc == 0) && 846 if (connection->current_chunk_offset < connection->current_chunk_size)
815 (connection->uploadSize == -1) && (connection->socket_fd == -1))) 847 {
816 { 848 /* we are in the middle of a chunk, give
817 connection->bodyReceived = MHD_YES; 849 as much as possible to the client (without
818 if (connection->read_buffer != NULL) 850 crossing chunk boundaries) */
819 MHD_pool_reallocate (connection->pool, 851 processed = connection->current_chunk_size - connection->current_chunk_offset;
820 connection->read_buffer, 852 if (processed > available)
821 (connection->read_buffer == 853 processed = available;
822 NULL) ? 0 : connection->read_buffer_size + 1, 854 available -= processed;
823 0); 855 if (available > 0)
824 connection->readLoc = 0; 856 instant_retry = MHD_YES;
825 connection->read_buffer_size = 0; 857 }
826 connection->read_buffer = NULL; 858 else
827 } 859 {
860 /* we need to read chunk boundaries */
861 i = 0;
862 while (i < available)
863 {
864 if ( (connection->read_buffer[i] == '\r') ||
865 (connection->read_buffer[i] == '\n') )
866 break;
867 i++;
868 if (i >= 6)
869 break;
870 }
871 if (i >= available)
872 return; /* need more data... */
873 /* The following if-statement is a bit crazy -- we
874 use the second clause only for the side-effect,
875 0-terminating the buffer for the following sscanf
876 attempts; yes, there should be only a single
877 "="-sign (assignment!) in the read_buffer[i]-line. */
878 if ( (i >= 6) ||
879 ((connection->read_buffer[i] = '\0')) ||
880 ( (1 != sscanf(connection->read_buffer,
881 "%X",
882 &connection->current_chunk_size)) &&
883 (1 != sscanf(connection->read_buffer,
884 "%x",
885 &connection->current_chunk_size)) ) )
886 {
887 /* malformed encoding */
888#if HAVE_MESSAGES
889 MHD_DLOG (connection->daemon,
890 "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
891#endif
892 connection_close_error (connection);
893 return;
894 }
895 i++;
896 if ( (connection->read_buffer[i] == '\r') ||
897 (connection->read_buffer[i] == '\n') )
898 i++; /* skip 2nd part of line feed */
899 memmove(connection->read_buffer,
900 &connection->read_buffer[i],
901 available - i);
902 connection->read_buffer_offset -= i;
903 connection->current_chunk_offset = 0;
904 instant_retry = MHD_YES;
905 if (connection->current_chunk_size == 0)
906 {
907 /* we're back to reading HEADERS (footers!) */
908 connection->have_received_body = MHD_YES;
909 connection->remaining_upload_size = 0;
910 connection->have_received_headers = MHD_NO;
911 MHD_parse_connection_headers(connection);
912 return;
913 }
914 continue;
915 }
916 }
917 else
918 {
919 /* no chunked encoding, give all to the client */
920 processed = available;
921 available = 0;
922 }
923 used = processed;
924 ah = MHD_find_access_handler (connection);
925 if (MHD_NO == ah->dh (ah->dh_cls,
926 connection,
927 connection->url,
928 connection->method,
929 connection->version,
930 connection->read_buffer, &processed,
931 &connection->client_context))
932 {
933 /* serious internal error, close connection */
934#if HAVE_MESSAGES
935 MHD_DLOG (connection->daemon,
936 "Internal application error, closing connection.\n");
937#endif
938 connection_close_error (connection);
939 return;
940 }
941 if (processed != 0)
942 instant_retry = MHD_NO; /* client did not process everything */
943 used -= processed;
944 if (connection->have_chunked_upload == MHD_YES)
945 connection->current_chunk_offset += used;
946 /* dh left "processed" bytes in buffer for next time... */
947 if (used > 0)
948 memmove (connection->read_buffer,
949 &connection->read_buffer[used],
950 processed + available);
951 if (connection->remaining_upload_size != -1)
952 connection->remaining_upload_size -= used;
953 connection->read_buffer_offset = processed + available;
954 if ((connection->remaining_upload_size == 0) ||
955 ((connection->read_buffer_offset == 0) &&
956 (connection->remaining_upload_size == -1) && (connection->socket_fd == -1)))
957 {
958 connection->have_received_body = MHD_YES;
959 if (connection->read_buffer != NULL)
960 MHD_pool_reallocate (connection->pool,
961 connection->read_buffer,
962 (connection->read_buffer ==
963 NULL) ? 0 : connection->read_buffer_size + 1,
964 0);
965 connection->read_buffer_offset = 0;
966 connection->read_buffer_size = 0;
967 connection->read_buffer = NULL;
968 }
969 } while (instant_retry == MHD_YES);
828} 970}
829 971
830
831/** 972/**
832 * This function handles a particular connection when it has been 973 * This function handles a particular connection when it has been
833 * determined that there is data to be read off a socket. All implementations 974 * determined that there is data to be read off a socket. All implementations
@@ -850,8 +991,8 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
850 connection_close_error (connection); 991 connection_close_error (connection);
851 return MHD_NO; 992 return MHD_NO;
852 } 993 }
853 if ((connection->readLoc >= connection->read_buffer_size) && 994 if ((connection->read_buffer_offset >= connection->read_buffer_size) &&
854 (connection->headersReceived == MHD_NO)) 995 (connection->have_received_headers == MHD_NO))
855 { 996 {
856 /* need to grow read buffer */ 997 /* need to grow read buffer */
857 tmp = MHD_pool_reallocate (connection->pool, 998 tmp = MHD_pool_reallocate (connection->pool,
@@ -873,7 +1014,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
873 connection->read_buffer_size = 1014 connection->read_buffer_size =
874 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; 1015 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
875 } 1016 }
876 if (connection->readLoc >= connection->read_buffer_size) 1017 if (connection->read_buffer_offset >= connection->read_buffer_size)
877 { 1018 {
878#if HAVE_MESSAGES 1019#if HAVE_MESSAGES
879 MHD_DLOG (connection->daemon, "Unexpected call to %s.\n", __FUNCTION__); 1020 MHD_DLOG (connection->daemon, "Unexpected call to %s.\n", __FUNCTION__);
@@ -881,8 +1022,8 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
881 return MHD_NO; 1022 return MHD_NO;
882 } 1023 }
883 bytes_read = RECV (connection->socket_fd, 1024 bytes_read = RECV (connection->socket_fd,
884 &connection->read_buffer[connection->readLoc], 1025 &connection->read_buffer[connection->read_buffer_offset],
885 connection->read_buffer_size - connection->readLoc, 1026 connection->read_buffer_size - connection->read_buffer_offset,
886 MSG_NOSIGNAL); 1027 MSG_NOSIGNAL);
887 if (bytes_read < 0) 1028 if (bytes_read < 0)
888 { 1029 {
@@ -899,7 +1040,7 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
899 { 1040 {
900 /* other side closed connection */ 1041 /* other side closed connection */
901 connection->read_close = MHD_YES; 1042 connection->read_close = MHD_YES;
902 if ((connection->headersReceived == MHD_YES) && (connection->readLoc > 0)) 1043 if ((connection->have_received_headers == MHD_YES) && (connection->read_buffer_offset > 0))
903 MHD_call_connection_handler (connection); 1044 MHD_call_connection_handler (connection);
904#if DEBUG_CLOSE 1045#if DEBUG_CLOSE
905#if HAVE_MESSAGES 1046#if HAVE_MESSAGES
@@ -908,18 +1049,18 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
908#endif 1049#endif
909#endif 1050#endif
910 shutdown (connection->socket_fd, SHUT_RD); 1051 shutdown (connection->socket_fd, SHUT_RD);
911 if ( (connection->headersReceived == MHD_NO) || 1052 if ( (connection->have_received_headers == MHD_NO) ||
912 (connection->bodyReceived == MHD_NO) ) { 1053 (connection->have_received_body == MHD_NO) ) {
913 /* no request => no response! */ 1054 /* no request => no response! */
914 CLOSE (connection->socket_fd); 1055 CLOSE (connection->socket_fd);
915 connection->socket_fd = -1; 1056 connection->socket_fd = -1;
916 } 1057 }
917 return MHD_YES; 1058 return MHD_YES;
918 } 1059 }
919 connection->readLoc += bytes_read; 1060 connection->read_buffer_offset += bytes_read;
920 if (connection->headersReceived == MHD_NO) 1061 if (connection->have_received_headers == MHD_NO)
921 MHD_parse_connection_headers (connection); 1062 MHD_parse_connection_headers (connection);
922 if ((connection->headersReceived == MHD_YES) && (connection->method != NULL)) 1063 if ((connection->have_received_headers == MHD_YES) && (connection->method != NULL))
923 MHD_call_connection_handler (connection); 1064 MHD_call_connection_handler (connection);
924 return MHD_YES; 1065 return MHD_YES;
925} 1066}
@@ -1035,8 +1176,8 @@ MHD_build_header_response (struct MHD_Connection *connection)
1035 if (off != size) 1176 if (off != size)
1036 abort (); 1177 abort ();
1037 connection->write_buffer = data; 1178 connection->write_buffer = data;
1038 connection->writeLoc = size; 1179 connection->write_buffer_append_offset = size;
1039 connection->writePos = 0; 1180 connection->write_buffer_send_offset = 0;
1040 connection->write_buffer_size = size + 1; 1181 connection->write_buffer_size = size + 1;
1041 return MHD_YES; 1182 return MHD_YES;
1042} 1183}
@@ -1057,8 +1198,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1057 if (MHD_need_100_continue (connection)) 1198 if (MHD_need_100_continue (connection))
1058 { 1199 {
1059 ret = SEND (connection->socket_fd, 1200 ret = SEND (connection->socket_fd,
1060 &HTTP_100_CONTINUE[connection->continuePos], 1201 &HTTP_100_CONTINUE[connection->continue_message_write_offset],
1061 strlen (HTTP_100_CONTINUE) - connection->continuePos, 1202 strlen (HTTP_100_CONTINUE) - connection->continue_message_write_offset,
1062 MSG_NOSIGNAL); 1203 MSG_NOSIGNAL);
1063 if (ret < 0) 1204 if (ret < 0)
1064 { 1205 {
@@ -1074,9 +1215,9 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1074#if DEBUG_SEND_DATA 1215#if DEBUG_SEND_DATA
1075 fprintf (stderr, 1216 fprintf (stderr,
1076 "Sent 100 continue response: `%.*s'\n", 1217 "Sent 100 continue response: `%.*s'\n",
1077 ret, &HTTP_100_CONTINUE[connection->continuePos]); 1218 ret, &HTTP_100_CONTINUE[connection->continue_message_write_offset]);
1078#endif 1219#endif
1079 connection->continuePos += ret; 1220 connection->continue_message_write_offset += ret;
1080 return MHD_YES; 1221 return MHD_YES;
1081 } 1222 }
1082 response = connection->response; 1223 response = connection->response;
@@ -1087,7 +1228,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1087#endif 1228#endif
1088 return MHD_NO; 1229 return MHD_NO;
1089 } 1230 }
1090 if (MHD_NO == connection->headersSent) 1231 if (MHD_NO == connection->have_sent_headers)
1091 { 1232 {
1092 if ((connection->write_buffer == NULL) && 1233 if ((connection->write_buffer == NULL) &&
1093 (MHD_NO == MHD_build_header_response (connection))) 1234 (MHD_NO == MHD_build_header_response (connection)))
@@ -1101,8 +1242,8 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1101 return MHD_NO; 1242 return MHD_NO;
1102 } 1243 }
1103 ret = SEND (connection->socket_fd, 1244 ret = SEND (connection->socket_fd,
1104 &connection->write_buffer[connection->writePos], 1245 &connection->write_buffer[connection->write_buffer_send_offset],
1105 connection->writeLoc - connection->writePos, 1246 connection->write_buffer_append_offset - connection->write_buffer_send_offset,
1106 MSG_NOSIGNAL); 1247 MSG_NOSIGNAL);
1107 if (ret < 0) 1248 if (ret < 0)
1108 { 1249 {
@@ -1118,14 +1259,14 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1118#if DEBUG_SEND_DATA 1259#if DEBUG_SEND_DATA
1119 fprintf (stderr, 1260 fprintf (stderr,
1120 "Sent HEADER response: `%.*s'\n", 1261 "Sent HEADER response: `%.*s'\n",
1121 ret, &connection->write_buffer[connection->writePos]); 1262 ret, &connection->write_buffer[connection->write_buffer_send_offset]);
1122#endif 1263#endif
1123 connection->writePos += ret; 1264 connection->write_buffer_send_offset += ret;
1124 if (connection->writeLoc == connection->writePos) 1265 if (connection->write_buffer_append_offset == connection->write_buffer_send_offset)
1125 { 1266 {
1126 connection->writeLoc = 0; 1267 connection->write_buffer_append_offset = 0;
1127 connection->writePos = 0; 1268 connection->write_buffer_send_offset = 0;
1128 connection->headersSent = MHD_YES; 1269 connection->have_sent_headers = MHD_YES;
1129 MHD_pool_reallocate (connection->pool, 1270 MHD_pool_reallocate (connection->pool,
1130 connection->write_buffer, 1271 connection->write_buffer,
1131 connection->write_buffer_size, 0); 1272 connection->write_buffer_size, 0);
@@ -1134,24 +1275,24 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1134 } 1275 }
1135 return MHD_YES; 1276 return MHD_YES;
1136 } 1277 }
1137 if (response->total_size < connection->messagePos) 1278 if (response->total_size < connection->response_write_position)
1138 abort (); /* internal error */ 1279 abort (); /* internal error */
1139 if (response->crc != NULL) 1280 if (response->crc != NULL)
1140 pthread_mutex_lock (&response->mutex); 1281 pthread_mutex_lock (&response->mutex);
1141 1282
1142 /* prepare send buffer */ 1283 /* prepare send buffer */
1143 if ((response->crc != NULL) && 1284 if ((response->crc != NULL) &&
1144 ((response->data_start > connection->messagePos) || 1285 ((response->data_start > connection->response_write_position) ||
1145 (response->data_start + response->data_size <= 1286 (response->data_start + response->data_size <=
1146 connection->messagePos)) && (MHD_YES != ready_response (connection))) 1287 connection->response_write_position)) && (MHD_YES != ready_response (connection)))
1147 { 1288 {
1148 pthread_mutex_unlock (&response->mutex); 1289 pthread_mutex_unlock (&response->mutex);
1149 return MHD_YES; 1290 return MHD_YES;
1150 } 1291 }
1151 /* transmit */ 1292 /* transmit */
1152 ret = SEND (connection->socket_fd, 1293 ret = SEND (connection->socket_fd,
1153 &response->data[connection->messagePos - response->data_start], 1294 &response->data[connection->response_write_position - response->data_start],
1154 response->data_size - (connection->messagePos - 1295 response->data_size - (connection->response_write_position -
1155 response->data_start), 1296 response->data_start),
1156 MSG_NOSIGNAL); 1297 MSG_NOSIGNAL);
1157 if (response->crc != NULL) 1298 if (response->crc != NULL)
@@ -1171,15 +1312,15 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1171 fprintf (stderr, 1312 fprintf (stderr,
1172 "Sent DATA response: `%.*s'\n", 1313 "Sent DATA response: `%.*s'\n",
1173 ret, 1314 ret,
1174 &response->data[connection->messagePos - response->data_start]); 1315 &response->data[connection->response_write_position - response->data_start]);
1175#endif 1316#endif
1176 connection->messagePos += ret; 1317 connection->response_write_position += ret;
1177 if (connection->messagePos > response->total_size) 1318 if (connection->response_write_position > response->total_size)
1178 abort (); /* internal error */ 1319 abort (); /* internal error */
1179 if (connection->messagePos == response->total_size) 1320 if (connection->response_write_position == response->total_size)
1180 { 1321 {
1181 if ((connection->bodyReceived == MHD_NO) || 1322 if ((connection->have_received_body == MHD_NO) ||
1182 (connection->headersReceived == MHD_NO)) 1323 (connection->have_received_headers == MHD_NO))
1183 abort (); /* internal error */ 1324 abort (); /* internal error */
1184 MHD_destroy_response (response); 1325 MHD_destroy_response (response);
1185 if (connection->daemon->notify_completed != NULL) 1326 if (connection->daemon->notify_completed != NULL)
@@ -1192,14 +1333,15 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1192 MHD_HEADER_KIND, 1333 MHD_HEADER_KIND,
1193 MHD_HTTP_HEADER_CONNECTION); 1334 MHD_HTTP_HEADER_CONNECTION);
1194 connection->client_context = NULL; 1335 connection->client_context = NULL;
1195 connection->continuePos = 0; 1336 connection->continue_message_write_offset = 0;
1196 connection->responseCode = 0; 1337 connection->responseCode = 0;
1197 connection->response = NULL; 1338 connection->response = NULL;
1198 connection->headers_received = NULL; 1339 connection->headers_received = NULL;
1199 connection->headersReceived = MHD_NO; 1340 connection->have_received_headers = MHD_NO;
1200 connection->headersSent = MHD_NO; 1341 connection->have_sent_headers = MHD_NO;
1201 connection->bodyReceived = MHD_NO; 1342 connection->have_received_body = MHD_NO;
1202 connection->messagePos = 0; 1343 connection->response_write_position = 0;
1344 connection->have_chunked_upload = MHD_NO;
1203 connection->method = NULL; 1345 connection->method = NULL;
1204 connection->url = NULL; 1346 connection->url = NULL;
1205 if ((end != NULL) && (0 == strcasecmp (end, "close"))) 1347 if ((end != NULL) && (0 == strcasecmp (end, "close")))
@@ -1230,10 +1372,10 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
1230 connection->read_buffer = NULL; 1372 connection->read_buffer = NULL;
1231 connection->write_buffer = NULL; 1373 connection->write_buffer = NULL;
1232 connection->read_buffer_size = 0; 1374 connection->read_buffer_size = 0;
1233 connection->readLoc = 0; 1375 connection->read_buffer_offset = 0;
1234 connection->write_buffer_size = 0; 1376 connection->write_buffer_size = 0;
1235 connection->writePos = 0; 1377 connection->write_buffer_send_offset = 0;
1236 connection->writeLoc = 0; 1378 connection->write_buffer_append_offset = 0;
1237 MHD_pool_destroy (connection->pool); 1379 MHD_pool_destroy (connection->pool);
1238 connection->pool = NULL; 1380 connection->pool = NULL;
1239 } 1381 }
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index b7c66c8d..09a37255 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -227,7 +227,7 @@ MHD_handle_connection (void *data)
227 (FD_ISSET (con->socket_fd, &ws)) && 227 (FD_ISSET (con->socket_fd, &ws)) &&
228 (MHD_YES != MHD_connection_handle_write (con)))) 228 (MHD_YES != MHD_connection_handle_write (con))))
229 break; 229 break;
230 if ((con->headersReceived == MHD_YES) && (con->response == NULL)) 230 if ((con->have_received_headers == MHD_YES) && (con->response == NULL))
231 MHD_call_connection_handler (con); 231 MHD_call_connection_handler (con);
232 if ((con->socket_fd != -1) && 232 if ((con->socket_fd != -1) &&
233 ((FD_ISSET (con->socket_fd, &rs)) || 233 ((FD_ISSET (con->socket_fd, &rs)) ||
@@ -438,7 +438,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
438 } 438 }
439 439
440 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 440 if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
441 ((pos->headersReceived == MHD_YES) && (pos->response == NULL)) ) 441 ((pos->have_received_headers == MHD_YES) && (pos->response == NULL)) )
442 MHD_call_connection_handler (pos); 442 MHD_call_connection_handler (pos);
443 443
444 prev = pos; 444 prev = pos;
diff --git a/src/daemon/daemontest_put_chunked.c b/src/daemon/daemontest_put_chunked.c
new file mode 100644
index 00000000..2abe4bd2
--- /dev/null
+++ b/src/daemon/daemontest_put_chunked.c
@@ -0,0 +1,382 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Christian Grothoff
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_put_chunked.c
23 * @brief Testcase for libmicrohttpd PUT operations with chunked encoding
24 * for the upload data
25 * @author Christian Grothoff
26 */
27
28#include "config.h"
29#include <curl/curl.h>
30#include <microhttpd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <time.h>
34
35#ifndef WINDOWS
36#include <unistd.h>
37#endif
38
39struct CBC
40{
41 char *buf;
42 size_t pos;
43 size_t size;
44};
45
46static size_t
47putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
48{
49 unsigned int *pos = ptr;
50 unsigned int wrt;
51
52 wrt = size * nmemb;
53 if (wrt > 8 - (*pos))
54 wrt = 8 - (*pos);
55 if (wrt > 4)
56 wrt = 4; /* only send half at first => force multiple chunks! */
57 memcpy (stream, &("Hello123"[*pos]), wrt);
58 (*pos) += wrt;
59 return wrt;
60}
61
62static size_t
63copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
64{
65 struct CBC *cbc = ctx;
66
67 if (cbc->pos + size * nmemb > cbc->size)
68 return 0; /* overflow */
69 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
70 cbc->pos += size * nmemb;
71 return size * nmemb;
72}
73
74static int
75ahc_echo (void *cls,
76 struct MHD_Connection *connection,
77 const char *url,
78 const char *method,
79 const char *version,
80 const char *upload_data, unsigned int *upload_data_size,
81 void **unused)
82{
83 int *done = cls;
84 struct MHD_Response *response;
85 int ret;
86 int have;
87
88 if (0 != strcmp ("PUT", method))
89 return MHD_NO; /* unexpected method */
90 if ((*done) < 8)
91 {
92 have = *upload_data_size;
93 if (have + *done > 8)
94 {
95 printf ("Invalid upload data `%8s'!\n", upload_data);
96 return MHD_NO;
97 }
98 if (0 == memcmp(upload_data,
99 &"Hello123"[*done],
100 have))
101 {
102 *done += have;
103 *upload_data_size = 0;
104 }
105 else
106 {
107 printf ("Invalid upload data `%8s'!\n", upload_data);
108 return MHD_NO;
109 }
110 return MHD_YES;
111 }
112 response = MHD_create_response_from_data (strlen (url),
113 (void *) url, MHD_NO, MHD_YES);
114 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
115 MHD_destroy_response (response);
116 return ret;
117}
118
119
120static int
121testInternalPut ()
122{
123 struct MHD_Daemon *d;
124 CURL *c;
125 char buf[2048];
126 struct CBC cbc;
127 unsigned int pos = 0;
128 int done_flag = 0;
129 CURLcode errornum;
130
131 cbc.buf = buf;
132 cbc.size = 2048;
133 cbc.pos = 0;
134 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
135 11080,
136 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
137 if (d == NULL)
138 return 1;
139 c = curl_easy_init ();
140 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world");
141 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
142 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
143 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
144 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
145 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
146 /*
147 // by not giving the file size, we force chunking!
148 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
149 */
150 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
151 curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
152 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
153 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
154 // NOTE: use of CONNECTTIMEOUT without also
155 // setting NOSIGNAL results in really weird
156 // crashes on my system!
157 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
158 if (CURLE_OK != (errornum = curl_easy_perform (c)))
159 {
160 fprintf (stderr,
161 "curl_easy_perform failed: `%s'\n",
162 curl_easy_strerror (errornum));
163 curl_easy_cleanup (c);
164 MHD_stop_daemon (d);
165 return 2;
166 }
167 curl_easy_cleanup (c);
168 MHD_stop_daemon (d);
169 if (cbc.pos != strlen ("/hello_world"))
170 return 4;
171 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
172 return 8;
173 return 0;
174}
175
176static int
177testMultithreadedPut ()
178{
179 struct MHD_Daemon *d;
180 CURL *c;
181 char buf[2048];
182 struct CBC cbc;
183 unsigned int pos = 0;
184 int done_flag = 0;
185 CURLcode errornum;
186
187 cbc.buf = buf;
188 cbc.size = 2048;
189 cbc.pos = 0;
190 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
191 11081,
192 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
193 if (d == NULL)
194 return 16;
195 c = curl_easy_init ();
196 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
197 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
198 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
199 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
200 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
201 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
202 /*
203 // by not giving the file size, we force chunking!
204 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
205 */
206 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
207 curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
208 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
209 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
210 // NOTE: use of CONNECTTIMEOUT without also
211 // setting NOSIGNAL results in really weird
212 // crashes on my system!
213 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
214 if (CURLE_OK != (errornum = curl_easy_perform (c)))
215 {
216 fprintf (stderr,
217 "curl_easy_perform failed: `%s'\n",
218 curl_easy_strerror (errornum));
219 curl_easy_cleanup (c);
220 MHD_stop_daemon (d);
221 return 32;
222 }
223 curl_easy_cleanup (c);
224 MHD_stop_daemon (d);
225 if (cbc.pos != strlen ("/hello_world"))
226 return 64;
227 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
228 return 128;
229
230 return 0;
231}
232
233
234static int
235testExternalPut ()
236{
237 struct MHD_Daemon *d;
238 CURL *c;
239 char buf[2048];
240 struct CBC cbc;
241 CURLM *multi;
242 CURLMcode mret;
243 fd_set rs;
244 fd_set ws;
245 fd_set es;
246 int max;
247 int running;
248 struct CURLMsg *msg;
249 time_t start;
250 struct timeval tv;
251 unsigned int pos = 0;
252 int done_flag = 0;
253
254 multi = NULL;
255 cbc.buf = buf;
256 cbc.size = 2048;
257 cbc.pos = 0;
258 d = MHD_start_daemon (MHD_USE_DEBUG,
259 11082,
260 NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
261 if (d == NULL)
262 return 256;
263 c = curl_easy_init ();
264 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world");
265 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
266 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
267 curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
268 curl_easy_setopt (c, CURLOPT_READDATA, &pos);
269 curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
270 /*
271 // by not giving the file size, we force chunking!
272 curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
273 */
274 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
275 curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
276 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
277 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
278 // NOTE: use of CONNECTTIMEOUT without also
279 // setting NOSIGNAL results in really weird
280 // crashes on my system!
281 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
282
283
284 multi = curl_multi_init ();
285 if (multi == NULL)
286 {
287 curl_easy_cleanup (c);
288 MHD_stop_daemon (d);
289 return 512;
290 }
291 mret = curl_multi_add_handle (multi, c);
292 if (mret != CURLM_OK)
293 {
294 curl_multi_cleanup (multi);
295 curl_easy_cleanup (c);
296 MHD_stop_daemon (d);
297 return 1024;
298 }
299 start = time (NULL);
300 while ((time (NULL) - start < 5) && (multi != NULL))
301 {
302 max = 0;
303 FD_ZERO (&rs);
304 FD_ZERO (&ws);
305 FD_ZERO (&es);
306 curl_multi_perform (multi, &running);
307 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
308 if (mret != CURLM_OK)
309 {
310 curl_multi_remove_handle (multi, c);
311 curl_multi_cleanup (multi);
312 curl_easy_cleanup (c);
313 MHD_stop_daemon (d);
314 return 2048;
315 }
316 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
317 {
318 curl_multi_remove_handle (multi, c);
319 curl_multi_cleanup (multi);
320 curl_easy_cleanup (c);
321 MHD_stop_daemon (d);
322 return 4096;
323 }
324 tv.tv_sec = 0;
325 tv.tv_usec = 1000;
326 select (max + 1, &rs, &ws, &es, &tv);
327 curl_multi_perform (multi, &running);
328 if (running == 0)
329 {
330 msg = curl_multi_info_read (multi, &running);
331 if (msg == NULL)
332 break;
333 if (msg->msg == CURLMSG_DONE)
334 {
335 if (msg->data.result != CURLE_OK)
336 printf ("%s failed at %s:%d: `%s'\n",
337 "curl_multi_perform",
338 __FILE__,
339 __LINE__, curl_easy_strerror (msg->data.result));
340 curl_multi_remove_handle (multi, c);
341 curl_multi_cleanup (multi);
342 curl_easy_cleanup (c);
343 c = NULL;
344 multi = NULL;
345 }
346 }
347 MHD_run (d);
348 }
349 if (multi != NULL)
350 {
351 curl_multi_remove_handle (multi, c);
352 curl_easy_cleanup (c);
353 curl_multi_cleanup (multi);
354 }
355 MHD_stop_daemon (d);
356 if (cbc.pos != strlen ("/hello_world"))
357 return 8192;
358 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
359 return 16384;
360 return 0;
361}
362
363
364
365int
366main (int argc, char *const *argv)
367{
368 unsigned int errorCount = 0;
369
370 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
371 return 2;
372 errorCount += testInternalPut ();
373 if (0)
374 {
375 errorCount += testMultithreadedPut ();
376 errorCount += testExternalPut ();
377 }
378 if (errorCount != 0)
379 fprintf (stderr, "Error (code: %u)\n", errorCount);
380 curl_global_cleanup ();
381 return errorCount != 0; /* 0 == pass */
382}
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index 1596e8df..de4ae725 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -273,7 +273,7 @@ struct MHD_Connection
273 * Position where we currently append data in 273 * Position where we currently append data in
274 * read_buffer (last valid position). 274 * read_buffer (last valid position).
275 */ 275 */
276 size_t readLoc; 276 size_t read_buffer_offset;
277 277
278 /** 278 /**
279 * Size of write_buffer (in bytes). 279 * Size of write_buffer (in bytes).
@@ -283,32 +283,33 @@ struct MHD_Connection
283 /** 283 /**
284 * Offset where we are with sending from write_buffer. 284 * Offset where we are with sending from write_buffer.
285 */ 285 */
286 size_t writePos; 286 size_t write_buffer_send_offset;
287 287
288 /** 288 /**
289 * Last valid location in write_buffer. 289 * Last valid location in write_buffer (where do we
290 * append and up to where is it safe to send?)
290 */ 291 */
291 size_t writeLoc; 292 size_t write_buffer_append_offset;
292 293
293 /** 294 /**
294 * Current write position in the actual response 295 * Current write position in the actual response
295 * (excluding headers, content only; should be 0 296 * (excluding headers, content only; should be 0
296 * while sending headers). 297 * while sending headers).
297 */ 298 */
298 size_t messagePos; 299 size_t response_write_position;
299 300
300 /** 301 /**
301 * Remaining (!) number of bytes in the upload. 302 * Remaining (!) number of bytes in the upload.
302 * Set to -1 for unknown (connection will close 303 * Set to -1 for unknown (connection will close
303 * to indicate end of upload). 304 * to indicate end of upload).
304 */ 305 */
305 size_t uploadSize; 306 size_t remaining_upload_size;
306 307
307 /** 308 /**
308 * Position in the 100 CONTINUE message that 309 * Position in the 100 CONTINUE message that
309 * we need to send when receiving http 1.1 requests. 310 * we need to send when receiving http 1.1 requests.
310 */ 311 */
311 size_t continuePos; 312 size_t continue_message_write_offset;
312 313
313 /** 314 /**
314 * Length of the foreign address. 315 * Length of the foreign address.
@@ -343,18 +344,18 @@ struct MHD_Connection
343 * possible that the NEXT request is already 344 * possible that the NEXT request is already
344 * (partially) waiting in the read buffer. 345 * (partially) waiting in the read buffer.
345 */ 346 */
346 int headersReceived; 347 int have_received_headers;
347 348
348 /** 349 /**
349 * Have we finished receiving the data from a 350 * Have we finished receiving the data from a
350 * potential file-upload? 351 * potential file-upload?
351 */ 352 */
352 int bodyReceived; 353 int have_received_body;
353 354
354 /** 355 /**
355 * Have we finished sending all of the headers yet? 356 * Have we finished sending all of the headers yet?
356 */ 357 */
357 int headersSent; 358 int have_sent_headers;
358 359
359 /** 360 /**
360 * HTTP response code. Only valid if response object 361 * HTTP response code. Only valid if response object
@@ -371,6 +372,29 @@ struct MHD_Connection
371 */ 372 */
372 int response_unready; 373 int response_unready;
373 374
375 /**
376 * Are we receiving with chunked encoding? This will be set to
377 * MHD_YES after we parse the headers and are processing the body
378 * with chunks. After we are done with the body and we are
379 * processing the footers; once the footers are also done, this will
380 * be set to MHD_NO again (before the final call to the handler).
381 */
382 int have_chunked_upload;
383
384 /**
385 * If we are receiving with chunked encoding, where are we right
386 * now? Set to 0 if we are waiting to receive the chunk size;
387 * otherwise, this is the size of the current chunk. A value of
388 * zero is also used when we're at the end of the chunks.
389 */
390 unsigned int current_chunk_size;
391
392 /**
393 * If we are receiving with chunked encoding, where are we currently
394 * with respect to the current chunk (at what offset / position)?
395 */
396 unsigned int current_chunk_offset;
397
374}; 398};
375 399
376 400