[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r5926 - in libmicrohttpd: . src/daemon
From: |
gnunet |
Subject: |
[GNUnet-SVN] r5926 - in libmicrohttpd: . src/daemon |
Date: |
Sun, 16 Dec 2007 03:27:30 -0700 (MST) |
Author: grothoff
Date: 2007-12-16 03:27:29 -0700 (Sun, 16 Dec 2007)
New Revision: 5926
Added:
libmicrohttpd/src/daemon/daemontest_put_chunked.c
Modified:
libmicrohttpd/ChangeLog
libmicrohttpd/README
libmicrohttpd/src/daemon/Makefile.am
libmicrohttpd/src/daemon/connection.c
libmicrohttpd/src/daemon/daemon.c
libmicrohttpd/src/daemon/internal.h
Log:
fixing Mantis 1260
Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog 2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/ChangeLog 2007-12-16 10:27:29 UTC (rev 5926)
@@ -1,3 +1,11 @@
+Sun Dec 16 03:24:13 MST 2007
+ Implemented handling of chunked (HTTP 1.1) uploads.
+ Note that the upload callback must be able to
+ process chunks in the size uploaded by the client,
+ MHD will not "join" small chunks into a big
+ contiguous block of memory (even if buffer space
+ would be available). - CG
+
Wed Dec 5 21:39:35 MST 2007
Fixed race in multi-threaded server mode.
Fixed handling of POST data when receiving a
Modified: libmicrohttpd/README
===================================================================
--- libmicrohttpd/README 2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/README 2007-12-16 10:27:29 UTC (rev 5926)
@@ -53,7 +53,7 @@
For http/1.1-compliance:
========================
connection.c:
-- support chunked requests from clients (#1260, ARCH, TEST)
+- support sending of chunked responses (#1260, TEST)
For POST:
=========
Modified: libmicrohttpd/src/daemon/Makefile.am
===================================================================
--- libmicrohttpd/src/daemon/Makefile.am 2007-12-16 05:47:40 UTC (rev
5925)
+++ libmicrohttpd/src/daemon/Makefile.am 2007-12-16 10:27:29 UTC (rev
5926)
@@ -48,6 +48,7 @@
daemontest_postform \
daemontest_post_loop \
daemontest_put \
+ daemontest_put_chunked \
daemontest_large_put \
daemontest_get11 \
daemontest_post11 \
@@ -94,6 +95,12 @@
$(top_builddir)/src/daemon/libmicrohttpd.la \
@LIBCURL@
+daemontest_put_chunked_SOURCES = \
+ daemontest_put_chunked.c
+daemontest_put_chunked_LDADD = \
+ $(top_builddir)/src/daemon/libmicrohttpd.la \
+ @LIBCURL@
+
daemontest_get11_SOURCES = \
daemontest_get.c
daemontest_get11_LDADD = \
Modified: libmicrohttpd/src/daemon/connection.c
===================================================================
--- libmicrohttpd/src/daemon/connection.c 2007-12-16 05:47:40 UTC (rev
5925)
+++ libmicrohttpd/src/daemon/connection.c 2007-12-16 10:27:29 UTC (rev
5926)
@@ -152,7 +152,7 @@
if ((connection == NULL) ||
(response == NULL) ||
(connection->response != NULL) ||
- (connection->bodyReceived == MHD_NO) || (connection->headersReceived ==
MHD_NO))
+ (connection->have_received_body == MHD_NO) ||
(connection->have_received_headers == MHD_NO))
return MHD_NO;
MHD_increment_response_rc (response);
connection->response = response;
@@ -162,7 +162,7 @@
{
/* if this is a "HEAD" request, pretend that we
have already sent the full message body */
- connection->messagePos = response->total_size;
+ connection->response_write_position = response->total_size;
}
return MHD_YES;
}
@@ -179,12 +179,12 @@
return ((connection->version != NULL) &&
(0 == strcasecmp (connection->version,
MHD_HTTP_VERSION_1_1)) &&
- (connection->headersReceived == MHD_YES) &&
+ (connection->have_received_headers == MHD_YES) &&
(NULL != (expect = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_EXPECT)))
&& (0 == strcasecmp (expect, "100-continue"))
- && (connection->continuePos < strlen (HTTP_100_CONTINUE)));
+ && (connection->continue_message_write_offset < strlen
(HTTP_100_CONTINUE)));
}
/**
@@ -221,10 +221,10 @@
response = connection->response;
ret = response->crc (response->crc_cls,
- connection->messagePos,
+ connection->response_write_position,
response->data,
MIN (response->data_buffer_size,
- response->total_size - connection->messagePos));
+ response->total_size -
connection->response_write_position));
if (ret == -1)
{
/* end of message, signal other side by closing! */
@@ -233,11 +233,11 @@
MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
#endif
#endif
- response->total_size = connection->messagePos;
+ response->total_size = connection->response_write_position;
connection_close_error (connection);
return MHD_NO;
}
- response->data_start = connection->messagePos;
+ response->data_start = connection->response_write_position;
response->data_size = ret;
if (ret == 0)
{
@@ -278,8 +278,8 @@
if (fd == -1)
return MHD_YES;
if ((connection->read_close == MHD_NO) &&
- ((connection->headersReceived == MHD_NO) ||
- (connection->readLoc < connection->read_buffer_size)))
+ ((connection->have_received_headers == MHD_NO) ||
+ (connection->read_buffer_offset < connection->read_buffer_size)))
{
FD_SET (fd, read_fd_set);
if (fd > *max_fd)
@@ -288,8 +288,8 @@
else
{
if ((connection->read_close == MHD_NO) &&
- ((connection->headersReceived == MHD_YES) &&
- (connection->readLoc == connection->read_buffer_size)))
+ ((connection->have_received_headers == MHD_YES) &&
+ (connection->read_buffer_offset == connection->read_buffer_size)))
{
/* try growing the read buffer, just in case */
buf = MHD_pool_reallocate (connection->pool,
@@ -342,8 +342,8 @@
/* die, header far too long to be reasonable */
connection->read_close = MHD_YES;
- connection->headersReceived = MHD_YES;
- connection->bodyReceived = MHD_YES;
+ connection->have_received_headers = MHD_YES;
+ connection->have_received_body = MHD_YES;
#if HAVE_MESSAGES
MHD_DLOG (connection->daemon,
"Received excessively long header, closing connection.\n");
@@ -368,17 +368,17 @@
char *rbuf;
size_t pos;
- if (connection->readLoc == 0)
+ if (connection->read_buffer_offset == 0)
return NULL;
pos = 0;
rbuf = connection->read_buffer;
- while ((pos < connection->readLoc - 1) &&
+ while ((pos < connection->read_buffer_offset - 1) &&
(rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
pos++;
- if (pos == connection->readLoc - 1)
+ if (pos == connection->read_buffer_offset - 1)
{
/* not found, consider growing... */
- if (connection->readLoc == connection->read_buffer_size)
+ if (connection->read_buffer_offset == connection->read_buffer_size)
{
rbuf = MHD_pool_reallocate (connection->pool,
connection->read_buffer,
@@ -407,7 +407,7 @@
rbuf[pos++] = '\0';
connection->read_buffer += pos;
connection->read_buffer_size -= pos;
- connection->readLoc -= pos;
+ connection->read_buffer_offset -= pos;
return rbuf;
}
@@ -586,14 +586,16 @@
/**
- * This function is designed to parse the input buffer of a given connection.
+ * This function is designed to parse the input buffer of a given
+ * connection for HTTP headers -- and in the case of chunked encoding,
+ * also for HTTP "footers".
*
* Once the header is complete, it should have set the
* headers_received, url and method values and set
- * headersReceived to MHD_YES. If no body is expected, it should
- * also set "bodyReceived" to MHD_YES. Otherwise, it should
- * set "uploadSize" to the expected size of the body. If the
- * size of the body is unknown, it should be set to -1.
+ * have_received_headers to MHD_YES. If no body is expected, it
+ * should also set "have_received_body" to MHD_YES. Otherwise, it
+ * should set "remaining_upload_size" to the expected size of the
+ * body. If the size of the body is unknown, it should be set to -1.
*/
static void
MHD_parse_connection_headers (struct MHD_Connection *connection)
@@ -606,8 +608,9 @@
unsigned long long cval;
struct MHD_Response *response;
- if ( (connection->bodyReceived == MHD_YES) ||
- (connection->headersReceived == MHD_YES) )
+ if ( ( (connection->have_received_body == MHD_YES) &&
+ (connection->have_chunked_upload == MHD_NO) ) ||
+ (connection->have_received_headers == MHD_YES) )
abort ();
colon = NULL; /* make gcc happy */
last = NULL;
@@ -656,7 +659,7 @@
if (strlen (line) == 0)
{
/* end of header */
- connection->headersReceived = MHD_YES;
+ connection->have_received_headers = MHD_YES;
clen = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_CONTENT_LENGTH);
@@ -671,8 +674,8 @@
#endif
goto DIE;
}
- connection->uploadSize = cval;
- connection->bodyReceived = cval == 0 ? MHD_YES : MHD_NO;
+ connection->remaining_upload_size = cval;
+ connection->have_received_body = cval == 0 ? MHD_YES : MHD_NO;
}
else
{
@@ -681,14 +684,29 @@
MHD_HTTP_HEADER_TRANSFER_ENCODING))
{
/* this request does not have a body */
- connection->uploadSize = 0;
- connection->bodyReceived = MHD_YES;
+ connection->remaining_upload_size = 0;
+ connection->have_received_body = MHD_YES;
}
else
{
- connection->uploadSize = -1; /* unknown size */
- connection->bodyReceived = MHD_NO;
- }
+ if (connection->have_chunked_upload == MHD_NO)
+ {
+ connection->remaining_upload_size = -1; /* unknown size
*/
+ if (0 ==
strcasecmp(MHD_lookup_connection_value(connection,
+
MHD_HEADER_KIND,
+
MHD_HTTP_HEADER_TRANSFER_ENCODING),
+ "chunked"))
+ connection->have_chunked_upload = MHD_YES;
+ }
+ else
+ {
+ /* we were actually processing the footers at the
+ END of a chunked encoding; give connection
+ handler an extra chance... */
+ connection->have_chunked_upload = MHD_NO; /* no more! */
+ MHD_call_connection_handler(connection);
+ }
+ }
}
if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
&& (NULL != connection->version)
@@ -698,7 +716,7 @@
MHD_HTTP_HEADER_HOST)))
{
/* die, http 1.1 request without host and we are pedantic */
- connection->bodyReceived = MHD_YES;
+ connection->have_received_body = MHD_YES;
connection->read_close = MHD_YES;
#if HAVE_MESSAGES
MHD_DLOG (connection->daemon,
@@ -780,54 +798,177 @@
{
struct MHD_Access_Handler *ah;
unsigned int processed;
+ unsigned int available;
+ unsigned int used;
+ int instant_retry;
+ unsigned int i;
if (connection->response != NULL)
return; /* already queued a response */
- if (connection->headersReceived == MHD_NO)
+ if (connection->have_received_headers == MHD_NO)
abort (); /* bad timing... */
- ah = MHD_find_access_handler (connection);
- processed = connection->readLoc;
- if (MHD_NO == ah->dh (ah->dh_cls,
- connection,
- connection->url,
- connection->method,
- connection->version,
- connection->read_buffer, &processed,
- &connection->client_context))
+ do
{
- /* serious internal error, close connection */
+ instant_retry = MHD_NO;
+ available = connection->read_buffer_offset;
+ if (connection->have_chunked_upload == MHD_YES)
+ {
+ 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') )
+ i++; /* skip 1st part of line feed */
+ if ( (connection->read_buffer[i] == '\r') ||
+ (connection->read_buffer[i] == '\n') )
+ i++; /* skip 2nd part of line feed */
+ if (i == 0)
+ {
+ /* malformed encoding */
#if HAVE_MESSAGES
- MHD_DLOG (connection->daemon,
- "Internal application error, closing connection.\n");
+ MHD_DLOG (connection->daemon,
+ "Received malformed HTTP request (bad chunked
encoding), closing connection.\n");
#endif
- connection_close_error (connection);
- return;
- }
- /* dh left "processed" bytes in buffer for next time... */
- memmove (connection->read_buffer,
- &connection->read_buffer[connection->readLoc - processed],
- processed);
- if (connection->uploadSize != -1)
- connection->uploadSize -= (connection->readLoc - processed);
- connection->readLoc = processed;
- if ((connection->uploadSize == 0) ||
- ((connection->readLoc == 0) &&
- (connection->uploadSize == -1) && (connection->socket_fd == -1)))
- {
- connection->bodyReceived = MHD_YES;
- if (connection->read_buffer != NULL)
- MHD_pool_reallocate (connection->pool,
- connection->read_buffer,
- (connection->read_buffer ==
- NULL) ? 0 : connection->read_buffer_size + 1,
- 0);
- connection->readLoc = 0;
- connection->read_buffer_size = 0;
- connection->read_buffer = NULL;
- }
+ connection_close_error (connection);
+ return;
+ }
+ connection->read_buffer_offset -= i;
+ available -= i;
+ memmove(connection->read_buffer,
+ &connection->read_buffer[i],
+ available);
+ connection->current_chunk_offset = 0;
+ connection->current_chunk_size = 0;
+ }
+ if (connection->current_chunk_offset < connection->current_chunk_size)
+ {
+ /* we are in the middle of a chunk, give
+ as much as possible to the client (without
+ crossing chunk boundaries) */
+ processed = connection->current_chunk_size -
connection->current_chunk_offset;
+ if (processed > available)
+ processed = available;
+ available -= processed;
+ if (available > 0)
+ instant_retry = MHD_YES;
+ }
+ else
+ {
+ /* we need to read chunk boundaries */
+ i = 0;
+ while (i < available)
+ {
+ if ( (connection->read_buffer[i] == '\r') ||
+ (connection->read_buffer[i] == '\n') )
+ break;
+ i++;
+ if (i >= 6)
+ break;
+ }
+ if (i >= available)
+ return; /* need more data... */
+ /* The following if-statement is a bit crazy -- we
+ use the second clause only for the side-effect,
+ 0-terminating the buffer for the following sscanf
+ attempts; yes, there should be only a single
+ "="-sign (assignment!) in the read_buffer[i]-line. */
+ if ( (i >= 6) ||
+ ((connection->read_buffer[i] = '\0')) ||
+ ( (1 != sscanf(connection->read_buffer,
+ "%X",
+ &connection->current_chunk_size)) &&
+ (1 != sscanf(connection->read_buffer,
+ "%x",
+ &connection->current_chunk_size)) ) )
+ {
+ /* malformed encoding */
+#if HAVE_MESSAGES
+ MHD_DLOG (connection->daemon,
+ "Received malformed HTTP request (bad chunked
encoding), closing connection.\n");
+#endif
+ connection_close_error (connection);
+ return;
+ }
+ i++;
+ if ( (connection->read_buffer[i] == '\r') ||
+ (connection->read_buffer[i] == '\n') )
+ i++; /* skip 2nd part of line feed */
+ memmove(connection->read_buffer,
+ &connection->read_buffer[i],
+ available - i);
+ connection->read_buffer_offset -= i;
+ connection->current_chunk_offset = 0;
+ instant_retry = MHD_YES;
+ if (connection->current_chunk_size == 0)
+ {
+ /* we're back to reading HEADERS (footers!) */
+ connection->have_received_body = MHD_YES;
+ connection->remaining_upload_size = 0;
+ connection->have_received_headers = MHD_NO;
+ MHD_parse_connection_headers(connection);
+ return;
+ }
+ continue;
+ }
+ }
+ else
+ {
+ /* no chunked encoding, give all to the client */
+ processed = available;
+ available = 0;
+ }
+ used = processed;
+ ah = MHD_find_access_handler (connection);
+ if (MHD_NO == ah->dh (ah->dh_cls,
+ connection,
+ connection->url,
+ connection->method,
+ connection->version,
+ connection->read_buffer, &processed,
+ &connection->client_context))
+ {
+ /* serious internal error, close connection */
+#if HAVE_MESSAGES
+ MHD_DLOG (connection->daemon,
+ "Internal application error, closing connection.\n");
+#endif
+ connection_close_error (connection);
+ return;
+ }
+ if (processed != 0)
+ instant_retry = MHD_NO; /* client did not process everything */
+ used -= processed;
+ if (connection->have_chunked_upload == MHD_YES)
+ 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);
+ if (connection->remaining_upload_size != -1)
+ connection->remaining_upload_size -= used;
+ connection->read_buffer_offset = processed + available;
+ if ((connection->remaining_upload_size == 0) ||
+ ((connection->read_buffer_offset == 0) &&
+ (connection->remaining_upload_size == -1) && (connection->socket_fd
== -1)))
+ {
+ connection->have_received_body = MHD_YES;
+ if (connection->read_buffer != NULL)
+ MHD_pool_reallocate (connection->pool,
+ connection->read_buffer,
+ (connection->read_buffer ==
+ NULL) ? 0 : connection->read_buffer_size + 1,
+ 0);
+ connection->read_buffer_offset = 0;
+ connection->read_buffer_size = 0;
+ connection->read_buffer = NULL;
+ }
+ } while (instant_retry == MHD_YES);
}
-
/**
* This function handles a particular connection when it has been
* determined that there is data to be read off a socket. All implementations
@@ -850,8 +991,8 @@
connection_close_error (connection);
return MHD_NO;
}
- if ((connection->readLoc >= connection->read_buffer_size) &&
- (connection->headersReceived == MHD_NO))
+ if ((connection->read_buffer_offset >= connection->read_buffer_size) &&
+ (connection->have_received_headers == MHD_NO))
{
/* need to grow read buffer */
tmp = MHD_pool_reallocate (connection->pool,
@@ -873,7 +1014,7 @@
connection->read_buffer_size =
connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
}
- if (connection->readLoc >= connection->read_buffer_size)
+ if (connection->read_buffer_offset >= connection->read_buffer_size)
{
#if HAVE_MESSAGES
MHD_DLOG (connection->daemon, "Unexpected call to %s.\n", __FUNCTION__);
@@ -881,8 +1022,8 @@
return MHD_NO;
}
bytes_read = RECV (connection->socket_fd,
- &connection->read_buffer[connection->readLoc],
- connection->read_buffer_size - connection->readLoc,
+ &connection->read_buffer[connection->read_buffer_offset],
+ connection->read_buffer_size -
connection->read_buffer_offset,
MSG_NOSIGNAL);
if (bytes_read < 0)
{
@@ -899,7 +1040,7 @@
{
/* other side closed connection */
connection->read_close = MHD_YES;
- if ((connection->headersReceived == MHD_YES) && (connection->readLoc >
0))
+ if ((connection->have_received_headers == MHD_YES) &&
(connection->read_buffer_offset > 0))
MHD_call_connection_handler (connection);
#if DEBUG_CLOSE
#if HAVE_MESSAGES
@@ -908,18 +1049,18 @@
#endif
#endif
shutdown (connection->socket_fd, SHUT_RD);
- if ( (connection->headersReceived == MHD_NO) ||
- (connection->bodyReceived == MHD_NO) ) {
+ if ( (connection->have_received_headers == MHD_NO) ||
+ (connection->have_received_body == MHD_NO) ) {
/* no request => no response! */
CLOSE (connection->socket_fd);
connection->socket_fd = -1;
}
return MHD_YES;
}
- connection->readLoc += bytes_read;
- if (connection->headersReceived == MHD_NO)
+ connection->read_buffer_offset += bytes_read;
+ if (connection->have_received_headers == MHD_NO)
MHD_parse_connection_headers (connection);
- if ((connection->headersReceived == MHD_YES) && (connection->method != NULL))
+ if ((connection->have_received_headers == MHD_YES) && (connection->method !=
NULL))
MHD_call_connection_handler (connection);
return MHD_YES;
}
@@ -1035,8 +1176,8 @@
if (off != size)
abort ();
connection->write_buffer = data;
- connection->writeLoc = size;
- connection->writePos = 0;
+ connection->write_buffer_append_offset = size;
+ connection->write_buffer_send_offset = 0;
connection->write_buffer_size = size + 1;
return MHD_YES;
}
@@ -1057,8 +1198,8 @@
if (MHD_need_100_continue (connection))
{
ret = SEND (connection->socket_fd,
- &HTTP_100_CONTINUE[connection->continuePos],
- strlen (HTTP_100_CONTINUE) - connection->continuePos,
+
&HTTP_100_CONTINUE[connection->continue_message_write_offset],
+ strlen (HTTP_100_CONTINUE) -
connection->continue_message_write_offset,
MSG_NOSIGNAL);
if (ret < 0)
{
@@ -1074,9 +1215,9 @@
#if DEBUG_SEND_DATA
fprintf (stderr,
"Sent 100 continue response: `%.*s'\n",
- ret, &HTTP_100_CONTINUE[connection->continuePos]);
+ ret,
&HTTP_100_CONTINUE[connection->continue_message_write_offset]);
#endif
- connection->continuePos += ret;
+ connection->continue_message_write_offset += ret;
return MHD_YES;
}
response = connection->response;
@@ -1087,7 +1228,7 @@
#endif
return MHD_NO;
}
- if (MHD_NO == connection->headersSent)
+ if (MHD_NO == connection->have_sent_headers)
{
if ((connection->write_buffer == NULL) &&
(MHD_NO == MHD_build_header_response (connection)))
@@ -1101,8 +1242,8 @@
return MHD_NO;
}
ret = SEND (connection->socket_fd,
- &connection->write_buffer[connection->writePos],
- connection->writeLoc - connection->writePos,
+
&connection->write_buffer[connection->write_buffer_send_offset],
+ connection->write_buffer_append_offset -
connection->write_buffer_send_offset,
MSG_NOSIGNAL);
if (ret < 0)
{
@@ -1118,14 +1259,14 @@
#if DEBUG_SEND_DATA
fprintf (stderr,
"Sent HEADER response: `%.*s'\n",
- ret, &connection->write_buffer[connection->writePos]);
+ ret,
&connection->write_buffer[connection->write_buffer_send_offset]);
#endif
- connection->writePos += ret;
- if (connection->writeLoc == connection->writePos)
+ connection->write_buffer_send_offset += ret;
+ if (connection->write_buffer_append_offset ==
connection->write_buffer_send_offset)
{
- connection->writeLoc = 0;
- connection->writePos = 0;
- connection->headersSent = MHD_YES;
+ connection->write_buffer_append_offset = 0;
+ connection->write_buffer_send_offset = 0;
+ connection->have_sent_headers = MHD_YES;
MHD_pool_reallocate (connection->pool,
connection->write_buffer,
connection->write_buffer_size, 0);
@@ -1134,24 +1275,24 @@
}
return MHD_YES;
}
- if (response->total_size < connection->messagePos)
+ if (response->total_size < connection->response_write_position)
abort (); /* internal error */
if (response->crc != NULL)
pthread_mutex_lock (&response->mutex);
/* prepare send buffer */
if ((response->crc != NULL) &&
- ((response->data_start > connection->messagePos) ||
+ ((response->data_start > connection->response_write_position) ||
(response->data_start + response->data_size <=
- connection->messagePos)) && (MHD_YES != ready_response (connection)))
+ connection->response_write_position)) && (MHD_YES != ready_response
(connection)))
{
pthread_mutex_unlock (&response->mutex);
return MHD_YES;
}
/* transmit */
ret = SEND (connection->socket_fd,
- &response->data[connection->messagePos - response->data_start],
- response->data_size - (connection->messagePos -
+ &response->data[connection->response_write_position -
response->data_start],
+ response->data_size - (connection->response_write_position -
response->data_start),
MSG_NOSIGNAL);
if (response->crc != NULL)
@@ -1171,15 +1312,15 @@
fprintf (stderr,
"Sent DATA response: `%.*s'\n",
ret,
- &response->data[connection->messagePos - response->data_start]);
+ &response->data[connection->response_write_position -
response->data_start]);
#endif
- connection->messagePos += ret;
- if (connection->messagePos > response->total_size)
+ connection->response_write_position += ret;
+ if (connection->response_write_position > response->total_size)
abort (); /* internal error */
- if (connection->messagePos == response->total_size)
+ if (connection->response_write_position == response->total_size)
{
- if ((connection->bodyReceived == MHD_NO) ||
- (connection->headersReceived == MHD_NO))
+ if ((connection->have_received_body == MHD_NO) ||
+ (connection->have_received_headers == MHD_NO))
abort (); /* internal error */
MHD_destroy_response (response);
if (connection->daemon->notify_completed != NULL)
@@ -1192,14 +1333,15 @@
MHD_HEADER_KIND,
MHD_HTTP_HEADER_CONNECTION);
connection->client_context = NULL;
- connection->continuePos = 0;
+ connection->continue_message_write_offset = 0;
connection->responseCode = 0;
connection->response = NULL;
connection->headers_received = NULL;
- connection->headersReceived = MHD_NO;
- connection->headersSent = MHD_NO;
- connection->bodyReceived = MHD_NO;
- connection->messagePos = 0;
+ connection->have_received_headers = MHD_NO;
+ connection->have_sent_headers = MHD_NO;
+ connection->have_received_body = MHD_NO;
+ connection->response_write_position = 0;
+ connection->have_chunked_upload = MHD_NO;
connection->method = NULL;
connection->url = NULL;
if ((end != NULL) && (0 == strcasecmp (end, "close")))
@@ -1230,10 +1372,10 @@
connection->read_buffer = NULL;
connection->write_buffer = NULL;
connection->read_buffer_size = 0;
- connection->readLoc = 0;
+ connection->read_buffer_offset = 0;
connection->write_buffer_size = 0;
- connection->writePos = 0;
- connection->writeLoc = 0;
+ connection->write_buffer_send_offset = 0;
+ connection->write_buffer_append_offset = 0;
MHD_pool_destroy (connection->pool);
connection->pool = NULL;
}
Modified: libmicrohttpd/src/daemon/daemon.c
===================================================================
--- libmicrohttpd/src/daemon/daemon.c 2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/src/daemon/daemon.c 2007-12-16 10:27:29 UTC (rev 5926)
@@ -227,7 +227,7 @@
(FD_ISSET (con->socket_fd, &ws)) &&
(MHD_YES != MHD_connection_handle_write (con))))
break;
- if ((con->headersReceived == MHD_YES) && (con->response == NULL))
+ if ((con->have_received_headers == MHD_YES) && (con->response == NULL))
MHD_call_connection_handler (con);
if ((con->socket_fd != -1) &&
((FD_ISSET (con->socket_fd, &rs)) ||
@@ -438,7 +438,7 @@
}
if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
- ((pos->headersReceived == MHD_YES) && (pos->response == NULL)) )
+ ((pos->have_received_headers == MHD_YES) && (pos->response == NULL))
)
MHD_call_connection_handler (pos);
prev = pos;
Added: libmicrohttpd/src/daemon/daemontest_put_chunked.c
===================================================================
--- libmicrohttpd/src/daemon/daemontest_put_chunked.c
(rev 0)
+++ libmicrohttpd/src/daemon/daemontest_put_chunked.c 2007-12-16 10:27:29 UTC
(rev 5926)
@@ -0,0 +1,382 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Christian Grothoff
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_put_chunked.c
+ * @brief Testcase for libmicrohttpd PUT operations with chunked encoding
+ * for the upload data
+ * @author Christian Grothoff
+ */
+
+#include "config.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+struct CBC
+{
+ char *buf;
+ size_t pos;
+ size_t size;
+};
+
+static size_t
+putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+ unsigned int *pos = ptr;
+ unsigned int wrt;
+
+ wrt = size * nmemb;
+ if (wrt > 8 - (*pos))
+ wrt = 8 - (*pos);
+ if (wrt > 4)
+ wrt = 4; /* only send half at first => force multiple chunks! */
+ memcpy (stream, &("Hello123"[*pos]), wrt);
+ (*pos) += wrt;
+ return wrt;
+}
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+ struct CBC *cbc = ctx;
+
+ if (cbc->pos + size * nmemb > cbc->size)
+ return 0; /* overflow */
+ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+ cbc->pos += size * nmemb;
+ return size * nmemb;
+}
+
+static int
+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 **unused)
+{
+ int *done = cls;
+ struct MHD_Response *response;
+ int ret;
+ int have;
+
+ if (0 != strcmp ("PUT", method))
+ return MHD_NO; /* unexpected method */
+ if ((*done) < 8)
+ {
+ have = *upload_data_size;
+ if (have + *done > 8)
+ {
+ printf ("Invalid upload data `%8s'!\n", upload_data);
+ return MHD_NO;
+ }
+ if (0 == memcmp(upload_data,
+ &"Hello123"[*done],
+ have))
+ {
+ *done += have;
+ *upload_data_size = 0;
+ }
+ else
+ {
+ printf ("Invalid upload data `%8s'!\n", upload_data);
+ return MHD_NO;
+ }
+ return MHD_YES;
+ }
+ response = MHD_create_response_from_data (strlen (url),
+ (void *) url, MHD_NO, MHD_YES);
+ ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
+static int
+testInternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+ 11080,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 1;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 4;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 8;
+ return 0;
+}
+
+static int
+testMultithreadedPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ unsigned int pos = 0;
+ int done_flag = 0;
+ CURLcode errornum;
+
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+ 11081,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 16;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+ if (CURLE_OK != (errornum = curl_easy_perform (c)))
+ {
+ fprintf (stderr,
+ "curl_easy_perform failed: `%s'\n",
+ curl_easy_strerror (errornum));
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 32;
+ }
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 64;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 128;
+
+ return 0;
+}
+
+
+static int
+testExternalPut ()
+{
+ struct MHD_Daemon *d;
+ CURL *c;
+ char buf[2048];
+ struct CBC cbc;
+ CURLM *multi;
+ CURLMcode mret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ int max;
+ int running;
+ struct CURLMsg *msg;
+ time_t start;
+ struct timeval tv;
+ unsigned int pos = 0;
+ int done_flag = 0;
+
+ multi = NULL;
+ cbc.buf = buf;
+ cbc.size = 2048;
+ cbc.pos = 0;
+ d = MHD_start_daemon (MHD_USE_DEBUG,
+ 11082,
+ NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+ if (d == NULL)
+ return 256;
+ c = curl_easy_init ();
+ curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world");
+ curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
+ curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+ curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+ curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+ curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+ /*
+ // by not giving the file size, we force chunking!
+ curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+ */
+ curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
+ curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+ // NOTE: use of CONNECTTIMEOUT without also
+ // setting NOSIGNAL results in really weird
+ // crashes on my system!
+ curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+ multi = curl_multi_init ();
+ if (multi == NULL)
+ {
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 512;
+ }
+ mret = curl_multi_add_handle (multi, c);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 1024;
+ }
+ start = time (NULL);
+ while ((time (NULL) - start < 5) && (multi != NULL))
+ {
+ max = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ curl_multi_perform (multi, &running);
+ mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 2048;
+ }
+ if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ MHD_stop_daemon (d);
+ return 4096;
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select (max + 1, &rs, &ws, &es, &tv);
+ curl_multi_perform (multi, &running);
+ if (running == 0)
+ {
+ msg = curl_multi_info_read (multi, &running);
+ if (msg == NULL)
+ break;
+ if (msg->msg == CURLMSG_DONE)
+ {
+ if (msg->data.result != CURLE_OK)
+ printf ("%s failed at %s:%d: `%s'\n",
+ "curl_multi_perform",
+ __FILE__,
+ __LINE__, curl_easy_strerror (msg->data.result));
+ curl_multi_remove_handle (multi, c);
+ curl_multi_cleanup (multi);
+ curl_easy_cleanup (c);
+ c = NULL;
+ multi = NULL;
+ }
+ }
+ MHD_run (d);
+ }
+ if (multi != NULL)
+ {
+ curl_multi_remove_handle (multi, c);
+ curl_easy_cleanup (c);
+ curl_multi_cleanup (multi);
+ }
+ MHD_stop_daemon (d);
+ if (cbc.pos != strlen ("/hello_world"))
+ return 8192;
+ if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+ return 16384;
+ return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned int errorCount = 0;
+
+ if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+ return 2;
+ errorCount += testInternalPut ();
+ if (0)
+ {
+ errorCount += testMultithreadedPut ();
+ errorCount += testExternalPut ();
+ }
+ if (errorCount != 0)
+ fprintf (stderr, "Error (code: %u)\n", errorCount);
+ curl_global_cleanup ();
+ return errorCount != 0; /* 0 == pass */
+}
Property changes on: libmicrohttpd/src/daemon/daemontest_put_chunked.c
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: libmicrohttpd/src/daemon/internal.h
===================================================================
--- libmicrohttpd/src/daemon/internal.h 2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/src/daemon/internal.h 2007-12-16 10:27:29 UTC (rev 5926)
@@ -273,7 +273,7 @@
* Position where we currently append data in
* read_buffer (last valid position).
*/
- size_t readLoc;
+ size_t read_buffer_offset;
/**
* Size of write_buffer (in bytes).
@@ -283,32 +283,33 @@
/**
* Offset where we are with sending from write_buffer.
*/
- size_t writePos;
+ size_t write_buffer_send_offset;
/**
- * Last valid location in write_buffer.
+ * Last valid location in write_buffer (where do we
+ * append and up to where is it safe to send?)
*/
- size_t writeLoc;
+ size_t write_buffer_append_offset;
/**
* Current write position in the actual response
* (excluding headers, content only; should be 0
* while sending headers).
*/
- size_t messagePos;
+ size_t response_write_position;
/**
* Remaining (!) number of bytes in the upload.
* Set to -1 for unknown (connection will close
* to indicate end of upload).
*/
- size_t uploadSize;
+ size_t remaining_upload_size;
/**
* Position in the 100 CONTINUE message that
* we need to send when receiving http 1.1 requests.
*/
- size_t continuePos;
+ size_t continue_message_write_offset;
/**
* Length of the foreign address.
@@ -343,18 +344,18 @@
* possible that the NEXT request is already
* (partially) waiting in the read buffer.
*/
- int headersReceived;
+ int have_received_headers;
/**
* Have we finished receiving the data from a
* potential file-upload?
*/
- int bodyReceived;
+ int have_received_body;
/**
* Have we finished sending all of the headers yet?
*/
- int headersSent;
+ int have_sent_headers;
/**
* HTTP response code. Only valid if response object
@@ -371,6 +372,29 @@
*/
int response_unready;
+ /**
+ * Are we receiving with chunked encoding? This will be set to
+ * MHD_YES after we parse the headers and are processing the body
+ * with chunks. After we are done with the body and we are
+ * processing the footers; once the footers are also done, this will
+ * be set to MHD_NO again (before the final call to the handler).
+ */
+ int have_chunked_upload;
+
+ /**
+ * If we are receiving with chunked encoding, where are we right
+ * now? Set to 0 if we are waiting to receive the chunk size;
+ * otherwise, this is the size of the current chunk. A value of
+ * zero is also used when we're at the end of the chunks.
+ */
+ unsigned int current_chunk_size;
+
+ /**
+ * If we are receiving with chunked encoding, where are we currently
+ * with respect to the current chunk (at what offset / position)?
+ */
+ unsigned int current_chunk_offset;
+
};
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r5926 - in libmicrohttpd: . src/daemon,
gnunet <=