mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
fixing Mantis 1260
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -53,7 +53,7 @@ feature.
|
||||
For http/1.1-compliance:
|
||||
========================
|
||||
connection.c:
|
||||
- support chunked requests from clients (#1260, ARCH, TEST)
|
||||
- support sending of chunked responses (#1260, TEST)
|
||||
|
||||
For POST:
|
||||
=========
|
||||
|
||||
@@ -48,6 +48,7 @@ check_PROGRAMS = \
|
||||
daemontest_postform \
|
||||
daemontest_post_loop \
|
||||
daemontest_put \
|
||||
daemontest_put_chunked \
|
||||
daemontest_large_put \
|
||||
daemontest_get11 \
|
||||
daemontest_post11 \
|
||||
@@ -94,6 +95,12 @@ daemontest_put_LDADD = \
|
||||
$(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 = \
|
||||
|
||||
+261
-119
@@ -152,7 +152,7 @@ MHD_queue_response (struct MHD_Connection *connection,
|
||||
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 @@ MHD_queue_response (struct MHD_Connection *connection,
|
||||
{
|
||||
/* 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 @@ MHD_need_100_continue (struct MHD_Connection *connection)
|
||||
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 @@ ready_response (struct MHD_Connection *connection)
|
||||
|
||||
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 @@ ready_response (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
|
||||
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 @@ MHD_connection_get_fdset (struct MHD_Connection *connection,
|
||||
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 @@ MHD_excessive_data_handler (struct MHD_Connection *connection,
|
||||
|
||||
/* 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 @@ MHD_get_next_header_line (struct MHD_Connection *connection)
|
||||
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 @@ MHD_get_next_header_line (struct MHD_Connection *connection)
|
||||
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 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line)
|
||||
|
||||
|
||||
/**
|
||||
* 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 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
|
||||
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 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
|
||||
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 @@ MHD_parse_connection_headers (struct MHD_Connection *connection)
|
||||
#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_parse_connection_headers (struct MHD_Connection *connection)
|
||||
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_parse_connection_headers (struct MHD_Connection *connection)
|
||||
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 @@ MHD_call_connection_handler (struct MHD_Connection *connection)
|
||||
{
|
||||
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 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
|
||||
{
|
||||
/* 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 @@ MHD_connection_handle_read (struct MHD_Connection *connection)
|
||||
#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 @@ MHD_build_header_response (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
#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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
#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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
#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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
}
|
||||
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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
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_connection_handle_write (struct MHD_Connection *connection)
|
||||
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 @@ MHD_connection_handle_write (struct MHD_Connection *connection)
|
||||
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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -227,7 +227,7 @@ MHD_handle_connection (void *data)
|
||||
(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 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
+34
-10
@@ -273,7 +273,7 @@ struct MHD_Connection
|
||||
* 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 @@ struct MHD_Connection
|
||||
/**
|
||||
* 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 @@ struct MHD_Connection
|
||||
* 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 @@ struct MHD_Connection
|
||||
*/
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user