improving chunked connection handling

This commit is contained in:
Christian Grothoff
2008-09-05 07:07:58 +00:00
parent cd1ab8768d
commit 4f30665776
4 changed files with 57 additions and 39 deletions
+1
View File
@@ -10,6 +10,7 @@ John Popplewell <john@johnnypops.demon.co.uk>
Nils Durner <durner@gnunet.org>
Heikki Lindholm <holindho@cs.helsinki.fi>
Alex Sadovsky <alexeysad@gmail.com>
Greg Schohn <greg.schohn@gmail.com>
Documentation contributions also came from:
Marco Maggi <marco.maggi-ipsu@poste.it>
+6
View File
@@ -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
+1 -1
View File
@@ -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
+49 -38
View File
@@ -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 ((i<available) &&
( (buffer_head[i] == '\r') ||
(buffer_head[i] == '\n')) )
i++; /* skip 2nd part of line feed */
memmove (connection->read_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;
}
/**