commit c0ac86b069fac3460fd2e4c7997245c5a1281536
parent 285adcb02aaf613b173bab0d2cde6cbaf504b800
Author: Christian Grothoff <christian@grothoff.org>
Date: Fri, 16 Feb 2018 07:34:45 +0100
add call_handlers
Diffstat:
7 files changed, 229 insertions(+), 30 deletions(-)
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -59,6 +59,7 @@ libmicrohttpd_la_SOURCES = \
action_process_upload.c \
action_suspend.c \
connection_add.c connection_add.h \
+ connection_call_handlers.c connection_call_handlers.h \
connection_cleanup.c connection_cleanup.h \
connection_close.c connection_close.h \
connection_finish_forward.c connection_finish_forward.h \
diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c
@@ -23,6 +23,7 @@
*/
#include "internal.h"
#include "connection_add.h"
+#include "connection_call_handlers.h"
#include "connection_close.h"
#include "connection_finish_forward.h"
#include "connection_update_last_activity.h"
@@ -317,13 +318,13 @@ thread_main_handle_connection (void *data)
MHD_itc_clear_ (daemon->itc);
#endif
if (MHD_NO ==
- call_handlers (con,
- FD_ISSET (con->socket_fd,
- &rs),
- FD_ISSET (con->socket_fd,
- &ws),
- FD_ISSET (con->socket_fd,
- &es)) )
+ MHD_connection_call_handlers_ (con,
+ FD_ISSET (con->socket_fd,
+ &rs),
+ FD_ISSET (con->socket_fd,
+ &ws),
+ FD_ISSET (con->socket_fd,
+ &es)) )
goto exit;
}
#ifdef HAVE_POLL
@@ -385,10 +386,10 @@ thread_main_handle_connection (void *data)
MHD_itc_clear_ (daemon->itc);
#endif
if (MHD_NO ==
- call_handlers (con,
- 0 != (p[0].revents & POLLIN),
- 0 != (p[0].revents & POLLOUT),
- 0 != (p[0].revents & (POLLERR | MHD_POLL_REVENTS_ERR_DISC))))
+ MHD_connection_call_handlers_ (con,
+ 0 != (p[0].revents & POLLIN),
+ 0 != (p[0].revents & POLLOUT),
+ 0 != (p[0].revents & (POLLERR | MHD_POLL_REVENTS_ERR_DISC))))
goto exit;
}
#endif
diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c
@@ -0,0 +1,146 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+/**
+ * @file lib/connection_call_handlers.c
+ * @brief call the connection's handlers based on the event trigger
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+#include "connection_call_handlers.h"
+#include "connection_close.h"
+
+
+/**
+ * Call the handlers for a connection in the appropriate order based
+ * on the readiness as detected by the event loop.
+ *
+ * @param con connection to handle
+ * @param read_ready set if the socket is ready for reading
+ * @param write_ready set if the socket is ready for writing
+ * @param force_close set if a hard error was detected on the socket;
+ * if this information is not available, simply pass #MHD_NO
+ * @return #MHD_YES to continue normally,
+ * #MHD_NO if a serious error was encountered and the
+ * connection is to be closed.
+ */
+// FIXME: rename connection->request?
+int
+MHD_connection_call_handlers_ (struct MHD_Connection *con,
+ bool read_ready,
+ bool write_ready,
+ bool force_close)
+{
+ struct MHD_Daemon *daemon = con->daemon;
+ int ret;
+ bool states_info_processed = false;
+ /* Fast track flag */
+ bool on_fasttrack = (con->request.state == MHD_REQUEST_INIT);
+
+#ifdef HTTPS_SUPPORT
+ if (con->tls_read_ready)
+ read_ready = true;
+#endif /* HTTPS_SUPPORT */
+ if (!force_close)
+ {
+ if ( (MHD_EVENT_LOOP_INFO_READ ==
+ con->request.event_loop_info) &&
+ read_ready)
+ {
+ MHD_connection_handle_read (con);
+ ret = MHD_connection_handle_idle (con);
+ states_info_processed = true;
+ }
+ /* No need to check value of 'ret' here as closed connection
+ * cannot be in MHD_EVENT_LOOP_INFO_WRITE state. */
+ if ( (MHD_EVENT_LOOP_INFO_WRITE ==
+ con->request.event_loop_info) &&
+ write_ready)
+ {
+ MHD_connection_handle_write (con);
+ ret = MHD_connection_handle_idle (con);
+ states_info_processed = true;
+ }
+ }
+ else
+ {
+ MHD_connection_close_ (con,
+ MHD_REQUEST_TERMINATED_WITH_ERROR);
+ return MHD_connection_handle_idle (con);
+ }
+
+ if (! states_info_processed)
+ { /* Connection is not read or write ready, but external conditions
+ * may be changed and need to be processed. */
+ ret = MHD_connection_handle_idle (con);
+ }
+ /* Fast track for fast connections. */
+ /* If full request was read by single read_handler() invocation
+ and headers were completely prepared by single MHD_connection_handle_idle()
+ then try not to wait for next sockets polling and send response
+ immediately.
+ As writeability of socket was not checked and it may have
+ some data pending in system buffers, use this optimization
+ only for non-blocking sockets. */
+ /* No need to check 'ret' as connection is always in
+ * MHD_CONNECTION_CLOSED state if 'ret' is equal 'MHD_NO'. */
+ else if (on_fasttrack &&
+ con->sk_nonblck)
+ {
+ if (MHD_REQUEST_HEADERS_SENDING == con->request.state)
+ {
+ MHD_connection_handle_write (con);
+ /* Always call 'MHD_connection_handle_idle()' after each read/write. */
+ ret = MHD_connection_handle_idle (con);
+ }
+ /* If all headers were sent by single write_handler() and
+ * response body is prepared by single MHD_connection_handle_idle()
+ * call - continue. */
+ if ((MHD_REQUEST_NORMAL_BODY_READY == con->request.state) ||
+ (MHD_REQUEST_CHUNKED_BODY_READY == con->request.state))
+ {
+ MHD_connection_handle_write (con);
+ ret = MHD_connection_handle_idle (con);
+ }
+ }
+
+ /* All connection's data and states are processed for this turn.
+ * If connection already has more data to be processed - use
+ * zero timeout for next select()/poll(). */
+ /* Thread-per-connection do not need global zero timeout as
+ * connections are processed individually. */
+ /* Note: no need to check for read buffer availability for
+ * TLS read-ready connection in 'read info' state as connection
+ * without space in read buffer will be market as 'info block'. */
+ if ( (! daemon->data_already_pending) &&
+ (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) )
+ {
+ if (MHD_EVENT_LOOP_INFO_BLOCK ==
+ con->request.event_loop_info)
+ daemon->data_already_pending = true;
+#ifdef HTTPS_SUPPORT
+ else if ( (con->tls_read_ready) &&
+ (MHD_EVENT_LOOP_INFO_READ ==
+ con->request.event_loop_info) )
+ daemon->data_already_pending = true;
+#endif /* HTTPS_SUPPORT */
+ }
+ return ret;
+}
+
+/* end of connection_call_handlers.c */
diff --git a/src/lib/connection_call_handlers.h b/src/lib/connection_call_handlers.h
@@ -0,0 +1,48 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+/**
+ * @file lib/connection_call_handlers.h
+ * @brief function to call event handlers based on event mask
+ * @author Christian Grothoff
+ */
+
+#ifndef CONNECTION_CALL_HANDLERS_H
+#define CONNECTION_CALL_HANDLERS_H
+
+/**
+ * Call the handlers for a connection in the appropriate order based
+ * on the readiness as detected by the event loop.
+ *
+ * @param con connection to handle
+ * @param read_ready set if the socket is ready for reading
+ * @param write_ready set if the socket is ready for writing
+ * @param force_close set if a hard error was detected on the socket;
+ * if this information is not available, simply pass #MHD_NO
+ * @return #MHD_YES to continue normally,
+ * #MHD_NO if a serious error was encountered and the
+ * connection is to be closed.
+ */
+int
+MHD_connection_call_handlers_ (struct MHD_Connection *con,
+ bool read_ready,
+ bool write_ready,
+ bool force_close)
+ MHD_NONNULL (1);
+
+#endif
diff --git a/src/lib/daemon_epoll.c b/src/lib/daemon_epoll.c
@@ -23,11 +23,12 @@
* @author Christian Grothoff
*/
#include "internal.h"
+#include "connection_add.h"
+#include "connection_call_handlers.h"
+#include "connection_finish_forward.h"
#include "daemon_epoll.h"
#include "upgrade_process.h"
#include "request_resume.h"
-#include "connection_add.h"
-#include "connection_finish_forward.h"
#ifdef EPOLL_SUPPORT
@@ -454,10 +455,10 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon,
while (NULL != (pos = prev))
{
prev = pos->prevE;
- call_handlers (pos,
- 0 != (pos->epoll_state & MHD_EPOLL_STATE_READ_READY),
- 0 != (pos->epoll_state & MHD_EPOLL_STATE_WRITE_READY),
- 0 != (pos->epoll_state & MHD_EPOLL_STATE_ERROR));
+ MHD_connection_call_handlers_ (pos,
+ 0 != (pos->epoll_state & MHD_EPOLL_STATE_READ_READY),
+ 0 != (pos->epoll_state & MHD_EPOLL_STATE_WRITE_READY),
+ 0 != (pos->epoll_state & MHD_EPOLL_STATE_ERROR));
if (MHD_EPOLL_STATE_IN_EREADY_EDLL ==
(pos->epoll_state & (MHD_EPOLL_STATE_SUSPENDED | MHD_EPOLL_STATE_IN_EREADY_EDLL)))
{
diff --git a/src/lib/daemon_poll.c b/src/lib/daemon_poll.c
@@ -22,11 +22,12 @@
* @author Christian Grothoff
*/
#include "internal.h"
+#include "connection_add.h"
+#include "connection_call_handlers.h"
+#include "connection_finish_forward.h"
#include "daemon_poll.h"
#include "upgrade_process.h"
#include "request_resume.h"
-#include "connection_add.h"
-#include "connection_finish_forward.h"
#ifdef HAVE_POLL
@@ -294,10 +295,10 @@ MHD_daemon_poll_all_ (struct MHD_Daemon *daemon,
break; /* connection list changed somehow, retry later ... */
if (p[poll_server+i].fd != pos->socket_fd)
continue; /* fd mismatch, something else happened, retry later ... */
- call_handlers (pos,
- 0 != (p[poll_server+i].revents & POLLIN),
- 0 != (p[poll_server+i].revents & POLLOUT),
- 0 != (p[poll_server+i].revents & MHD_POLL_REVENTS_ERR_DISC));
+ MHD_connection_call_handlers_ (pos,
+ 0 != (p[poll_server+i].revents & POLLIN),
+ 0 != (p[poll_server+i].revents & POLLOUT),
+ 0 != (p[poll_server+i].revents & MHD_POLL_REVENTS_ERR_DISC));
i++;
}
#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
diff --git a/src/lib/daemon_select.c b/src/lib/daemon_select.c
@@ -24,6 +24,7 @@
*/
#include "internal.h"
#include "connection_add.h"
+#include "connection_call_handlers.h"
#include "connection_cleanup.h"
#include "connection_finish_forward.h"
#include "daemon_select.h"
@@ -444,13 +445,13 @@ internal_run_from_select (struct MHD_Daemon *daemon,
ds = pos->socket_fd;
if (MHD_INVALID_SOCKET == ds)
continue;
- call_handlers (pos,
- FD_ISSET (ds,
- read_fd_set),
- FD_ISSET (ds,
- write_fd_set),
- FD_ISSET (ds,
- except_fd_set));
+ MHD_connection_call_handlers_ (pos,
+ FD_ISSET (ds,
+ read_fd_set),
+ FD_ISSET (ds,
+ write_fd_set),
+ FD_ISSET (ds,
+ except_fd_set));
}
}