libmicrohttpd

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

commit 101e71a8cf90c3b12c66f5a40436509ea1bc4184
parent b2a05d373cfec12f26bd71de7a1d63741b8b5e15
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Thu,  4 Feb 2016 11:44:04 +0000

Added some buffer overrun protection, fixed handling of misformed URI with spaces.

Diffstat:
MChangeLog | 4++++
Msrc/microhttpd/connection.c | 68+++++++++++++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,7 @@ +Thu Feb 4 11:38:11 CET 2016 + Added some buffer overrun protection. + Fixed handling of misformed URI with spaces. -EG + Wed Feb 3 15:41:57 CET 2016 Make signal-pipe non-blocking and drain it. -CG diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -1328,10 +1328,13 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) * return NULL. Otherwise return a pointer to the line. * * @param connection connection we're processing + * @param[out] line_len pointer to variable that receive + * length of line or NULL * @return NULL if no full line is available */ static char * -get_next_header_line (struct MHD_Connection *connection) +get_next_header_line (struct MHD_Connection *connection, + size_t *line_len) { char *rbuf; size_t pos; @@ -1357,8 +1360,13 @@ get_next_header_line (struct MHD_Connection *connection) : MHD_HTTP_REQUEST_URI_TOO_LONG, REQUEST_TOO_BIG); } + if (line_len) + *line_len = 0; return NULL; } + + if (line_len) + *line_len = pos; /* found, check if we have proper LFCR */ if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1])) rbuf[pos++] = '\0'; /* skip both r and n */ @@ -1512,11 +1520,13 @@ parse_cookie_header (struct MHD_Connection *connection) * * @param connection the connection (updated) * @param line the first line + * @param line_len length of the first line * @return #MHD_YES if the line is ok, #MHD_NO if it is malformed */ static int parse_initial_message_line (struct MHD_Connection *connection, - char *line) + char *line, + size_t line_len) { struct MHD_Daemon *daemon = connection->daemon; char *uri; @@ -1524,25 +1534,48 @@ parse_initial_message_line (struct MHD_Connection *connection, char *args; unsigned int unused_num_headers; - if (NULL == (uri = strchr (line, ' '))) + if (NULL == (uri = memchr (line, ' ', line_len))) return MHD_NO; /* serious error */ uri[0] = '\0'; connection->method = line; uri++; - while (' ' == uri[0]) + /* Skip any spaces. Not required by standard but allow + to be more tolerant. */ + while (' ' == uri[0] && (size_t)(uri - line) < line_len) uri++; - http_version = strchr (uri, ' '); - if (NULL != http_version) + if (uri - line == line_len) { - http_version[0] = '\0'; - http_version++; + uri = ""; + connection->version = ""; + args = NULL; + } + else + { + /* Search from back to accept misformed URI with space */ + http_version = line + line_len - 1; + /* Skip any trailing spaces */ + while (' ' == http_version[0] && http_version > uri) + http_version--; + /* Find first space in reverse direction */ + while (' ' != http_version[0] && http_version > uri) + http_version--; + if (http_version > uri) + { + http_version[0] = '\0'; + connection->version = http_version + 1; + args = memchr(uri, '?', http_version - uri); + } + else + { + connection->version = ""; + args = memchr(uri, '?', line_len - (uri - line)); + } } if (NULL != daemon->uri_log_callback) connection->client_context = daemon->uri_log_callback (daemon->uri_log_callback_cls, uri, connection); - args = strchr (uri, '?'); if (NULL != args) { args[0] = '\0'; @@ -1558,10 +1591,6 @@ parse_initial_message_line (struct MHD_Connection *connection, connection, uri); connection->url = uri; - if (NULL == http_version) - connection->version = ""; - else - connection->version = http_version; return MHD_YES; } @@ -2416,6 +2445,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) unsigned int timeout; const char *end; char *line; + size_t line_len; int client_close; connection->in_idle = MHD_YES; @@ -2430,7 +2460,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) switch (connection->state) { case MHD_CONNECTION_INIT: - line = get_next_header_line (connection); + line = get_next_header_line (connection, &line_len); /* Check for empty string, as we might want to tolerate 'spurious' empty lines; also NULL means we didn't get a full line yet. */ @@ -2447,13 +2477,13 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } break; } - if (MHD_NO == parse_initial_message_line (connection, line)) + if (MHD_NO == parse_initial_message_line (connection, line, line_len)) CONNECTION_CLOSE_ERROR (connection, NULL); else connection->state = MHD_CONNECTION_URL_RECEIVED; continue; case MHD_CONNECTION_URL_RECEIVED: - line = get_next_header_line (connection); + line = get_next_header_line (connection, NULL); if (NULL == line) { if (MHD_CONNECTION_URL_RECEIVED != connection->state) @@ -2481,7 +2511,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; continue; case MHD_CONNECTION_HEADER_PART_RECEIVED: - line = get_next_header_line (connection); + line = get_next_header_line (connection, NULL); if (NULL == line) { if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) @@ -2571,7 +2601,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } break; case MHD_CONNECTION_BODY_RECEIVED: - line = get_next_header_line (connection); + line = get_next_header_line (connection, NULL); if (NULL == line) { if (connection->state != MHD_CONNECTION_BODY_RECEIVED) @@ -2599,7 +2629,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; continue; case MHD_CONNECTION_FOOTER_PART_RECEIVED: - line = get_next_header_line (connection); + line = get_next_header_line (connection, NULL); if (NULL == line) { if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)