From 4f3066577684a4daa70da52366276a18c6824bf1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 5 Sep 2008 07:07:58 +0000 Subject: improving chunked connection handling --- AUTHORS | 1 + ChangeLog | 6 ++++ src/daemon/Makefile.am | 2 +- src/daemon/connection.c | 87 ++++++++++++++++++++++++++++--------------------- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/AUTHORS b/AUTHORS index a0e8a704..4806d034 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ John Popplewell Nils Durner Heikki Lindholm Alex Sadovsky +Greg Schohn Documentation contributions also came from: Marco Maggi diff --git a/ChangeLog b/ChangeLog index 68cb14e5..51d8fb68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Thu Sep 4 23:37:18 MDT 2008 + Fixed some boundary issues with processing + chunked requests; removed memmove from a + number of spots, in favor of using an index into + the current buffer instead. -GS + Sun Aug 24 13:05:41 MDT 2008 Now handling clients returning 0 from response callback as specified in the documentation (abort if internal diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index d910b65c..781220c8 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -15,7 +15,7 @@ AM_CPPFLAGS = \ -I$(GCRYPT_CPPFLAGS) if HAVE_GNU_LD - retaincommand=-Wl,--retain-symbols-file -Wl,$(srcdir)/SYMBOLS +# retaincommand=-Wl,--retain-symbols-file -Wl,$(srcdir)/SYMBOLS endif EXTRA_DIST = SYMBOLS diff --git a/src/daemon/connection.c b/src/daemon/connection.c index 3fd03a41..e4c5df33 100644 --- a/src/daemon/connection.c +++ b/src/daemon/connection.c @@ -1065,27 +1065,30 @@ call_connection_handler (struct MHD_Connection *connection) int instant_retry; unsigned int i; int malformed; + char * buffer_head; if (connection->response != NULL) return; /* already queued a response */ + + buffer_head = connection->read_buffer; + available = connection->read_buffer_offset; do { instant_retry = MHD_NO; - available = connection->read_buffer_offset; if ((connection->have_chunked_upload == MHD_YES) && (connection->remaining_upload_size == -1)) { - if ((connection->current_chunk_offset == - connection->current_chunk_size) - && (connection->current_chunk_offset != 0) && (available >= 2)) + if ((connection->current_chunk_offset == connection->current_chunk_size) && + (connection->current_chunk_offset != 0) && + (available >= 2)) { /* skip new line at the *end* of a chunk */ i = 0; - if ((connection->read_buffer[i] == '\r') || - (connection->read_buffer[i] == '\n')) + if ((buffer_head[i] == '\r') || + (buffer_head[i] == '\n')) i++; /* skip 1st part of line feed */ - if ((connection->read_buffer[i] == '\r') || - (connection->read_buffer[i] == '\n')) + if ((buffer_head[i] == '\r') || + (buffer_head[i] == '\n')) i++; /* skip 2nd part of line feed */ if (i == 0) { @@ -1097,10 +1100,8 @@ call_connection_handler (struct MHD_Connection *connection) connection_close_error (connection); return; } - connection->read_buffer_offset -= i; available -= i; - memmove (connection->read_buffer, - &connection->read_buffer[i], available); + buffer_head += i; connection->current_chunk_offset = 0; connection->current_chunk_size = 0; } @@ -1115,8 +1116,7 @@ call_connection_handler (struct MHD_Connection *connection) connection->current_chunk_offset; if (processed > available) processed = available; - available -= processed; - if (available > 0) + if (available > processed) instant_retry = MHD_YES; } else @@ -1125,25 +1125,31 @@ call_connection_handler (struct MHD_Connection *connection) i = 0; while (i < available) { - if ((connection->read_buffer[i] == '\r') || - (connection->read_buffer[i] == '\n')) + if ((buffer_head[i] == '\r') || + (buffer_head[i] == '\n')) break; i++; if (i >= 6) break; } - if (i >= available) - return; /* need more data... */ + /* take '\n' into account; if '\n' + is the unavailable character, we + will need to wait until we have it + before going further */ + if ( (i+1 >= available) && + ! ( (i == 1) && + (available == 2) && + (buffer_head[0] == '0') ) ) + break; /* need more data... */ malformed = (i >= 6); if (!malformed) { - connection->read_buffer[i] = '\0'; - malformed = (1 != sscanf (connection->read_buffer, - "%X", - &connection->current_chunk_size)) - && (1 != - sscanf (connection->read_buffer, "%x", - &connection->current_chunk_size)); + buffer_head[i] = '\0'; + malformed = + (1 != sscanf (buffer_head, "%X", + &connection->current_chunk_size)) && + (1 != sscanf (buffer_head, "%x", + &connection->current_chunk_size)); } if (malformed) { @@ -1156,18 +1162,21 @@ call_connection_handler (struct MHD_Connection *connection) return; } i++; - if ((connection->read_buffer[i] == '\r') || - (connection->read_buffer[i] == '\n')) + if ((iread_buffer, - &connection->read_buffer[i], available - i); - connection->read_buffer_offset -= i; + + buffer_head += i; + available -= i; connection->current_chunk_offset = 0; - instant_retry = MHD_YES; + + if (available > 0) + instant_retry = MHD_YES; if (connection->current_chunk_size == 0) { connection->remaining_upload_size = 0; - return; + break; } continue; } @@ -1176,7 +1185,6 @@ call_connection_handler (struct MHD_Connection *connection) { /* no chunked encoding, give all to the client */ processed = available; - available = 0; } used = processed; if (MHD_NO == @@ -1185,7 +1193,7 @@ call_connection_handler (struct MHD_Connection *connection) connection, connection->url, connection->method, connection->version, - connection->read_buffer, + buffer_head, &processed, &connection->client_context)) { @@ -1203,16 +1211,19 @@ call_connection_handler (struct MHD_Connection *connection) instant_retry = MHD_NO; /* client did not process everything */ used -= processed; if (connection->have_chunked_upload == MHD_YES) - connection->current_chunk_offset += used; + connection->current_chunk_offset += used; /* dh left "processed" bytes in buffer for next time... */ - if (used > 0) - memmove (connection->read_buffer, - &connection->read_buffer[used], processed + available); + buffer_head += used; + available -= used; if (connection->remaining_upload_size != -1) connection->remaining_upload_size -= used; - connection->read_buffer_offset = processed + available; } while (instant_retry == MHD_YES); + if (available > 0) + memmove(connection->read_buffer, + buffer_head, + available); + connection->read_buffer_offset = available; } /** -- cgit v1.2.3