libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit c0ac86b069fac3460fd2e4c7997245c5a1281536
parent 285adcb02aaf613b173bab0d2cde6cbaf504b800
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri, 16 Feb 2018 07:34:45 +0100

add call_handlers

Diffstat:
Msrc/lib/Makefile.am | 1+
Msrc/lib/connection_add.c | 23++++++++++++-----------
Asrc/lib/connection_call_handlers.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/connection_call_handlers.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/daemon_epoll.c | 13+++++++------
Msrc/lib/daemon_poll.c | 13+++++++------
Msrc/lib/daemon_select.c | 15++++++++-------
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)); } }