libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit a747d35a8bb6593e3418c5bf2c5704c29dc56d73
parent 2fb1e810a3f5bca2b32f946b3a33b6faebb54f6d
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 10 Mar 2010 12:19:27 +0000

bugfix

Diffstat:
MChangeLog | 6+++++-
Msrc/daemon/connection.c | 38+++++++++++++++++++++++++++++++++++++-
Msrc/testcurl/daemontest_post.c | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 217 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,7 @@ +Wed Mar 10 13:18:26 CET 2010 + Fixing bug in 100 CONTINUE replacement when handling POSTs + (see report on mailinglist), with testcase. -CG/MC + Tue Feb 23 09:16:15 CET 2010 Added configure check for endianness to define WORDS_BIGENDIAN which fixes SSL support on big endian architectures. -JA/CG @@ -15,7 +19,7 @@ Thu Jan 28 21:28:56 CET 2010 Thu Jan 28 20:35:48 CET 2010 Make sure addresses returned by memory pool are aligned (fixes bus errors on Sparc). -CG - + Thu Dec 17 20:26:52 CET 2009 poll.h is not stricly required anymore. -ND diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -1140,6 +1140,7 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line) return MHD_YES; } + /** * Call the handler of the application for this * connection. Handles chunking of the upload @@ -1149,6 +1150,41 @@ static void call_connection_handler (struct MHD_Connection *connection) { size_t processed; + + if (connection->response != NULL) + return; /* already queued a response */ + processed = 0; + connection->client_aware = MHD_YES; + if (MHD_NO == + connection->daemon->default_handler (connection->daemon-> + default_handler_cls, + connection, connection->url, + connection->method, + connection->version, + NULL, &processed, + &connection->client_context)) + { + /* serious internal error, close connection */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Internal application error, closing connection.\n"); +#endif + connection_close_error (connection); + return; + } +} + + + +/** + * Call the handler of the application for this + * connection. Handles chunking of the upload + * as well as normal uploads. + */ +static void +process_request_body (struct MHD_Connection *connection) +{ + size_t processed; size_t available; size_t used; size_t i; @@ -1949,7 +1985,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) case MHD_CONNECTION_CONTINUE_SENT: if (connection->read_buffer_offset != 0) { - call_connection_handler (connection); /* loop call */ + process_request_body (connection); /* loop call */ if (connection->state == MHD_CONNECTION_CLOSED) continue; } diff --git a/src/testcurl/daemontest_post.c b/src/testcurl/daemontest_post.c @@ -409,7 +409,181 @@ testExternalPost () return 0; } +static int +ahc_cancel (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("POST", method)) + { + fprintf (stderr, + "Unexpected method `%s'\n", method); + return MHD_NO; + } + + if (*unused == NULL) + { + *unused = "wibble"; + /* We don't want the body. Send a 500. */ + response = MHD_create_response_from_data(0, NULL, 0, 0); + ret = MHD_queue_response(connection, 500, response); + if (ret != MHD_YES) + fprintf(stderr, "Failed to queue response\n"); + MHD_destroy_response(response); + return ret; + } + else + { + fprintf(stderr, + "In ahc_cancel again. This should not happen.\n"); + return MHD_NO; + } +} + +struct CRBC +{ + const char *buffer; + size_t size; + size_t pos; +}; + +static size_t +readBuffer(void *p, size_t size, size_t nmemb, void *opaque) +{ + struct CRBC *data = opaque; + size_t required = size * nmemb; + size_t left = data->size - data->pos; + + if (required > left) + required = left; + + memcpy(p, data->buffer + data->pos, required); + data->pos += required; + + return required/size; +} + +static size_t +slowReadBuffer(void *p, size_t size, size_t nmemb, void *opaque) +{ + sleep(1); + return readBuffer(p, size, nmemb, opaque); +} + +#define FLAG_EXPECT_CONTINUE 1 +#define FLAG_CHUNKED 2 +#define FLAG_FORM_DATA 4 +#define FLAG_SLOW_READ 8 +#define FLAG_COUNT 16 + +static int +testMultithreadedPostCancelPart(int flags) +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + struct curl_slist *headers = NULL; + long response_code; + CURLcode cc; + int result = 0; + struct CRBC crbc; + + /* Don't test features that aren't available with HTTP/1.0 in + * HTTP/1.0 mode. */ + if (!oneone && (flags & (FLAG_EXPECT_CONTINUE | FLAG_CHUNKED))) + return 0; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_cancel, NULL, MHD_OPTION_END); + if (d == NULL) + return 32768; + crbc.buffer = "Test content"; + crbc.size = strlen(crbc.buffer); + crbc.pos = 0; + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, (flags & FLAG_SLOW_READ) ? &slowReadBuffer : &readBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &crbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, NULL); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, crbc.size); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + if (flags & FLAG_CHUNKED) + headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); + if (!(flags & FLAG_FORM_DATA)) + headers = curl_slist_append(headers, "Content-Type: application/octet-stream"); + if (flags & FLAG_EXPECT_CONTINUE) + headers = curl_slist_append(headers, "Expect: 100-Continue"); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers); + + if (CURLE_HTTP_RETURNED_ERROR != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "flibbet curl_easy_perform didn't fail as expected: `%s' %d\n", + curl_easy_strerror (errornum), errornum); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + curl_slist_free_all(headers); + return 65536; + } + + if (CURLE_OK != (cc = curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &response_code))) + { + fprintf(stderr, "curl_easy_getinfo failed: '%s'\n", curl_easy_strerror(errornum)); + result = 65536; + } + + if (!result && (response_code != 500)) + { + fprintf(stderr, "Unexpected response code: %ld\n", response_code); + result = 131072; + } + + if (!result && (cbc.pos != 0)) + result = 262144; + + curl_easy_cleanup (c); + MHD_stop_daemon (d); + curl_slist_free_all(headers); + return result; +} + +static int +testMultithreadedPostCancel() +{ + int result = 0; + int flags; + for(flags = 0; flags < FLAG_COUNT; ++flags) + result |= testMultithreadedPostCancelPart(flags); + return result; +} int main (int argc, char *const *argv) @@ -419,6 +593,7 @@ main (int argc, char *const *argv) oneone = NULL != strstr (argv[0], "11"); if (0 != curl_global_init (CURL_GLOBAL_WIN32)) return 2; + errorCount += testMultithreadedPostCancel (); errorCount += testInternalPost (); errorCount += testMultithreadedPost (); errorCount += testMultithreadedPoolPost ();