From 4a9bb6522a5dcb991e69ad8b975df6e616a5238f Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 25 Mar 2008 19:47:23 +0000 Subject: Alex's patches --- ChangeLog | 18 + configure.ac | 4 +- src/daemon/Makefile.am | 2 +- src/daemon/connection.c | 18 +- src/daemon/daemon.c | 77 +++-- src/daemon/minimal_example.c | 5 +- src/daemon/postprocessor.c | 745 ++++++++++++++++++++-------------------- src/daemon/postprocessor_test.c | 159 ++++----- src/daemon/response.c | 8 +- 9 files changed, 517 insertions(+), 519 deletions(-) diff --git a/ChangeLog b/ChangeLog index d9887909..66b047f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +Tue Mar 25 13:40:53 MDT 2008 + Prevent multi-part post-processor from going to error + state when the input buffer is full and current token + just changes processor state without consuming any data. + Also, the original implementation would not consume any + input in process_value_to_boundary if there is no new + line character in sight. -AS + + Remove checks for request method after it finished writing + response footers as it's only _pipelined_ requests that + should not be allowed after POST or PUT requests. Reusing + the existing connection is perfectly ok though. And there + is no reliable way to detect pipelining on server side + anyway so it is the client's responsibility to not send new + data before it gets a response after a POST operation. -AS + + Clarified license in man page. -CG + Sat Mar 22 01:12:38 MDT 2008 Releasing libmicrohttpd 0.2.2. -CG diff --git a/configure.ac b/configure.ac index 4413681e..975bb519 100644 --- a/configure.ac +++ b/configure.ac @@ -21,8 +21,8 @@ # # AC_PREREQ(2.57) -AC_INIT([libmicrohttpd], [0.2.2],[libmicrohttpd@gnunet.org]) -AM_INIT_AUTOMAKE([libmicrohttpd], [0.2.2]) +AC_INIT([libmicrohttpd], [0.2.3],[libmicrohttpd@gnunet.org]) +AM_INIT_AUTOMAKE([libmicrohttpd], [0.2.3]) AM_CONFIG_HEADER([config.h]) AH_TOP([#define _GNU_SOURCE 1]) diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index 254dab8c..b2f58c94 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -12,7 +12,7 @@ lib_LTLIBRARIES = \ libmicrohttpd.la libmicrohttpd_la_LDFLAGS = \ - -export-dynamic -version-info 3:1:0 $(retaincommand) + -export-dynamic -version-info 3:2:0 $(retaincommand) libmicrohttpd_la_SOURCES = \ connection.c connection.h \ reason_phrase.c reason_phrase.h \ diff --git a/src/daemon/connection.c b/src/daemon/connection.c index 08b503d7..60cbfe43 100644 --- a/src/daemon/connection.c +++ b/src/daemon/connection.c @@ -654,9 +654,9 @@ MHD_connection_get_fdset (struct MHD_Connection *connection, case MHD_CONNECTION_CONTINUE_SENT: if (connection->read_buffer_offset == connection->read_buffer_size) try_grow_read_buffer (connection); - if ( (connection->read_buffer_offset < connection->read_buffer_size) && - (MHD_NO == connection->read_closed) ) - do_fd_set (fd, read_fd_set, max_fd); + if ((connection->read_buffer_offset < connection->read_buffer_size) + && (MHD_NO == connection->read_closed)) + do_fd_set (fd, read_fd_set, max_fd); break; case MHD_CONNECTION_BODY_RECEIVED: case MHD_CONNECTION_FOOTER_PART_RECEIVED: @@ -1797,13 +1797,9 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) if (((MHD_YES == connection->read_closed) && (0 == connection->read_buffer_offset)) || (connection->version == NULL) || - (connection->method == NULL) || - ( (0 != strcasecmp (MHD_HTTP_METHOD_HEAD, connection->method)) && - (0 != strcasecmp (MHD_HTTP_METHOD_GET, connection->method)) ) || - (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) + (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) { - /* http 1.0, version-less or non-HEAD/GET requests cannot be - pipelined */ + /* http 1.0, version-less requests cannot be pipelined */ connection->state = MHD_CONNECTION_CLOSED; MHD_pool_destroy (connection->pool); connection->pool = NULL; @@ -1832,8 +1828,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) break; } timeout = connection->daemon->connection_timeout; - if ( (connection->socket_fd != -1) && - (timeout != 0) && (time (NULL) - timeout > connection->last_activity)) + if ((connection->socket_fd != -1) && + (timeout != 0) && (time (NULL) - timeout > connection->last_activity)) { connection_close_error (connection); return MHD_NO; diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index e971c9b2..971196f8 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c @@ -172,7 +172,7 @@ MHD_handle_connection (void *data) static int MHD_accept_connection (struct MHD_Daemon *daemon) { - struct MHD_Connection *pos; + struct MHD_Connection *pos; struct MHD_Connection *connection; struct sockaddr_in6 addr6; struct sockaddr *addr = (struct sockaddr *) &addr6; @@ -204,42 +204,44 @@ MHD_accept_connection (struct MHD_Daemon *daemon) #if DEBUG_CONNECT MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); #endif - have = 0; - if ( (daemon->per_ip_connection_limit != 0) && - (daemon->max_connections > 0) ) + have = 0; + if ((daemon->per_ip_connection_limit != 0) && (daemon->max_connections > 0)) { pos = daemon->connections; - while (pos != NULL) - { - if ( (pos->addr != NULL) && - (pos->addr_len == addrlen) ) - { - if (addrlen == sizeof(struct sockaddr_in)) - { - const struct sockaddr_in * a1 = (const struct sockaddr_in *) &addr; - const struct sockaddr_in * a2 = (const struct sockaddr_in *) pos->addr; - if (0 == memcmp(&a1->sin_addr, - &a2->sin_addr, - sizeof(struct in_addr))) - have++; - } - if (addrlen == sizeof(struct sockaddr_in6)) - { - const struct sockaddr_in6 * a1 = (const struct sockaddr_in6 *) &addr; - const struct sockaddr_in6 * a2 = (const struct sockaddr_in6 *) pos->addr; - if (0 == memcmp(&a1->sin6_addr, - &a2->sin6_addr, - sizeof(struct in6_addr))) - have++; - } - } - pos = pos->next; - } + while (pos != NULL) + { + if ((pos->addr != NULL) && (pos->addr_len == addrlen)) + { + if (addrlen == sizeof (struct sockaddr_in)) + { + const struct sockaddr_in *a1 = + (const struct sockaddr_in *) &addr; + const struct sockaddr_in *a2 = + (const struct sockaddr_in *) pos->addr; + if (0 == + memcmp (&a1->sin_addr, &a2->sin_addr, + sizeof (struct in_addr))) + have++; + } + if (addrlen == sizeof (struct sockaddr_in6)) + { + const struct sockaddr_in6 *a1 = + (const struct sockaddr_in6 *) &addr; + const struct sockaddr_in6 *a2 = + (const struct sockaddr_in6 *) pos->addr; + if (0 == + memcmp (&a1->sin6_addr, &a2->sin6_addr, + sizeof (struct in6_addr))) + have++; + } + } + pos = pos->next; + } } - if ( (daemon->max_connections == 0) || - ( (daemon->per_ip_connection_limit != 0) && - (daemon->per_ip_connection_limit <= have) ) ) + if ((daemon->max_connections == 0) || + ((daemon->per_ip_connection_limit != 0) && + (daemon->per_ip_connection_limit <= have))) { /* above connection limit - reject */ #if HAVE_MESSAGES @@ -635,7 +637,7 @@ MHD_start_daemon (unsigned int options, retVal = malloc (sizeof (struct MHD_Daemon)); if (retVal == NULL) { - CLOSE(socket_fd); + CLOSE (socket_fd); return NULL; } memset (retVal, 0, sizeof (struct MHD_Daemon)); @@ -668,10 +670,9 @@ MHD_start_daemon (unsigned int options, va_arg (ap, MHD_RequestCompletedCallback); retVal->notify_completed_cls = va_arg (ap, void *); break; - case MHD_OPTION_PER_IP_CONNECTION_LIMIT: - retVal->per_ip_connection_limit - = va_arg (ap, unsigned int); - break; + case MHD_OPTION_PER_IP_CONNECTION_LIMIT: + retVal->per_ip_connection_limit = va_arg (ap, unsigned int); + break; default: #if HAVE_MESSAGES fprintf (stderr, diff --git a/src/daemon/minimal_example.c b/src/daemon/minimal_example.c index 0cbf3a14..647a4776 100644 --- a/src/daemon/minimal_example.c +++ b/src/daemon/minimal_example.c @@ -40,9 +40,8 @@ ahc_echo (void *cls, struct MHD_Connection *connection, const char *url, const char *method, - const char *version, - const char *upload_data, - unsigned int *upload_data_size, void **ptr) + const char *version, + const char *upload_data, unsigned int *upload_data_size, void **ptr) { static int aptr; const char *me = cls; diff --git a/src/daemon/postprocessor.c b/src/daemon/postprocessor.c index 5b8f01a2..8be3ee89 100644 --- a/src/daemon/postprocessor.c +++ b/src/daemon/postprocessor.c @@ -40,13 +40,13 @@ enum PP_State PP_Done, PP_Init, - /* url encoding-states*/ - PP_ProcessValue, - PP_ExpectNewLine, + /* url encoding-states */ + PP_ProcessValue, + PP_ExpectNewLine, /* post encoding-states */ PP_ProcessEntryHeaders, - PP_PerformCheckMultipart, + PP_PerformCheckMultipart, PP_ProcessValueToBoundary, PP_PerformCleanup, @@ -56,7 +56,7 @@ enum PP_State PP_Nested_ProcessEntryHeaders, PP_Nested_ProcessValueToBoundary, PP_Nested_PerformCleanup, - + }; enum RN_State @@ -76,11 +76,11 @@ enum RN_State * Expect '\r\n' (and only '\r\n'). As always, we also * expect only '\r' or only '\n'. */ - RN_Full = 2, + RN_Full = 2, /** * Expect either '\r\n' or '--\r\n'. If '--\r\n', transition into dash-state - * for the main state machine + * for the main state machine */ RN_Dash = 3, @@ -94,8 +94,8 @@ enum RN_State * Bits for the globally known fields that * should not be deleted when we exit the * nested state. - */ -enum NE_State + */ +enum NE_State { NE_none = 0, NE_content_name = 1, @@ -136,12 +136,12 @@ struct MHD_PostProcessor /** * Primary boundary (points into encoding string) */ - const char * boundary; + const char *boundary; /** - * Nested boundary (if we have multipart/mixed encoding). + * Nested boundary (if we have multipart/mixed encoding). */ - char * nested_boundary; + char *nested_boundary; /** * Pointer to the name given in disposition. @@ -263,23 +263,22 @@ MHD_create_post_processor (struct MHD_Connection *connection, if (encoding == NULL) return NULL; boundary = NULL; - if (0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, - encoding)) + if (0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding)) { - if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding, - strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) - return NULL; + if (0 != + strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding, + strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) + return NULL; boundary = - &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)]; + &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)]; /* Q: should this be "strcasestr"? */ if (NULL != strstr (boundary, "boundary=")) - boundary = strstr (boundary, "boundary=") + strlen ("boundary="); + boundary = strstr (boundary, "boundary=") + strlen ("boundary="); else - return NULL; /* failed to determine boundary */ + return NULL; /* failed to determine boundary */ blen = strlen (boundary); - if ( (blen == 0) || - (blen * 2 + 2 > buffer_size) ) - return NULL; /* (will be) out of memory or invalid boundary */ + if ((blen == 0) || (blen * 2 + 2 > buffer_size)) + return NULL; /* (will be) out of memory or invalid boundary */ } else blen = 0; @@ -322,10 +321,10 @@ post_process_urlencoded (struct MHD_PostProcessor *pp, { case PP_Error: return MHD_NO; - case PP_Done: - /* did not expect to receive more data */ - pp->state = PP_Error; - return MHD_NO; + case PP_Done: + /* did not expect to receive more data */ + pp->state = PP_Error; + return MHD_NO; case PP_Init: equals = 0; while ((equals + poff < post_data_len) && @@ -444,39 +443,37 @@ try_match_header (const char *prefix, char *line, char **suffix) { if (NULL != *suffix) return MHD_NO; - while(*line != 0) + while (*line != 0) { - if (0 == strncasecmp (prefix, line, strlen (prefix))) - { - *suffix = strdup (&line[strlen (prefix)]); - return MHD_YES; - } - ++line; + if (0 == strncasecmp (prefix, line, strlen (prefix))) + { + *suffix = strdup (&line[strlen (prefix)]); + return MHD_YES; + } + ++line; } return MHD_NO; } static int -find_boundary(struct MHD_PostProcessor * pp, - const char * boundary, - size_t blen, - unsigned int * ioffptr, - enum PP_State next_state, - enum PP_State next_dash_state) +find_boundary (struct MHD_PostProcessor *pp, + const char *boundary, + size_t blen, + unsigned int *ioffptr, + enum PP_State next_state, enum PP_State next_dash_state) { - char * buf = (char*) &pp[1]; + char *buf = (char *) &pp[1]; if (pp->buffer_pos < 2 + blen) { if (pp->buffer_pos == pp->buffer_size) - pp->state = PP_Error; /* out of memory */ - return MHD_NO; /* not enough data */ - } - if ( (0 != memcmp ("--", buf, 2)) || - (0 != memcmp (&buf[2], boundary, blen))) + pp->state = PP_Error; /* out of memory */ + return MHD_NO; /* not enough data */ + } + if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen))) { pp->state = PP_Error; - return MHD_NO; /* expected boundary */ + return MHD_NO; /* expected boundary */ } /* remove boundary from buffer */ (*ioffptr) += 2 + blen; @@ -491,49 +488,43 @@ find_boundary(struct MHD_PostProcessor * pp, * In buf, there maybe an expression * '$key="$value"'. If that is the case, * copy a copy of $value to destination. - * + * * If destination is already non-NULL, * do nothing. */ static void -try_get_value(const char * buf, - const char * key, - char ** destination) +try_get_value (const char *buf, const char *key, char **destination) { - const char * spos; - const char * bpos; - const char * endv; + const char *spos; + const char *bpos; + const char *endv; size_t klen; size_t vlen; if (NULL != *destination) return; bpos = buf; - klen = strlen(key); - while (NULL != (spos = strstr(bpos, key))) + klen = strlen (key); + while (NULL != (spos = strstr (bpos, key))) { - if ( (spos[klen] != '=') || - ( (spos != buf) && - (spos[-1] != ' ') ) ) - { - /* no match */ - bpos = spos + 1; - continue; - } + if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' '))) + { + /* no match */ + bpos = spos + 1; + continue; + } if (spos[klen + 1] != '"') - return; /* not quoted */ - if (NULL == (endv = strstr(&spos[klen+2], "\""))) - return; /* no end-quote */ + return; /* not quoted */ + if (NULL == (endv = strstr (&spos[klen + 2], "\""))) + return; /* no end-quote */ vlen = endv - spos - klen - 1; - *destination = malloc(vlen); + *destination = malloc (vlen); if (NULL == *destination) - return; /* out of memory */ + return; /* out of memory */ (*destination)[vlen - 1] = '\0'; - memcpy(*destination, - &spos[klen + 2], - vlen - 1); - return; /* success */ - } + memcpy (*destination, &spos[klen + 2], vlen - 1); + return; /* success */ + } } /** @@ -541,37 +532,35 @@ try_get_value(const char * buf, * the fields in "pp" according to what we find. * If we are at the end of the headers (as indicated * by an empty line), transition into next_state. - * + * * @param ioffptr set to how many bytes have been * processed * @return MHD_YES if we can continue processing, * MHD_NO on error or if we do not have * enough data yet - */ + */ static int -process_multipart_headers(struct MHD_PostProcessor * pp, - unsigned int * ioffptr, - enum PP_State next_state) +process_multipart_headers (struct MHD_PostProcessor *pp, + unsigned int *ioffptr, enum PP_State next_state) { - char * buf = (char*) &pp[1]; + char *buf = (char *) &pp[1]; unsigned int newline; newline = 0; while ((newline < pp->buffer_pos) && - (buf[newline] != '\r') && - (buf[newline] != '\n')) + (buf[newline] != '\r') && (buf[newline] != '\n')) newline++; if (newline == pp->buffer_size) { pp->state = PP_Error; - return MHD_NO; /* out of memory */ + return MHD_NO; /* out of memory */ } if (newline == pp->buffer_pos) - return MHD_NO; /* will need more data */ + return MHD_NO; /* will need more data */ if (newline == 0) { /* empty line - end of headers */ - pp->skip_rn = RN_Full; + pp->skip_rn = RN_Full; pp->state = next_state; return MHD_YES; } @@ -579,24 +568,21 @@ process_multipart_headers(struct MHD_PostProcessor * pp, if (buf[newline] == '\r') pp->skip_rn = RN_OptN; buf[newline] = '\0'; - if (0 == strncasecmp("Content-disposition: ", - buf, - strlen("Content-disposition: "))) - { - try_get_value(&buf[strlen("Content-disposition: ")], - "name", - &pp->content_name); - try_get_value(&buf[strlen("Content-disposition: ")], - "filename", - &pp->content_filename); + if (0 == strncasecmp ("Content-disposition: ", + buf, strlen ("Content-disposition: "))) + { + try_get_value (&buf[strlen ("Content-disposition: ")], + "name", &pp->content_name); + try_get_value (&buf[strlen ("Content-disposition: ")], + "filename", &pp->content_filename); } - else + else { try_match_header ("Content-type: ", buf, &pp->content_type); try_match_header ("Content-Transfer-Encoding: ", - buf, &pp->content_transfer_encoding); -} - (*ioffptr) += newline + 1; + buf, &pp->content_transfer_encoding); + } + (*ioffptr) += newline + 1; return MHD_YES; } @@ -615,14 +601,14 @@ process_multipart_headers(struct MHD_PostProcessor * pp, * enough data yet */ static int -process_value_to_boundary(struct MHD_PostProcessor * pp, - unsigned int * ioffptr, - const char * boundary, - size_t blen, - enum PP_State next_state, - enum PP_State next_dash_state) +process_value_to_boundary (struct MHD_PostProcessor *pp, + unsigned int *ioffptr, + const char *boundary, + size_t blen, + enum PP_State next_state, + enum PP_State next_dash_state) { - char * buf = (char*) &pp[1]; + char *buf = (char *) &pp[1]; unsigned int newline; /* all data in buf until the boundary @@ -631,53 +617,51 @@ process_value_to_boundary(struct MHD_PostProcessor * pp, while (1) { while ((newline + 4 < pp->buffer_pos) && - (0 != memcmp ("\r\n--", &buf[newline], 4))) - newline++; - if (newline + pp->blen + 4 <= pp->buffer_pos) - { - /* can check boundary */ - if (0 != memcmp (&buf[newline + 4], boundary, pp->blen)) - { - /* no boundary, "\r\n--" is part of content, skip */ - newline += 4; - continue; - } - else - { - /* boundary found, process until newline then - skip boundary and go back to init */ - pp->skip_rn = RN_Dash; - pp->state = next_state; - pp->dash_state = next_dash_state; - (*ioffptr) += pp->blen + 4; /* skip boundary as well */ - break; - } - } + (0 != memcmp ("\r\n--", &buf[newline], 4))) + newline++; + if (newline + pp->blen + 4 <= pp->buffer_pos) + { + /* can check boundary */ + if (0 != memcmp (&buf[newline + 4], boundary, pp->blen)) + { + /* no boundary, "\r\n--" is part of content, skip */ + newline += 4; + continue; + } + else + { + /* boundary found, process until newline then + skip boundary and go back to init */ + pp->skip_rn = RN_Dash; + pp->state = next_state; + pp->dash_state = next_dash_state; + (*ioffptr) += pp->blen + 4; /* skip boundary as well */ + break; + } + } else - { - /* cannot check for boundary, process content that - we have and check again later; except, if we have - no content, abort (out of memory) */ - if ( (newline == 0) && - (pp->buffer_pos == pp->buffer_size) ) - { - pp->state = PP_Error; - return MHD_NO; - } - return MHD_NO; - } + { + /* cannot check for boundary, process content that + we have and check again later; except, if we have + no content, abort (out of memory) */ + if ((newline == 0) && (pp->buffer_pos == pp->buffer_size)) + { + pp->state = PP_Error; + return MHD_NO; + } + break; + } } /* newline is either at beginning of boundary or at least at the last character that we are sure is not part of the boundary */ if (MHD_NO == pp->ikvi (pp->cls, - MHD_POSTDATA_KIND, - pp->content_name, - pp->content_filename, - pp->content_type, - pp->content_transfer_encoding, - buf, - pp->value_offset, newline)) + MHD_POSTDATA_KIND, + pp->content_name, + pp->content_filename, + pp->content_type, + pp->content_transfer_encoding, + buf, pp->value_offset, newline)) { pp->state = PP_Error; return MHD_NO; @@ -688,30 +672,28 @@ process_value_to_boundary(struct MHD_PostProcessor * pp, } static void -free_unmarked(struct MHD_PostProcessor * pp) +free_unmarked (struct MHD_PostProcessor *pp) { - if ( (pp->content_name != NULL) && - (0 == (pp->have & NE_content_name)) ) + if ((pp->content_name != NULL) && (0 == (pp->have & NE_content_name))) { - free(pp->content_name); + free (pp->content_name); pp->content_name = NULL; } - if ( (pp->content_type != NULL) && - (0 == (pp->have & NE_content_type)) ) + if ((pp->content_type != NULL) && (0 == (pp->have & NE_content_type))) { - free(pp->content_type); + free (pp->content_type); pp->content_type = NULL; } - if ( (pp->content_filename != NULL) && - (0 == (pp->have & NE_content_filename)) ) + if ((pp->content_filename != NULL) && + (0 == (pp->have & NE_content_filename))) { - free(pp->content_filename); + free (pp->content_filename); pp->content_filename = NULL; } - if ( (pp->content_transfer_encoding != NULL) && - (0 == (pp->have & NE_content_transfer_encoding)) ) + if ((pp->content_transfer_encoding != NULL) && + (0 == (pp->have & NE_content_transfer_encoding))) { - free(pp->content_transfer_encoding); + free (pp->content_transfer_encoding); pp->content_transfer_encoding = NULL; } } @@ -727,251 +709,252 @@ post_process_multipart (struct MHD_PostProcessor *pp, unsigned int max; unsigned int ioff; unsigned int poff; + int state_changed; buf = (char *) &pp[1]; ioff = 0; poff = 0; - max = 1; - while ( (poff < post_data_len) || - ( (pp->buffer_pos > 0) && - (max != 0) ) ) + state_changed = 1; + while ((poff < post_data_len) || + ((pp->buffer_pos > 0) && (state_changed != 0))) { - /* first, move as much input data - as possible to our internal buffer */ + /* first, move as much input data + as possible to our internal buffer */ max = pp->buffer_size - pp->buffer_pos; if (max > post_data_len - poff) max = post_data_len - poff; memcpy (&buf[pp->buffer_pos], &post_data[poff], max); poff += max; pp->buffer_pos += max; - if ( (max == 0) && - (poff < post_data_len) ) - { - pp->state = PP_Error; - return MHD_NO; /* out of memory */ - } + if ((max == 0) && (state_changed == 0) && (poff < post_data_len)) + { + pp->state = PP_Error; + return MHD_NO; /* out of memory */ + } + state_changed = 0; /* first state machine for '\r'-'\n' and '--' handling */ switch (pp->skip_rn) - { - case RN_Inactive: - break; - case RN_OptN: - if (buf[0] == '\n') - { - ioff++; - pp->skip_rn = RN_Inactive; - goto AGAIN; - } - case RN_Dash: - if (buf[0] == '-') - { - ioff++; - pp->skip_rn = RN_Dash2; - goto AGAIN; - } - pp->skip_rn = RN_Full; - /* fall-through! */ - case RN_Full: - if (buf[0] == '\r') - { - if ( (pp->buffer_pos > 1) && - (buf[1] == '\n') ) - { - pp->skip_rn = RN_Inactive; - ioff += 2; - } - else - { - pp->skip_rn = RN_OptN; - ioff++; - } - goto AGAIN; - } - if (buf[0] == '\n') - { - ioff++; - pp->skip_rn = RN_Inactive; - goto AGAIN; - } - pp->skip_rn = RN_Inactive; - pp->state = PP_Error; - return MHD_NO; /* no '\r\n' */ - case RN_Dash2: - if (buf[0] == '-') - { - ioff++; - pp->skip_rn = RN_Full; - pp->state = pp->dash_state; - goto AGAIN; - } - pp->state = PP_Error; - break; - } + { + case RN_Inactive: + break; + case RN_OptN: + if (buf[0] == '\n') + { + ioff++; + pp->skip_rn = RN_Inactive; + goto AGAIN; + } + case RN_Dash: + if (buf[0] == '-') + { + ioff++; + pp->skip_rn = RN_Dash2; + goto AGAIN; + } + pp->skip_rn = RN_Full; + /* fall-through! */ + case RN_Full: + if (buf[0] == '\r') + { + if ((pp->buffer_pos > 1) && (buf[1] == '\n')) + { + pp->skip_rn = RN_Inactive; + ioff += 2; + } + else + { + pp->skip_rn = RN_OptN; + ioff++; + } + goto AGAIN; + } + if (buf[0] == '\n') + { + ioff++; + pp->skip_rn = RN_Inactive; + goto AGAIN; + } + pp->skip_rn = RN_Inactive; + pp->state = PP_Error; + return MHD_NO; /* no '\r\n' */ + case RN_Dash2: + if (buf[0] == '-') + { + ioff++; + pp->skip_rn = RN_Full; + pp->state = pp->dash_state; + goto AGAIN; + } + pp->state = PP_Error; + break; + } /* main state engine */ switch (pp->state) - { + { case PP_Error: - return MHD_NO; - case PP_Done: - /* did not expect to receive more data */ - pp->state = PP_Error; - return MHD_NO; - case PP_Init: - if (MHD_NO == find_boundary(pp, - pp->boundary, - pp->blen, - &ioff, - PP_ProcessEntryHeaders, - PP_Done)) - { - if (pp->state == PP_Error) - return MHD_NO; - goto END; - } - break; - case PP_ProcessEntryHeaders: - if (MHD_NO == process_multipart_headers(pp, &ioff, PP_PerformCheckMultipart)) - { - if (pp->state == PP_Error) - return MHD_NO; - else - goto END; - } - max = 1; + return MHD_NO; + case PP_Done: + /* did not expect to receive more data */ + pp->state = PP_Error; + return MHD_NO; + case PP_Init: + if (MHD_NO == find_boundary (pp, + pp->boundary, + pp->blen, + &ioff, + PP_ProcessEntryHeaders, PP_Done)) + { + if (pp->state == PP_Error) + return MHD_NO; + goto END; + } + break; + case PP_ProcessEntryHeaders: + if (MHD_NO == + process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart)) + { + if (pp->state == PP_Error) + return MHD_NO; + else + goto END; + } + state_changed = 1; break; case PP_PerformCheckMultipart: - if ( (pp->content_type != NULL) && - (0 == strncasecmp(pp->content_type, - "multipart/mixed", - strlen("multipart/mixed")) ) ) - { - pp->nested_boundary = strstr(pp->content_type, - "boundary="); - if (pp->nested_boundary == NULL) - { - pp->state = PP_Error; - return MHD_NO; - } - pp->nested_boundary = strdup(&pp->nested_boundary[strlen("boundary=")]); - if (pp->nested_boundary == NULL) - { - /* out of memory */ - pp->state = PP_Error; - return MHD_NO; - } - /* free old content type, we will need that field - for the content type of the nested elements */ - free(pp->content_type); - pp->content_type = NULL; - pp->nlen = strlen(pp->nested_boundary); - pp->state = PP_Nested_Init; - max = 1; - break; - } - pp->state = PP_ProcessValueToBoundary; - pp->value_offset = 0; - max = 1; - break; + if ((pp->content_type != NULL) && + (0 == strncasecmp (pp->content_type, + "multipart/mixed", + strlen ("multipart/mixed")))) + { + pp->nested_boundary = strstr (pp->content_type, "boundary="); + if (pp->nested_boundary == NULL) + { + pp->state = PP_Error; + return MHD_NO; + } + pp->nested_boundary = + strdup (&pp->nested_boundary[strlen ("boundary=")]); + if (pp->nested_boundary == NULL) + { + /* out of memory */ + pp->state = PP_Error; + return MHD_NO; + } + /* free old content type, we will need that field + for the content type of the nested elements */ + free (pp->content_type); + pp->content_type = NULL; + pp->nlen = strlen (pp->nested_boundary); + pp->state = PP_Nested_Init; + state_changed = 1; + break; + } + pp->state = PP_ProcessValueToBoundary; + pp->value_offset = 0; + state_changed = 1; + break; case PP_ProcessValueToBoundary: - if (MHD_NO == process_value_to_boundary(pp, - &ioff, - pp->boundary, - pp->blen, - PP_PerformCleanup, - PP_Done)) - { - if (pp->state == PP_Error) - return MHD_NO; - break; - } - break; - case PP_PerformCleanup: - /* clean up state of one multipart form-data element! */ - pp->have = NE_none; - free_unmarked(pp); - if (pp->nested_boundary != NULL) - { - free (pp->nested_boundary); - pp->nested_boundary = NULL; - } - pp->state = PP_ProcessEntryHeaders; - max = 1; - break; - case PP_Nested_Init: - if (pp->nested_boundary == NULL) - { - pp->state = PP_Error; - return MHD_NO; - } - if (MHD_NO == find_boundary(pp, - pp->nested_boundary, - pp->nlen, - &ioff, - PP_Nested_PerformMarking, - PP_Init /* or PP_Error? */)) - { - if (pp->state == PP_Error) - return MHD_NO; - goto END; - } - break; - case PP_Nested_PerformMarking: - /* remember what headers were given - globally */ - pp->have = NE_none; - if (pp->content_name != NULL) - pp->have |= NE_content_name; - if (pp->content_type != NULL) - pp->have |= NE_content_type; - if (pp->content_filename != NULL) - pp->have |= NE_content_filename; - if (pp->content_transfer_encoding != NULL) - pp->have |= NE_content_transfer_encoding; - pp->state = PP_Nested_ProcessEntryHeaders; - max = 1; - break; - case PP_Nested_ProcessEntryHeaders: - pp->value_offset = 0; - if (MHD_NO == process_multipart_headers(pp, &ioff, PP_Nested_ProcessValueToBoundary)) - { - if (pp->state == PP_Error) - return MHD_NO; - else - goto END; - } - max = 1; + if (MHD_NO == process_value_to_boundary (pp, + &ioff, + pp->boundary, + pp->blen, + PP_PerformCleanup, + PP_Done)) + { + if (pp->state == PP_Error) + return MHD_NO; + break; + } + break; + case PP_PerformCleanup: + /* clean up state of one multipart form-data element! */ + pp->have = NE_none; + free_unmarked (pp); + if (pp->nested_boundary != NULL) + { + free (pp->nested_boundary); + pp->nested_boundary = NULL; + } + pp->state = PP_ProcessEntryHeaders; + state_changed = 1; + break; + case PP_Nested_Init: + if (pp->nested_boundary == NULL) + { + pp->state = PP_Error; + return MHD_NO; + } + if (MHD_NO == find_boundary (pp, + pp->nested_boundary, + pp->nlen, + &ioff, + PP_Nested_PerformMarking, + PP_Init /* or PP_Error? */ )) + { + if (pp->state == PP_Error) + return MHD_NO; + goto END; + } + break; + case PP_Nested_PerformMarking: + /* remember what headers were given + globally */ + pp->have = NE_none; + if (pp->content_name != NULL) + pp->have |= NE_content_name; + if (pp->content_type != NULL) + pp->have |= NE_content_type; + if (pp->content_filename != NULL) + pp->have |= NE_content_filename; + if (pp->content_transfer_encoding != NULL) + pp->have |= NE_content_transfer_encoding; + pp->state = PP_Nested_ProcessEntryHeaders; + state_changed = 1; + break; + case PP_Nested_ProcessEntryHeaders: + pp->value_offset = 0; + if (MHD_NO == + process_multipart_headers (pp, &ioff, + PP_Nested_ProcessValueToBoundary)) + { + if (pp->state == PP_Error) + return MHD_NO; + else + goto END; + } + state_changed = 1; + break; + case PP_Nested_ProcessValueToBoundary: + if (MHD_NO == process_value_to_boundary (pp, + &ioff, + pp->nested_boundary, + pp->nlen, + PP_Nested_PerformCleanup, + PP_Init)) + { + if (pp->state == PP_Error) + return MHD_NO; + break; + } + break; + case PP_Nested_PerformCleanup: + free_unmarked (pp); + pp->state = PP_Nested_ProcessEntryHeaders; + state_changed = 1; break; - case PP_Nested_ProcessValueToBoundary: - if (MHD_NO == process_value_to_boundary(pp, - &ioff, - pp->nested_boundary, - pp->nlen, - PP_Nested_PerformCleanup, - PP_Init)) - { - if (pp->state == PP_Error) - return MHD_NO; - break; - } - break; - case PP_Nested_PerformCleanup: - free_unmarked(pp); - pp->state = PP_Nested_ProcessEntryHeaders; - max = 1; - break; default: - abort (); /* should never happen! */ + abort (); /* should never happen! */ } -AGAIN: - if (ioff > 0) + AGAIN: + if (ioff > 0) { memmove (buf, &buf[ioff], pp->buffer_pos - ioff); pp->buffer_pos -= ioff; ioff = 0; - max = 1; - } + state_changed = 1; + } } END: if (ioff != 0) @@ -979,10 +962,10 @@ END: memmove (buf, &buf[ioff], pp->buffer_pos - ioff); pp->buffer_pos -= ioff; } - if (poff < post_data_len) + if (poff < post_data_len) { pp->state = PP_Error; - return MHD_NO; /* serious error */ + return MHD_NO; /* serious error */ } return MHD_YES; } @@ -1027,9 +1010,9 @@ MHD_destroy_post_processor (struct MHD_PostProcessor *pp) the post-processing may have been interrupted at any stage */ pp->have = NE_none; - free_unmarked(pp); + free_unmarked (pp); if (pp->nested_boundary != NULL) - free(pp->nested_boundary); + free (pp->nested_boundary); free (pp); } diff --git a/src/daemon/postprocessor_test.c b/src/daemon/postprocessor_test.c index a931b300..6641fe1e 100644 --- a/src/daemon/postprocessor_test.c +++ b/src/daemon/postprocessor_test.c @@ -40,10 +40,10 @@ * Each series of checks should be terminated by * five NULL-entries. */ -const char * want[] = { +const char *want[] = { #define URL_DATA "abc=def&x=5" #define URL_START 0 - "abc", NULL, NULL, NULL, "def", + "abc", NULL, NULL, NULL, "def", "x", NULL, NULL, NULL, "5", #define URL_END (URL_START + 10) NULL, NULL, NULL, NULL, NULL, @@ -63,81 +63,80 @@ const char * want[] = { }; static int -mismatch(const char * a, const char * b) { - if (a == b) +mismatch (const char *a, const char *b) +{ + if (a == b) return 0; - if ( (a == NULL) || - (b == NULL) ) + if ((a == NULL) || (b == NULL)) return 1; - return 0 != strcmp(a, b); + return 0 != strcmp (a, b); } static int -value_checker(void * cls, - enum MHD_ValueKind kind, - const char * key, - const char * filename, - const char * content_type, - const char * transfer_encoding, - const char * data, - size_t off, - size_t size) { - int * want_off = cls; +value_checker (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, size_t off, size_t size) +{ + int *want_off = cls; int idx = *want_off; #if 0 - fprintf(stderr, - "VC: `%s' `%s' `%s' `%s' `%.*s'\n", - key, filename, content_type, transfer_encoding, size, data); + fprintf (stderr, + "VC: `%s' `%s' `%s' `%s' `%.*s'\n", + key, filename, content_type, transfer_encoding, size, data); #endif if (size == 0) return MHD_YES; - if ( (idx < 0) || - (want[idx] == NULL) || - (0 != strcmp(key, want[idx])) || - (mismatch(filename, want[idx+1])) || - (mismatch(content_type, want[idx+2])) || - (mismatch(transfer_encoding, want[idx+3])) || - (0 != memcmp(data, &want[idx+4][off], size)) ) + if ((idx < 0) || + (want[idx] == NULL) || + (0 != strcmp (key, want[idx])) || + (mismatch (filename, want[idx + 1])) || + (mismatch (content_type, want[idx + 2])) || + (mismatch (transfer_encoding, want[idx + 3])) || + (0 != memcmp (data, &want[idx + 4][off], size))) { *want_off = -1; return MHD_NO; } - if (off + size == strlen(want[idx+4])) + if (off + size == strlen (want[idx + 4])) *want_off = idx + 5; return MHD_YES; - + } static int -test_urlencoding() { +test_urlencoding () +{ struct MHD_Connection connection; struct MHD_HTTP_Header header; - struct MHD_PostProcessor * pp; + struct MHD_PostProcessor *pp; unsigned int want_off = URL_START; int i; int delta; size_t size; - memset(&connection, 0, sizeof(struct MHD_Connection)); - memset(&header, 0, sizeof(struct MHD_HTTP_Header)); + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); connection.headers_received = &header; header.header = MHD_HTTP_HEADER_CONTENT_TYPE; header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; header.kind = MHD_HEADER_KIND; - pp = MHD_create_post_processor(&connection, - 1024, - &value_checker, - &want_off); + pp = MHD_create_post_processor (&connection, + 1024, &value_checker, &want_off); i = 0; - size = strlen(URL_DATA); - while (i < size) { - delta = 1 + random() % (size - i); - MHD_post_process(pp, &URL_DATA[i], delta); - i += delta; - } - MHD_destroy_post_processor(pp); + size = strlen (URL_DATA); + while (i < size) + { + delta = 1 + random () % (size - i); + MHD_post_process (pp, &URL_DATA[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); if (want_off != URL_END) return 1; return 0; @@ -145,33 +144,34 @@ test_urlencoding() { static int -test_multipart() { +test_multipart () +{ struct MHD_Connection connection; struct MHD_HTTP_Header header; - struct MHD_PostProcessor * pp; + struct MHD_PostProcessor *pp; unsigned int want_off = FORM_START; int i; int delta; size_t size; - memset(&connection, 0, sizeof(struct MHD_Connection)); - memset(&header, 0, sizeof(struct MHD_HTTP_Header)); + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); connection.headers_received = &header; header.header = MHD_HTTP_HEADER_CONTENT_TYPE; - header.value = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; + header.value = + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; header.kind = MHD_HEADER_KIND; - pp = MHD_create_post_processor(&connection, - 1024, - &value_checker, - &want_off); + pp = MHD_create_post_processor (&connection, + 1024, &value_checker, &want_off); i = 0; - size = strlen(FORM_DATA); - while (i < size) { - delta = 1 + random() % (size - i); - MHD_post_process(pp, &FORM_DATA[i], delta); - i += delta; - } - MHD_destroy_post_processor(pp); + size = strlen (FORM_DATA); + while (i < size) + { + delta = 1 + random () % (size - i); + MHD_post_process (pp, &FORM_DATA[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); if (want_off != FORM_END) return 2; return 0; @@ -179,33 +179,34 @@ test_multipart() { static int -test_nested_multipart() { +test_nested_multipart () +{ struct MHD_Connection connection; struct MHD_HTTP_Header header; - struct MHD_PostProcessor * pp; + struct MHD_PostProcessor *pp; unsigned int want_off = FORM_NESTED_START; int i; int delta; size_t size; - memset(&connection, 0, sizeof(struct MHD_Connection)); - memset(&header, 0, sizeof(struct MHD_HTTP_Header)); + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); connection.headers_received = &header; header.header = MHD_HTTP_HEADER_CONTENT_TYPE; - header.value = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; + header.value = + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; header.kind = MHD_HEADER_KIND; - pp = MHD_create_post_processor(&connection, - 1024, - &value_checker, - &want_off); + pp = MHD_create_post_processor (&connection, + 1024, &value_checker, &want_off); i = 0; - size = strlen(FORM_NESTED_DATA); - while (i < size) { - delta = 1 + random() % (size - i); - MHD_post_process(pp, &FORM_NESTED_DATA[i], delta); - i += delta; - } - MHD_destroy_post_processor(pp); + size = strlen (FORM_NESTED_DATA); + while (i < size) + { + delta = 1 + random () % (size - i); + MHD_post_process (pp, &FORM_NESTED_DATA[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); if (want_off != FORM_NESTED_END) return 4; return 0; @@ -216,9 +217,9 @@ main (int argc, char *const *argv) { unsigned int errorCount = 0; - errorCount += test_urlencoding(); - errorCount += test_multipart(); - errorCount += test_nested_multipart(); + errorCount += test_urlencoding (); + errorCount += test_multipart (); + errorCount += test_nested_multipart (); if (errorCount != 0) fprintf (stderr, "Error (code: %u)\n", errorCount); return errorCount != 0; /* 0 == pass */ diff --git a/src/daemon/response.c b/src/daemon/response.c index ea1fe9c0..3089e6c1 100644 --- a/src/daemon/response.c +++ b/src/daemon/response.c @@ -238,10 +238,10 @@ MHD_create_response_from_data (size_t size, { tmp = malloc (size); if (tmp == NULL) - { - free(retVal); - return NULL; - } + { + free (retVal); + return NULL; + } memcpy (tmp, data, size); must_free = 1; data = tmp; -- cgit v1.2.3