libmicrohttpd

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

commit 72f05a8364e251076a458b897b4efcd339be0e23
parent dd749c2274ef01d0476f3471d28374dbf7c4b36b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon,  5 Oct 2015 10:06:13 +0000

deduplicate arg parsing logic between connection.c and digestauth.c (now in internal.c)

Diffstat:
MChangeLog | 5+++++
Msrc/include/microhttpd.h | 2+-
Msrc/microhttpd/connection.c | 140+++++++++++++++++++------------------------------------------------------------
Msrc/microhttpd/daemon.c | 8++++----
Msrc/microhttpd/digestauth.c | 118+++++++++++--------------------------------------------------------------------
Msrc/microhttpd/internal.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/internal.h | 40++++++++++++++++++++++++++++++++++++++++
7 files changed, 212 insertions(+), 213 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,8 @@ +Mon Oct 5 11:53:52 CEST 2015 + Deduplicate code between digestauth and connection + parsing logic for URI arguments, shared code moved + to new MHD_parse_arguments_ function in internal.c. -CG + Thu Oct 1 21:22:05 CEST 2015 Releasing libmicrohttpd 0.9.44. -CG diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -130,7 +130,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00094400 +#define MHD_VERSION 0x00094401 /** * MHD-internal return code for "YES". diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -1176,17 +1176,22 @@ get_next_header_line (struct MHD_Connection *connection) */ static int connection_add_header (struct MHD_Connection *connection, - char *key, char *value, enum MHD_ValueKind kind) + const char *key, + const char *value, + enum MHD_ValueKind kind) { - if (MHD_NO == MHD_set_connection_value (connection, - kind, - key, value)) + if (MHD_NO == + MHD_set_connection_value (connection, + kind, + key, + value)) { #if HAVE_MESSAGES MHD_DLOG (connection->daemon, "Not enough memory to allocate header record!\n"); #endif - transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + transmit_error_response (connection, + MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, REQUEST_TOO_BIG); return MHD_NO; } @@ -1195,98 +1200,9 @@ connection_add_header (struct MHD_Connection *connection, /** - * Parse and unescape the arguments given by the client as part - * of the HTTP request URI. - * - * @param kind header kind to use for adding to the connection - * @param connection connection to add headers to - * @param args argument URI string (after "?" in URI) - * @return #MHD_NO on failure (out of memory), #MHD_YES for success - */ -static int -parse_arguments (enum MHD_ValueKind kind, - struct MHD_Connection *connection, - char *args) -{ - char *equals; - char *amper; - - while (NULL != args) - { - equals = strchr (args, '='); - amper = strchr (args, '&'); - if (NULL == amper) - { - /* last argument */ - if (NULL == equals) - { - /* got 'foo', add key 'foo' with NULL for value */ - MHD_unescape_plus (args); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - args); - return connection_add_header (connection, - args, - NULL, - kind); - } - /* got 'foo=bar' */ - equals[0] = '\0'; - equals++; - MHD_unescape_plus (args); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - args); - MHD_unescape_plus (equals); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - equals); - return connection_add_header (connection, args, equals, kind); - } - /* amper is non-NULL here */ - amper[0] = '\0'; - amper++; - if ( (NULL == equals) || - (equals >= amper) ) - { - /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */ - MHD_unescape_plus (args); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - args); - if (MHD_NO == - connection_add_header (connection, - args, - NULL, - kind)) - return MHD_NO; - /* continue with 'bar' */ - args = amper; - continue; - } - /* equals and amper are non-NULL here, and equals < amper, - so we got regular 'foo=value&bar...'-kind of argument */ - equals[0] = '\0'; - equals++; - MHD_unescape_plus (args); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - args); - MHD_unescape_plus (equals); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - equals); - if (MHD_NO == connection_add_header (connection, args, equals, kind)) - return MHD_NO; - args = amper; - } - return MHD_YES; -} - - -/** * Parse the cookie header (see RFC 2109). * + * @param connection connection to parse header of * @return #MHD_YES for success, #MHD_NO for failure (malformed, out of memory) */ static int @@ -1372,8 +1288,11 @@ parse_cookie_header (struct MHD_Connection *connection) equals[strlen (equals) - 1] = '\0'; equals++; } - if (MHD_NO == connection_add_header (connection, - pos, equals, MHD_COOKIE_KIND)) + if (MHD_NO == + connection_add_header (connection, + pos, + equals, + MHD_COOKIE_KIND)) return MHD_NO; pos = semicolon; } @@ -1392,9 +1311,11 @@ static int parse_initial_message_line (struct MHD_Connection *connection, char *line) { + struct MHD_Daemon *daemon = connection->daemon; char *uri; char *http_version; char *args; + unsigned int unused_num_headers; if (NULL == (uri = strchr (line, ' '))) return MHD_NO; /* serious error */ @@ -1409,21 +1330,26 @@ parse_initial_message_line (struct MHD_Connection *connection, http_version[0] = '\0'; http_version++; } - if (NULL != connection->daemon->uri_log_callback) + if (NULL != daemon->uri_log_callback) connection->client_context - = connection->daemon->uri_log_callback (connection->daemon->uri_log_callback_cls, - uri, - connection); + = daemon->uri_log_callback (daemon->uri_log_callback_cls, + uri, + connection); args = strchr (uri, '?'); if (NULL != args) { args[0] = '\0'; args++; - parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args); + /* note that this call clobbers 'args' */ + MHD_parse_arguments_ (connection, + MHD_GET_ARGUMENT_KIND, + args, + &connection_add_header, + &unused_num_headers); } - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - uri); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + uri); connection->url = uri; if (NULL == http_version) connection->version = ""; @@ -1858,7 +1784,9 @@ process_broken_line (struct MHD_Connection *connection, } EXTRA_CHECK ((NULL != last) && (NULL != connection->colon)); if ((MHD_NO == connection_add_header (connection, - last, connection->colon, kind))) + last, + connection->colon, + kind))) { transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, REQUEST_TOO_BIG); diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -1130,12 +1130,12 @@ send_param_adapter (struct MHD_Connection *connection, left = connection->response->total_size - connection->response_write_position; #ifndef HAVE_SENDFILE64 offset = (off_t) offsetu64; - if ( (offsetu64 <= (uint64_t)OFF_T_MAX) && - 0 < (ret = sendfile (connection->socket_fd, fd, &offset, left))) + if ( (offsetu64 <= (uint64_t) OFF_T_MAX) && + (0 < (ret = sendfile (connection->socket_fd, fd, &offset, left))) ) #else /* HAVE_SENDFILE64 */ offset = (off64_t) offsetu64; - if ( (offsetu64 <= (uint64_t)OFF64_T_MAX) && - 0 < (ret = sendfile64 (connection->socket_fd, fd, &offset, left))) + if ( (offsetu64 <= (uint64_t) OFF64_T_MAX) && + (0 < (ret = sendfile64 (connection->socket_fd, fd, &offset, left))) ) #endif /* HAVE_SENDFILE64 */ { #if EPOLL_SUPPORT diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c @@ -443,19 +443,21 @@ calculate_nonce (uint32_t nonce_time, * @param connection the connection * @param key the key * @param value the value, can be NULL + * @param kind type of the header * @return #MHD_YES if the key-value pair is in the headers, * #MHD_NO if not */ static int test_header (struct MHD_Connection *connection, const char *key, - const char *value) + const char *value, + enum MHD_ValueKind kind) { struct MHD_HTTP_Header *pos; for (pos = connection->headers_received; NULL != pos; pos = pos->next) { - if (MHD_GET_ARGUMENT_KIND != pos->kind) + if (kind != pos->kind) continue; if (0 != strcmp (key, pos->header)) continue; @@ -488,114 +490,26 @@ check_argument_match (struct MHD_Connection *connection, { struct MHD_HTTP_Header *pos; char *argb; - char *argp; - char *equals; - char *amper; unsigned int num_headers; + int ret; argb = strdup (args); if (NULL == argb) - { + { #if HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Failed to allocate memory for copy of URI arguments\n"); + MHD_DLOG (connection->daemon, + "Failed to allocate memory for copy of URI arguments\n"); #endif /* HAVE_MESSAGES */ - return MHD_NO; - } - num_headers = 0; - argp = argb; - while ( (NULL != argp) && - ('\0' != argp[0]) ) - { - equals = strchr (argp, '='); - amper = strchr (argp, '&'); - if (NULL == amper) - { - /* last argument */ - if (NULL == equals) - { - /* last argument, without '=' */ - MHD_unescape_plus (argp); - if (MHD_YES != test_header (connection, - argp, - NULL)) - { - free (argb); - return MHD_NO; - } - num_headers++; - break; - } - /* got 'foo=bar' */ - equals[0] = '\0'; - equals++; - MHD_unescape_plus (argp); - /* add with 'value' NULL */ - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - argp); - MHD_unescape_plus (equals); - /* add with 'value' NULL */ - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - equals); - if (MHD_YES != test_header (connection, - argp, - equals)) - { - free (argb); - return MHD_NO; - } - num_headers++; - break; - } - /* amper is non-NULL here */ - amper[0] = '\0'; - amper++; - if ( (NULL == equals) || - (equals >= amper) ) - { - /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */ - MHD_unescape_plus (argp); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - argp); - if (MHD_YES != - test_header (connection, - argp, - NULL)) - { - free (argb); - return MHD_NO; - } - /* continue with 'bar' */ - num_headers++; - args = amper; - continue; - } - equals[0] = '\0'; - equals++; - MHD_unescape_plus (argp); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - argp); - MHD_unescape_plus (equals); - connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, - connection, - equals); - if (MHD_YES != - test_header (connection, - argp, - equals)) - { - free (argb); - return MHD_NO; - } - num_headers++; - argp = amper; + return MHD_NO; } + ret = MHD_parse_arguments_ (connection, + MHD_GET_ARGUMENT_KIND, + argb, + &test_header, + &num_headers); free (argb); - + if (MHD_YES != ret) + return MHD_NO; /* also check that the number of headers matches */ for (pos = connection->headers_received; NULL != pos; pos = pos->next) { diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c @@ -171,4 +171,116 @@ MHD_http_unescape (char *val) } +/** + * Parse and unescape the arguments given by the client + * as part of the HTTP request URI. + * + * @param kind header kind to pass to @a cb + * @param connection connection to add headers to + * @param[in|out] args argument URI string (after "?" in URI), + * clobbered in the process! + * @param cb function to call on each key-value pair found + * @param[out] num_headers set to the number of headers found + * @return #MHD_NO on failure (@a cb returned #MHD_NO), + * #MHD_YES for success (parsing succeeded, @a cb always + * returned #MHD_YES) + */ +int +MHD_parse_arguments_ (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + char *args, + MHD_ArgumentIterator_ cb, + unsigned int *num_headers) +{ + struct MHD_Daemon *daemon = connection->daemon; + char *equals; + char *amper; + + *num_headers = 0; + while ( (NULL != args) && + ('\0' != args[0]) ) + { + equals = strchr (args, '='); + amper = strchr (args, '&'); + if (NULL == amper) + { + /* last argument */ + if (NULL == equals) + { + /* last argument, without '=' */ + MHD_unescape_plus (args); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + args); + if (MHD_YES != cb (connection, + args, + NULL, + kind)) + return MHD_NO; + (*num_headers)++; + break; + } + /* got 'foo=bar' */ + equals[0] = '\0'; + equals++; + MHD_unescape_plus (args); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + args); + MHD_unescape_plus (equals); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + equals); + if (MHD_YES != cb (connection, + args, + equals, + kind)) + return MHD_NO; + (*num_headers)++; + break; + } + /* amper is non-NULL here */ + amper[0] = '\0'; + amper++; + if ( (NULL == equals) || + (equals >= amper) ) + { + /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */ + MHD_unescape_plus (args); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + args); + if (MHD_YES != cb (connection, + args, + NULL, + kind)) + return MHD_NO; + /* continue with 'bar' */ + (*num_headers)++; + args = amper; + continue; + } + /* equals and amper are non-NULL here, and equals < amper, + so we got regular 'foo=value&bar...'-kind of argument */ + equals[0] = '\0'; + equals++; + MHD_unescape_plus (args); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + args); + MHD_unescape_plus (equals); + daemon->unescape_callback (daemon->unescape_callback_cls, + connection, + equals); + if (MHD_YES != cb (connection, + args, + equals, + kind)) + return MHD_NO; + (*num_headers)++; + args = amper; + } + return MHD_YES; +} + /* end of internal.c */ diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h @@ -1447,4 +1447,44 @@ void MHD_unescape_plus (char *arg); +/** + * Callback invoked when iterating over @a key / @a value + * argument pairs during parsing. + * + * @param connection context of the iteration + * @param key 0-terminated key string, never NULL + * @param value 0-terminated value string, may be NULL + * @param kind origin of the key-value pair + * @return #MHD_YES on success (continue to iterate) + * #MHD_NO to signal failure (and abort iteration) + */ +typedef int +(*MHD_ArgumentIterator_)(struct MHD_Connection *connection, + const char *key, + const char *value, + enum MHD_ValueKind kind); + + +/** + * Parse and unescape the arguments given by the client + * as part of the HTTP request URI. + * + * @param kind header kind to pass to @a cb + * @param connection connection to add headers to + * @param[in|out] args argument URI string (after "?" in URI), + * clobbered in the process! + * @param cb function to call on each key-value pair found + * @param[out] num_headers set to the number of headers found + * @return #MHD_NO on failure (@a cb returned #MHD_NO), + * #MHD_YES for success (parsing succeeded, @a cb always + * returned #MHD_YES) + */ +int +MHD_parse_arguments_ (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + char *args, + MHD_ArgumentIterator_ cb, + unsigned int *num_headers); + + #endif