diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | doc/microhttpd.texi | 25 | ||||
-rw-r--r-- | src/daemon/connection.c | 20 | ||||
-rw-r--r-- | src/examples/fileserver_example_dirs.c | 2 | ||||
-rw-r--r-- | src/examples/minimal_example_comet.c | 2 | ||||
-rw-r--r-- | src/include/microhttpd.h | 40 | ||||
-rw-r--r-- | src/testcurl/daemontest_get_chunked.c | 4 | ||||
-rw-r--r-- | src/testzzuf/daemontest_get_chunked.c | 4 |
8 files changed, 85 insertions, 19 deletions
@@ -1,3 +1,10 @@ | |||
1 | Wed Nov 17 12:16:53 CET 2010 | ||
2 | Allowing signalling of errors in generating chunked responses to | ||
3 | clients (by closing connectins) using the new | ||
4 | MHD_CONTENT_READER_END_WITH_ERROR ((size_t)-2) return value. Also | ||
5 | introducing MHD_CONTENT_READER_END_OF_STREAM constant instead | ||
6 | of (size_t) -1 / SIZE_MAX. | ||
7 | |||
1 | Sun Nov 14 20:45:45 CET 2010 | 8 | Sun Nov 14 20:45:45 CET 2010 |
2 | Adding API call to generate HTTP footers in response. -CG | 9 | Adding API call to generate HTTP footers in response. -CG |
3 | 10 | ||
diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi index a2df1136..9f509814 100644 --- a/doc/microhttpd.texi +++ b/doc/microhttpd.texi | |||
@@ -857,7 +857,7 @@ iteration. | |||
857 | @end deftypefn | 857 | @end deftypefn |
858 | 858 | ||
859 | 859 | ||
860 | @deftypefn {Function Pointer} int {*MHD_ContentReaderCallback} (void *cls, uint64_t pos, char *buf, int max) | 860 | @deftypefn {Function Pointer} int {*MHD_ContentReaderCallback} (void *cls, uint64_t pos, char *buf, size_t max) |
861 | Callback used by @mhd{} in order to obtain content. The callback has to | 861 | Callback used by @mhd{} in order to obtain content. The callback has to |
862 | copy at most @var{max} bytes of content into @var{buf}. The total | 862 | copy at most @var{max} bytes of content into @var{buf}. The total |
863 | number of bytes that has been placed into @var{buf} should be returned. | 863 | number of bytes that has been placed into @var{buf} should be returned. |
@@ -870,6 +870,29 @@ that runs in internal @cfunction{select} mode is an error (since it | |||
870 | would result in busy waiting) and cause the program to be aborted | 870 | would result in busy waiting) and cause the program to be aborted |
871 | (@cfunction{abort}). | 871 | (@cfunction{abort}). |
872 | 872 | ||
873 | While usually the callback simply returns the number of bytes written | ||
874 | into @var{buf}, there are two special return value: | ||
875 | |||
876 | @code{MHD_CONTENT_READER_END_OF_STREAM} (-1) should be returned | ||
877 | for the regular end of transmission (with chunked encoding, MHD will then | ||
878 | terminate the chunk and send any HTTP footers that might be | ||
879 | present; without chunked encoding and given an unknown | ||
880 | response size, @mhd{} will simply close the connection; note | ||
881 | that while returning @code{MHD_CONTENT_READER_END_OF_STREAM} is not technically | ||
882 | legal if a response size was specified, MHD accepts this | ||
883 | and treats it just as @code{MHD_CONTENT_READER_END_WITH_ERROR}. | ||
884 | |||
885 | @code{MHD_CONTENT_READER_END_WITH_ERROR} (-2) is used to indicate a server | ||
886 | error generating the response; this will cause @mhd{} to simply | ||
887 | close the connection immediately. If a response size was | ||
888 | given or if chunked encoding is in use, this will indicate | ||
889 | an error to the client. Note, however, that if the client | ||
890 | does not know a response size and chunked encoding is not in | ||
891 | use, then clients will not be able to tell the difference between | ||
892 | @code{MHD_CONTENT_READER_END_WITH_ERROR} and | ||
893 | @code{MHD_CONTENT_READER_END_OF_STREAM}. | ||
894 | This is not a limitation of @mhd{} but rather of the HTTP protocol. | ||
895 | |||
873 | @table @var | 896 | @table @var |
874 | @item cls | 897 | @item cls |
875 | custom value selected at callback registration time; | 898 | custom value selected at callback registration time; |
diff --git a/src/daemon/connection.c b/src/daemon/connection.c index cd8b6141..247ec178 100644 --- a/src/daemon/connection.c +++ b/src/daemon/connection.c | |||
@@ -357,14 +357,15 @@ try_ready_normal_body (struct MHD_Connection *connection) | |||
357 | NULL | 357 | NULL |
358 | #endif | 358 | #endif |
359 | ); | 359 | ); |
360 | if (ret == -1) | 360 | if ( (ret == MHD_CONTENT_READER_END_OF_STREAM) || |
361 | (ret == MHD_CONTENT_READER_END_WITH_ERROR) ) | ||
361 | { | 362 | { |
362 | /* either error or http 1.0 transfer, close | 363 | /* either error or http 1.0 transfer, close |
363 | socket! */ | 364 | socket! */ |
364 | #if DEBUG_CLOSE | 365 | #if DEBUG_CLOSE |
365 | #if HAVE_MESSAGES | 366 | #if HAVE_MESSAGES |
366 | MHD_DLOG (connection->daemon, | 367 | MHD_DLOG (connection->daemon, |
367 | "Closing connection (end of response)\n"); | 368 | "Closing connection (end of response or error)\n"); |
368 | #endif | 369 | #endif |
369 | #endif | 370 | #endif |
370 | response->total_size = connection->response_write_position; | 371 | response->total_size = connection->response_write_position; |
@@ -444,7 +445,20 @@ try_ready_chunked_body (struct MHD_Connection *connection) | |||
444 | &connection->write_buffer[sizeof (cbuf)], | 445 | &connection->write_buffer[sizeof (cbuf)], |
445 | connection->write_buffer_size - sizeof (cbuf) - 2); | 446 | connection->write_buffer_size - sizeof (cbuf) - 2); |
446 | } | 447 | } |
447 | if (ret == -1) | 448 | if (ret == MHD_CONTENT_READER_END_WITH_ERROR) |
449 | { | ||
450 | /* error, close socket! */ | ||
451 | #if DEBUG_CLOSE | ||
452 | #if HAVE_MESSAGES | ||
453 | MHD_DLOG (connection->daemon, | ||
454 | "Closing connection (error generating response)\n"); | ||
455 | #endif | ||
456 | #endif | ||
457 | response->total_size = connection->response_write_position; | ||
458 | connection_close_error (connection); | ||
459 | return MHD_NO; | ||
460 | } | ||
461 | if (ret == MHD_CONTENT_READER_END_OF_STREAM) | ||
448 | { | 462 | { |
449 | /* end of message, signal other side! */ | 463 | /* end of message, signal other side! */ |
450 | strcpy (connection->write_buffer, "0\r\n"); | 464 | strcpy (connection->write_buffer, "0\r\n"); |
diff --git a/src/examples/fileserver_example_dirs.c b/src/examples/fileserver_example_dirs.c index 8c874994..836c0623 100644 --- a/src/examples/fileserver_example_dirs.c +++ b/src/examples/fileserver_example_dirs.c | |||
@@ -66,7 +66,7 @@ dir_reader (void *cls, uint64_t pos, char *buf, size_t max) | |||
66 | { | 66 | { |
67 | e = readdir (dir); | 67 | e = readdir (dir); |
68 | if (e == NULL) | 68 | if (e == NULL) |
69 | return -1; | 69 | return MHD_CONTENT_READER_END_OF_STREAM; |
70 | } while (e->d_name[0] == '.'); | 70 | } while (e->d_name[0] == '.'); |
71 | return snprintf (buf, max, | 71 | return snprintf (buf, max, |
72 | "<a href=\"/%s\">%s</a><br>", | 72 | "<a href=\"/%s\">%s</a><br>", |
diff --git a/src/examples/minimal_example_comet.c b/src/examples/minimal_example_comet.c index 9b25889e..83493243 100644 --- a/src/examples/minimal_example_comet.c +++ b/src/examples/minimal_example_comet.c | |||
@@ -56,7 +56,7 @@ ahc_echo (void *cls, | |||
56 | return MHD_YES; | 56 | return MHD_YES; |
57 | } | 57 | } |
58 | *ptr = NULL; /* reset when done */ | 58 | *ptr = NULL; /* reset when done */ |
59 | response = MHD_create_response_from_callback (-1, | 59 | response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, |
60 | 80, | 60 | 80, |
61 | &data_generator, NULL, NULL); | 61 | &data_generator, NULL, NULL); |
62 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | 62 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); |
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 1b1a986d..7d99948e 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -133,6 +133,15 @@ extern "C" | |||
133 | #define MHD_SIZE_UNKNOWN ((uint64_t) -1LL) | 133 | #define MHD_SIZE_UNKNOWN ((uint64_t) -1LL) |
134 | #endif | 134 | #endif |
135 | 135 | ||
136 | #ifdef SIZE_MAX | ||
137 | #define MHD_CONTENT_READER_END_OF_STREAM SIZE_MAX | ||
138 | #define MHD_CONTENT_READER_END_WITH_ERROR (SIZE_MAX - 1) | ||
139 | #else | ||
140 | #define MHD_CONTENT_READER_END ((size_t) -1LL) | ||
141 | #define MHD_CONTENT_READER_END_WITH_ERROR (((size_t) -LL) - 1) | ||
142 | #endif | ||
143 | |||
144 | |||
136 | /** | 145 | /** |
137 | * HTTP response codes. | 146 | * HTTP response codes. |
138 | */ | 147 | */ |
@@ -868,15 +877,28 @@ typedef int | |||
868 | * obtained from the content reader so far. | 877 | * obtained from the content reader so far. |
869 | * @param buf where to copy the data | 878 | * @param buf where to copy the data |
870 | * @param max maximum number of bytes to copy to buf (size of buf) | 879 | * @param max maximum number of bytes to copy to buf (size of buf) |
871 | * @return -1 for the end of transmission (or on error); | 880 | * @return number of bytes written to 'buf'; |
872 | * if a content transfer size was pre-set and the callback | 881 | * 0 is legal unless we are running in internal select mode (since |
873 | * has provided fewer than that amount of data, | 882 | * this would cause busy-waiting); 0 in external select mode |
874 | * MHD will close the connection with the client; | 883 | * will cause this function to be called again once the external |
875 | * if no content size was specified and this is an | 884 | * select calls MHD again; |
876 | * http 1.1 connection using chunked encoding, MHD will | 885 | * MHD_CONTENT_READER_END_OF_STREAM (-1) for the regular |
877 | * interpret "-1" as the normal end of the transfer | 886 | * end of transmission (with chunked encoding, MHD will then |
878 | * (possibly allowing the client to perform additional | 887 | * terminate the chunk and send any HTTP footers that might be |
879 | * requests using the same TCP connection). | 888 | * present; without chunked encoding and given an unknown |
889 | * response size, MHD will simply close the connection; note | ||
890 | * that while returning END_OF_STREAM is not technically | ||
891 | * legal if a response size was specified, MHD accepts this | ||
892 | * and treats it just as MHD_CONTENT_READER_END_WITH_ERROR; | ||
893 | * MHD_CONTENT_READER_END_WITH_ERROR (-2) to indicate a server | ||
894 | * error generating the response; this will cause MHD to simply | ||
895 | * close the connection immediately. If a response size was | ||
896 | * given or if chunked encoding is in use, this will indicate | ||
897 | * an error to the client. Note, however, that if the client | ||
898 | * does not know a response size and chunked encoding is not in | ||
899 | * use, then clients will not be able to tell the difference between | ||
900 | * MHD_CONTENT_READER_END_WITH_ERROR and MHD_CONTENT_READER_END_OF_STREAM. | ||
901 | * This is not a limitation of MHD but rather of the HTTP protocol. | ||
880 | */ | 902 | */ |
881 | typedef ssize_t | 903 | typedef ssize_t |
882 | (*MHD_ContentReaderCallback) (void *cls, | 904 | (*MHD_ContentReaderCallback) (void *cls, |
diff --git a/src/testcurl/daemontest_get_chunked.c b/src/testcurl/daemontest_get_chunked.c index e5b1a73a..fd2561ca 100644 --- a/src/testcurl/daemontest_get_chunked.c +++ b/src/testcurl/daemontest_get_chunked.c | |||
@@ -71,7 +71,7 @@ crc (void *cls, uint64_t pos, char *buf, size_t max) | |||
71 | if (pos == 128 * 10) | 71 | if (pos == 128 * 10) |
72 | { | 72 | { |
73 | MHD_add_response_header (*responseptr, "Footer", "working"); | 73 | MHD_add_response_header (*responseptr, "Footer", "working"); |
74 | return -1; /* end of stream */ | 74 | return MHD_CONTENT_READER_END_OF_STREAM; |
75 | } | 75 | } |
76 | if (max < 128) | 76 | if (max < 128) |
77 | abort (); /* should not happen in this testcase... */ | 77 | abort (); /* should not happen in this testcase... */ |
@@ -113,7 +113,7 @@ ahc_echo (void *cls, | |||
113 | responseptr = malloc (sizeof (struct MHD_Response *)); | 113 | responseptr = malloc (sizeof (struct MHD_Response *)); |
114 | if (responseptr == NULL) | 114 | if (responseptr == NULL) |
115 | return MHD_NO; | 115 | return MHD_NO; |
116 | response = MHD_create_response_from_callback (-1, | 116 | response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, |
117 | 1024, | 117 | 1024, |
118 | &crc, responseptr, &crcf); | 118 | &crc, responseptr, &crcf); |
119 | *responseptr = response; | 119 | *responseptr = response; |
diff --git a/src/testzzuf/daemontest_get_chunked.c b/src/testzzuf/daemontest_get_chunked.c index 655f402a..35eed49d 100644 --- a/src/testzzuf/daemontest_get_chunked.c +++ b/src/testzzuf/daemontest_get_chunked.c | |||
@@ -69,7 +69,7 @@ crc (void *cls, uint64_t pos, char *buf, size_t max) | |||
69 | if (pos == 128 * 10) | 69 | if (pos == 128 * 10) |
70 | { | 70 | { |
71 | MHD_add_response_header (*responseptr, "Footer", "working"); | 71 | MHD_add_response_header (*responseptr, "Footer", "working"); |
72 | return -1; /* end of stream */ | 72 | return MHD_CONTENT_READER_END_OF_STREAM; |
73 | } | 73 | } |
74 | if (max < 128) | 74 | if (max < 128) |
75 | abort (); /* should not happen in this testcase... */ | 75 | abort (); /* should not happen in this testcase... */ |
@@ -109,7 +109,7 @@ ahc_echo (void *cls, | |||
109 | return MHD_YES; | 109 | return MHD_YES; |
110 | } | 110 | } |
111 | responseptr = malloc (sizeof (struct MHD_Response *)); | 111 | responseptr = malloc (sizeof (struct MHD_Response *)); |
112 | response = MHD_create_response_from_callback (-1, | 112 | response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, |
113 | 1024, | 113 | 1024, |
114 | &crc, responseptr, &crcf); | 114 | &crc, responseptr, &crcf); |
115 | *responseptr = response; | 115 | *responseptr = response; |