commit 6578d480c57c6fef92b5a980d41eabb22192f2cf
parent 02171fdaeb0c1e02f778cd1e595319fd63941b8e
Author: Christian Grothoff <christian@grothoff.org>
Date: Fri, 30 Aug 2013 11:54:56 +0000
towards fixing #3008
Diffstat:
5 files changed, 69 insertions(+), 22 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,10 @@
+Fri Aug 30 13:53:04 CEST 2013
+ Started to implement #3008 (RFC 2616, section 8.1.4
+ says HTTP server SHOULD terminate connection if the
+ client closes it for writing via TCP FIN, so we should
+ to continue to try to read and react differently
+ if recv() returns zero). -CG
+
Wed Aug 28 18:40:47 CEST 2013
Fix #3007 (build issue if messages are disabled). -CG
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
@@ -120,7 +120,7 @@ extern "C"
/**
* Current version of the library.
*/
-#define MHD_VERSION 0x00092201
+#define MHD_VERSION 0x00092202
/**
* MHD-internal return code for "YES".
@@ -882,7 +882,15 @@ enum MHD_RequestTerminationCode
* data.
* @ingroup request
*/
- MHD_REQUEST_TERMINATED_READ_ERROR = 4
+ MHD_REQUEST_TERMINATED_READ_ERROR = 4,
+
+ /**
+ * The client terminated the connection by closing the socket
+ * for writing (TCP half-closed); MHD aborted sending the
+ * response according to RFC 2616, section 8.1.4.
+ * @ingroup request
+ */
+ MHD_REQUEST_TERMINATED_CLIENT_ABORT = 5
};
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
@@ -1494,7 +1494,6 @@ do_read (struct MHD_Connection *connection)
if (connection->read_buffer_size == connection->read_buffer_offset)
return MHD_NO;
-
bytes_read = connection->recv_cls (connection,
&connection->read_buffer
[connection->read_buffer_offset],
@@ -1520,11 +1519,11 @@ do_read (struct MHD_Connection *connection)
}
if (0 == bytes_read)
{
- /* other side closed connection */
+ /* other side closed connection; RFC 2616, section 8.1.4 suggests
+ we should then shutdown ourselves as well. */
connection->read_closed = MHD_YES;
- /* shutdown is not required here, as the other side already
- knows; so flagging this internally should suffice */
- /* SHUTDOWN (connection->socket_fd, SHUT_RD); */
+ MHD_connection_close (connection,
+ MHD_REQUEST_TERMINATED_CLIENT_ABORT);
return MHD_YES;
}
connection->read_buffer_offset += bytes_read;
@@ -2465,6 +2464,15 @@ MHD_connection_handle_idle (struct MHD_Connection *connection)
}
break;
case MHD_EVENT_LOOP_INFO_WRITE:
+ if ( (connection->read_buffer_size > connection->read_buffer_offset) &&
+ (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) &&
+ (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) )
+ {
+ EDLL_insert (daemon->eready_head,
+ daemon->eready_tail,
+ connection);
+ connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
+ }
if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) &&
(0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) )
{
@@ -2498,8 +2506,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection)
#if EPOLL_SUPPORT
/**
- * Perform epoll processing, possibly moving the connection back into
- * the epoll set if needed.
+ * Perform epoll() processing, possibly moving the connection back into
+ * the epoll() set if needed.
*
* @param connection connection to process
* @return MHD_YES if we should continue to process the
@@ -2514,7 +2522,8 @@ MHD_connection_epoll_update_ (struct MHD_Connection *connection)
(0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
( (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) ||
( (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) &&
- (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) &&
+ ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) ||
+ (connection->read_buffer_size > connection->read_buffer_offset) ) &&
(MHD_NO == connection->read_closed) ) ) )
{
/* add to epoll set */
@@ -2694,11 +2703,8 @@ MHD_queue_response (struct MHD_Connection *connection,
(0 == strcasecmp (connection->method,
MHD_HTTP_METHOD_PUT))) )
{
- /* response was queued "early",
- refuse to read body / footers or further
- requests! */
- if (0 == (connection->daemon->options & MHD_USE_EPOLL_TURBO))
- (void) SHUTDOWN (connection->socket_fd, SHUT_RD);
+ /* response was queued "early", refuse to read body / footers or
+ further requests! */
connection->read_closed = MHD_YES;
connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
}
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
@@ -615,9 +615,12 @@ MHD_get_fdset (struct MHD_Daemon *daemon,
break;
case MHD_EVENT_LOOP_INFO_WRITE:
add_to_fd_set (pos->socket_fd, write_fd_set, max_fd);
+ if (pos->read_buffer_size > pos->read_buffer_offset)
+ add_to_fd_set (pos->socket_fd, read_fd_set, max_fd);
break;
case MHD_EVENT_LOOP_INFO_BLOCK:
- /* not in any FD set */
+ if (pos->read_buffer_size > pos->read_buffer_offset)
+ add_to_fd_set (pos->socket_fd, read_fd_set, max_fd);
break;
case MHD_EVENT_LOOP_INFO_CLEANUP:
/* this should never happen */
@@ -693,8 +696,12 @@ MHD_handle_connection (void *data)
break;
case MHD_EVENT_LOOP_INFO_WRITE:
add_to_fd_set (con->socket_fd, &ws, &max);
+ if (con->read_buffer_size > con->read_buffer_offset)
+ add_to_fd_set (con->socket_fd, &rs, &max);
break;
case MHD_EVENT_LOOP_INFO_BLOCK:
+ if (con->read_buffer_size > con->read_buffer_offset)
+ add_to_fd_set (con->socket_fd, &rs, &max);
tv.tv_sec = 0;
tv.tv_usec = 0;
tvp = &tv;
@@ -741,8 +748,12 @@ MHD_handle_connection (void *data)
break;
case MHD_EVENT_LOOP_INFO_WRITE:
p[0].events |= POLLOUT;
+ if (con->read_buffer_size > con->read_buffer_offset)
+ p[0].events |= POLLIN;
break;
case MHD_EVENT_LOOP_INFO_BLOCK:
+ if (con->read_buffer_size > con->read_buffer_offset)
+ p[0].events |= POLLIN;
tv.tv_sec = 0;
tv.tv_usec = 0;
tvp = &tv;
@@ -1774,11 +1785,16 @@ MHD_run_from_select (struct MHD_Daemon *daemon,
pos->read_handler (pos);
break;
case MHD_EVENT_LOOP_INFO_WRITE:
+ if ( (FD_ISSET (ds, read_fd_set)) &&
+ (pos->read_buffer_size > pos->read_buffer_offset) )
+ pos->read_handler (pos);
if (FD_ISSET (ds, write_fd_set))
pos->write_handler (pos);
break;
case MHD_EVENT_LOOP_INFO_BLOCK:
- /* only idle handler */
+ if ( (FD_ISSET (ds, read_fd_set)) &&
+ (pos->read_buffer_size > pos->read_buffer_offset) )
+ pos->read_handler (pos);
break;
case MHD_EVENT_LOOP_INFO_CLEANUP:
/* should never happen */
@@ -1903,9 +1919,7 @@ MHD_poll_all (struct MHD_Daemon *daemon,
/* count number of connections and thus determine poll set size */
num_connections = 0;
for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
- if ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) ||
- (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) )
- num_connections++;
+ num_connections++;
{
struct pollfd p[2 + num_connections];
MHD_UNSIGNED_LONG_LONG ltimeout;
@@ -1953,9 +1967,12 @@ MHD_poll_all (struct MHD_Daemon *daemon,
break;
case MHD_EVENT_LOOP_INFO_WRITE:
p[poll_server+i].events |= POLLOUT;
+ if (pos->read_buffer_size > pos->read_buffer_offset)
+ p[poll_server+i].events |= POLLIN;
break;
case MHD_EVENT_LOOP_INFO_BLOCK:
- /* not in poll */
+ if (pos->read_buffer_size > pos->read_buffer_offset)
+ p[poll_server+i].events |= POLLIN;
break;
case MHD_EVENT_LOOP_INFO_CLEANUP:
/* should never happen */
@@ -2005,12 +2022,16 @@ MHD_poll_all (struct MHD_Daemon *daemon,
if (p[poll_server+i].fd != pos->socket_fd)
break; /* fd mismatch, something else happened, retry later ... */
/* normal handling */
+ if (0 != (p[poll_server+i].revents & POLLIN))
+ pos->read_handler (pos);
if (0 != (p[poll_server+i].revents & POLLOUT))
pos->write_handler (pos);
pos->idle_handler (pos);
i++;
break;
case MHD_EVENT_LOOP_INFO_BLOCK:
+ if (0 != (p[poll_server+i].revents & POLLIN))
+ pos->read_handler (pos);
pos->idle_handler (pos);
break;
case MHD_EVENT_LOOP_INFO_CLEANUP:
@@ -2234,7 +2255,8 @@ MHD_epoll (struct MHD_Daemon *daemon,
if (0 != (events[i].events & EPOLLIN))
{
pos->epoll_state |= MHD_EPOLL_STATE_READ_READY;
- if ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) &&
+ if ( ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) ||
+ (pos->read_buffer_size > pos->read_buffer_offset) ) &&
(0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
{
EDLL_insert (daemon->eready_head,
diff --git a/src/testcurl/test_post.c b/src/testcurl/test_post.c
@@ -481,6 +481,7 @@ struct CRBC
size_t pos;
};
+
static size_t
readBuffer(void *p, size_t size, size_t nmemb, void *opaque)
{
@@ -497,6 +498,7 @@ readBuffer(void *p, size_t size, size_t nmemb, void *opaque)
return required/size;
}
+
static size_t
slowReadBuffer(void *p, size_t size, size_t nmemb, void *opaque)
{
@@ -504,6 +506,7 @@ slowReadBuffer(void *p, size_t size, size_t nmemb, void *opaque)
return readBuffer(p, size, nmemb, opaque);
}
+
#define FLAG_EXPECT_CONTINUE 1
#define FLAG_CHUNKED 2
#define FLAG_FORM_DATA 4
@@ -604,6 +607,7 @@ testMultithreadedPostCancelPart(int flags)
return result;
}
+
static int
testMultithreadedPostCancel()
{