libmicrohttpd

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

commit dcaf43e3230f725a6ec0b406c205b7a87b7e3368
parent 7d740904c403a0bdbf473b16025799ba03f89536
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 18 Feb 2018 11:08:36 +0100

more work towards getting lib to build nicely (currently FTBFS)

Diffstat:
Msrc/lib/Makefile.am | 1+
Msrc/lib/connection_add.c | 4++--
Msrc/lib/connection_call_handlers.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/lib/connection_call_handlers.h | 16++++++++++++++++
Msrc/lib/connection_cleanup.c | 4++--
Asrc/lib/connection_update_event_loop_info.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/connection_update_event_loop_info.h | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/connection_update_last_activity.c | 2+-
8 files changed, 385 insertions(+), 7 deletions(-)

diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -65,6 +65,7 @@ libmicrohttpd_la_SOURCES = \ connection_finish_forward.c connection_finish_forward.h \ connection_info.c \ connection_options.c \ + connection_update_event_loop_info.c connection_update_event_loop_info.h \ connection_update_last_activity.c connection_update_last_activity.h \ daemon_close_all_connections.c daemon_close_all_connections.h \ daemon_create.c \ diff --git a/src/lib/connection_add.c b/src/lib/connection_add.c @@ -193,7 +193,7 @@ thread_main_handle_connection (void *data) { MHD_connection_update_last_activity_ (con); /* Reset timeout timer. */ /* Process response queued during suspend and update states. */ - MHD_connection_handle_idle (con); + MHD_request_handle_idle_ (&con->request); was_suspended = false; } @@ -433,7 +433,7 @@ thread_main_handle_connection (void *data) (daemon->shutdown) ? MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN: MHD_REQUEST_TERMINATED_WITH_ERROR); - MHD_connection_handle_idle (con); + MHD_request_handle_idle_ (&con->request); } exit: if (NULL != con->request.response) diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c @@ -23,6 +23,7 @@ */ #include "internal.h" #include "connection_call_handlers.h" +#include "connection_update_event_loop_info.h" #include "connection_update_last_activity.h" #include "connection_close.h" @@ -2767,6 +2768,127 @@ process_request_body (struct MHD_Request *request) /** + * Clean up the state of the given connection and move it into the + * clean up queue for final disposal. + * @remark To be called only from thread that process connection's + * recv(), send() and response. + * + * @param connection handle for the connection to clean up + */ +static void +cleanup_connection (struct MHD_Connection *connection) +{ + struct MHD_Daemon *daemon = connection->daemon; + + if (connection->request.in_cleanup) + return; /* Prevent double cleanup. */ + connection->request.in_cleanup = true; + if (NULL != connection->request.response) + { + MHD_response_queue_for_destroy (connection->request.response); + connection->request.response = NULL; + } + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + if (connection->suspended) + { + DLL_remove (daemon->suspended_connections_head, + daemon->suspended_connections_tail, + connection); + connection->suspended = false; + } + else + { + if (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) + { + if (connection->connection_timeout == + daemon->connection_default_timeout) + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_remove (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); + } + DLL_remove (daemon->connections_head, + daemon->connections_tail, + connection); + } + DLL_insert (daemon->cleanup_head, + daemon->cleanup_tail, + connection); + connection->resuming = false; + connection->request.in_idle = false; + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); + if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) + { + /* if we were at the connection limit before and are in + thread-per-connection mode, signal the main thread + to resume accepting connections */ + if ( (MHD_ITC_IS_VALID_ (daemon->itc)) && + (! MHD_itc_activate_ (daemon->itc, + "c")) ) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + MHD_SC_ITC_USE_FAILED, + _("Failed to signal end of connection via inter-thread communication channel")); +#endif + } + } +} + + +#ifdef EPOLL_SUPPORT +/** + * Perform epoll() processing, possibly moving the connection back into + * the epoll() set if needed. + * + * @param connection connection to process + * @return true if we should continue to process the + * connection (not dead yet), false if it died + */ +static bool +connection_epoll_update_ (struct MHD_Connection *connection) +{ + struct MHD_Daemon *daemon = connection->daemon; + + if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) && + ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->request.event_loop_info) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) || + ( (MHD_EVENT_LOOP_INFO_READ == connection->request.event_loop_info) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) ) + { + /* add to epoll set */ + struct epoll_event event; + + event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; + event.data.ptr = connection; + if (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_ADD, + connection->socket_fd, + &event)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + MHD_SC_EPOLL_CTL_ADD_FAILED, + _("Call to epoll_ctl failed: %s\n"), + MHD_socket_last_strerr_ ()); +#endif + connection->request.state = MHD_REQUEST_CLOSED; + cleanup_connection (connection); + return false; + } + connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; + } + return true; +} +#endif + + +/** * This function was created to handle per-request processing that * has to happen even if the socket cannot be read or written to. * @remark To be called only from thread that process request's @@ -3064,6 +3186,7 @@ MHD_request_handle_idle_ (struct MHD_Request *request) { socket_start_normal_buffering (connection); request->state = MHD_REQUEST_UPGRADE; +#if FIXME_LEGACY_STYLE /* This request is "upgraded". Pass socket to application. */ if (! MHD_response_execute_upgrade_ (request->response, request)) @@ -3074,6 +3197,7 @@ MHD_request_handle_idle_ (struct MHD_Request *request) NULL); continue; } +#endif /* Response is not required anymore for this request. */ if (NULL != request->response) { @@ -3262,13 +3386,13 @@ MHD_request_handle_idle_ (struct MHD_Request *request) return true; } } - MHD_connection_update_event_loop_info (connection); + MHD_connection_update_event_loop_info_ (connection); ret = true; #ifdef EPOLL_SUPPORT if ( (! connection->suspended) && (MHD_ELS_EPOLL == daemon->event_loop_syscall) ) { - ret = MHD_connection_epoll_update_ (connection); + ret = connection_epoll_update_ (connection); } #endif /* EPOLL_SUPPORT */ request->in_idle = false; diff --git a/src/lib/connection_call_handlers.h b/src/lib/connection_call_handlers.h @@ -45,4 +45,20 @@ MHD_connection_call_handlers_ (struct MHD_Connection *con, bool force_close) MHD_NONNULL (1); + +/** + * This function was created to handle per-request processing that + * has to happen even if the socket cannot be read or written to. + * @remark To be called only from thread that process request's + * recv(), send() and response. + * + * @param request the request to handle + * @return true if we should continue to process the + * request (not dead yet), false if it died + */ +bool +MHD_request_handle_idle_ (struct MHD_Request *request) + MHD_NONNULL (1); + + #endif diff --git a/src/lib/connection_cleanup.c b/src/lib/connection_cleanup.c @@ -35,7 +35,7 @@ * @param connection handle to the upgraded connection to clean */ static void -cleanup_upgraded_connection (struct MHD_Connection *connection) +connection_cleanup_upgraded (struct MHD_Connection *connection) { struct MHD_UpgradeResponseHandle *urh = connection->request.urh; @@ -90,7 +90,7 @@ MHD_connection_cleanup_ (struct MHD_Daemon *daemon) (! MHD_join_thread_ (pos->pid.handle)) ) MHD_PANIC (_("Failed to join a thread\n")); #ifdef UPGRADE_SUPPORT - cleanup_upgraded_connection (pos); + connection_cleanup_upgraded (pos); #endif /* UPGRADE_SUPPORT */ MHD_pool_destroy (pos->pool); #ifdef HTTPS_SUPPORT diff --git a/src/lib/connection_update_event_loop_info.c b/src/lib/connection_update_event_loop_info.c @@ -0,0 +1,195 @@ +/* + 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_update_event_loop_info.c + * @brief update the set of network events this connection is waiting for + * @author Christian Grothoff + */ +#include "internal.h" +#include "connection_update_event_loop_info.h" + + +/** + * Update the 'event_loop_info' field of this connection based on the + * state that the connection is now in. May also close the connection + * or perform other updates to the connection if needed to prepare for + * the next round of the event loop. + * + * @param connection connection to get poll set for + */ +void +MHD_connection_update_event_loop_info_ (struct MHD_Connection *connection) +{ + /* Do not update states of suspended connection */ + if (connection->suspended) + return; /* States will be updated after resume. */ +#ifdef HTTPS_SUPPORT + if (MHD_TLS_CONN_NO_TLS != connection->tls_state) + { /* HTTPS connection. */ + switch (connection->tls_state) + { + case MHD_TLS_CONN_INIT: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + return; + case MHD_TLS_CONN_HANDSHAKING: + if (0 == gnutls_record_get_direction (connection->tls_session)) + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + return; + default: + break; + } + } +#endif /* HTTPS_SUPPORT */ + while (1) + { +#if DEBUG_STATES + MHD_DLOG (connection->daemon, + _("In function %s handling connection at state: %s\n"), + __FUNCTION__, + MHD_state_to_string (connection->state)); +#endif + switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: + /* while reading headers, we always grow the + read buffer if needed, no size-check required */ + if ( (connection->read_buffer_offset == connection->read_buffer_size) && + (MHD_NO == try_grow_read_buffer (connection)) ) + { + transmit_error_response (connection, + (connection->url != NULL) + ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE + : MHD_HTTP_URI_TOO_LONG, + REQUEST_TOO_BIG); + continue; + } + if (! connection->read_closed) + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_HEADERS_RECEIVED: + mhd_assert (0); + break; + case MHD_CONNECTION_HEADERS_PROCESSED: + mhd_assert (0); + break; + case MHD_CONNECTION_CONTINUE_SENDING: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_CONTINUE_SENT: + if (connection->read_buffer_offset == connection->read_buffer_size) + { + if ((MHD_YES != try_grow_read_buffer (connection)) && + (0 != (connection->daemon->options & + MHD_USE_INTERNAL_POLLING_THREAD))) + { + /* failed to grow the read buffer, and the + client which is supposed to handle the + received data in a *blocking* fashion + (in this mode) did not handle the data as + it was supposed to! + => we would either have to do busy-waiting + (on the client, which would likely fail), + or if we do nothing, we would just timeout + on the connection (if a timeout is even + set!). + Solution: we kill the connection with an error */ + transmit_error_response (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + INTERNAL_ERROR); + continue; + } + } + if ( (connection->read_buffer_offset < connection->read_buffer_size) && + (! connection->read_closed) ) + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + /* while reading footers, we always grow the + read buffer if needed, no size-check required */ + if (connection->read_closed) + { + CONNECTION_CLOSE_ERROR (connection, + NULL); + continue; + } + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + /* transition to FOOTERS_RECEIVED + happens in read handler */ + break; + case MHD_CONNECTION_FOOTERS_RECEIVED: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_HEADERS_SENDING: + /* headers in buffer, keep writing */ + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_HEADERS_SENT: + mhd_assert (0); + break; + case MHD_CONNECTION_NORMAL_BODY_READY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_BODY_SENT: + mhd_assert (0); + break; + case MHD_CONNECTION_FOOTERS_SENDING: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_FOOTERS_SENT: + mhd_assert (0); + break; + case MHD_CONNECTION_CLOSED: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + return; /* do nothing, not even reading */ + case MHD_CONNECTION_IN_CLEANUP: + mhd_assert (0); + break; +#ifdef UPGRADE_SUPPORT + case MHD_CONNECTION_UPGRADE: + mhd_assert (0); + break; +#endif /* UPGRADE_SUPPORT */ + default: + mhd_assert (0); + } + break; + } +} + + +/* end of connection_update_event_loop_info.c */ + diff --git a/src/lib/connection_update_event_loop_info.h b/src/lib/connection_update_event_loop_info.h @@ -0,0 +1,42 @@ +/* + 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_update_event_loop_info.h + * @brief function to update last activity of a connection + * @author Christian Grothoff + */ + +#ifndef CONNECTION_UPDATE_EVENT_LOOP_INFO_H +#define CONNECTION_UPDATE_EVENT_LOOP_INFO_H + + +/** + * Update the 'event_loop_info' field of this connection based on the + * state that the connection is now in. May also close the connection + * or perform other updates to the connection if needed to prepare for + * the next round of the event loop. + * + * @param connection connection to get poll set for + */ +void +MHD_connection_update_event_loop_info_ (struct MHD_Connection *connection) + MHD_NONNULL (1); + + +#endif diff --git a/src/lib/connection_update_last_activity.c b/src/lib/connection_update_last_activity.c @@ -17,7 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** - * @file lib/connection_add.c + * @file lib/connection_update_last_activity.c * @brief functions to add connection to our active set * @author Christian Grothoff */