libmicrohttpd

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

commit e5c2f9a339845bd040f3b326d2f976d4ea4d1ac2
parent dcaf43e3230f725a6ec0b406c205b7a87b7e3368
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 18 Feb 2018 12:31:35 +0100

add remaining missing symbols for library to fully link

Diffstat:
Asrc/gnutls/update_event_loop_info.c | 20++++++++++++++++++++
Msrc/include/microhttpd2.h | 39+++++++++++++++++++++++++++++++++++++--
Msrc/include/microhttpd_tls.h | 33+++++++++++++++++++++++++++++++++
Msrc/lib/Makefile.am | 1-
Msrc/lib/action_from_response.c | 2+-
Msrc/lib/connection_call_handlers.c | 167++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Dsrc/lib/connection_update_event_loop_info.c | 195-------------------------------------------------------------------------------
Dsrc/lib/connection_update_event_loop_info.h | 42------------------------------------------
Msrc/lib/daemon_epoll.c | 6+++---
Msrc/lib/internal.h | 27---------------------------
10 files changed, 259 insertions(+), 273 deletions(-)

diff --git a/src/gnutls/update_event_loop_info.c b/src/gnutls/update_event_loop_info.c @@ -0,0 +1,20 @@ + enum MHD_Bool + (*update_event_loop_info)(void *cls, + struct MHD_TLS_ConnectionState *cs, + enum MHD_RequestEventLoopInfo *eli); + + + switch (connection->tls_state) + { + case MHD_TLS_CONN_INIT: + *eli = MHD_EVENT_LOOP_INFO_READ; + return true; + case MHD_TLS_CONN_HANDSHAKING: + if (0 == gnutls_record_get_direction (connection->tls_session)) + *eli = MHD_EVENT_LOOP_INFO_READ; + else + *eli = MHD_EVENT_LOOP_INFO_WRITE; + return true; + default: + return false; + } diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -323,12 +323,13 @@ struct MHD_Connection; * for logging. * * A value of 0 indicates success (as a return value). - * Values between 1 and 10000 must not be used. + * Values between 0 and 10000 must be handled explicitly by the app. * Values from 10000-19999 are informational. * Values from 20000-29999 indicate successful operations. * Values from 30000-39999 indicate unsuccessful (normal) operations. * Values from 40000-49999 indicate client errors. - * Values from 50000-59999 indicate server errors. + * Values from 50000-59999 indicate MHD server errors. + * Values from 60000-69999 indicate application errors. */ enum MHD_StatusCode { @@ -866,6 +867,13 @@ enum MHD_StatusCode */ MHD_SC_APPLICATION_HUNG_CONNECTION = 60007, + /** + * Application only partially processed upload and did + * not suspend connection and the read buffer was maxxed + * out, so MHD closed the connection. + */ + MHD_SC_APPLICATION_HUNG_CONNECTION_CLOSED = 60008, + }; @@ -4154,4 +4162,31 @@ _MHD_EXTERN enum MHD_Bool MHD_is_feature_supported (enum MHD_Feature feature); +/** + * What is this request waiting for? + */ +enum MHD_RequestEventLoopInfo +{ + /** + * We are waiting to be able to read. + */ + MHD_EVENT_LOOP_INFO_READ = 0, + + /** + * We are waiting to be able to write. + */ + MHD_EVENT_LOOP_INFO_WRITE = 1, + + /** + * We are waiting for the application to provide data. + */ + MHD_EVENT_LOOP_INFO_BLOCK = 2, + + /** + * We are finished and are awaiting cleanup. + */ + MHD_EVENT_LOOP_INFO_CLEANUP = 3 +}; + + #endif diff --git a/src/include/microhttpd_tls.h b/src/include/microhttpd_tls.h @@ -1,6 +1,33 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2018 Christian Grothoff (and other contributing authors) + + 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 microhttpd_tls.h + * @brief interface for TLS plugins of libmicrohttpd + * @author Christian Grothoff + */ + #ifndef MICROHTTPD_TLS_H #define MICROHTTPD_TLS_H +#include <microhttpd2.h> + /** * Version of the TLS ABI. */ @@ -100,6 +127,12 @@ struct MHD_TLS_Plugin enum MHD_Bool (*idle_ready)(void *cls, struct MHD_TLS_ConnectionState *cs); + + + enum MHD_Bool + (*update_event_loop_info)(void *cls, + struct MHD_TLS_ConnectionState *cs, + enum MHD_RequestEventLoopInfo *eli); ssize_t (*send)(void *cls, diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -65,7 +65,6 @@ 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/action_from_response.c b/src/lib/action_from_response.c @@ -89,7 +89,7 @@ response_action (void *cls, request->state = MHD_REQUEST_FOOTERS_RECEIVED; } if (! request->in_idle) - (void) MHD_connection_handle_idle (request->connection); + (void) MHD_request_handle_idle_ (request); return MHD_SC_OK; } diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c @@ -23,7 +23,6 @@ */ #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" @@ -2889,6 +2888,170 @@ connection_epoll_update_ (struct MHD_Connection *connection) /** + * 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 + */ +static void +connection_update_event_loop_info (struct MHD_Connection *connection) +{ + struct MHD_Daemon *daemon = connection->daemon; + struct MHD_Request *request = &connection->request; + + /* Do not update states of suspended connection */ + if (connection->suspended) + return; /* States will be updated after resume. */ +#ifdef HTTPS_SUPPORT + { + struct MHD_TLS_Plugin *tls; + + if ( (NULL != (tls = daemon->tls_api)) && + (tls->update_event_loop_info (tls->cls, + connection->tls_cs, + &request->event_loop_info)) ) + return; /* TLS has decided what to do */ + } +#endif /* HTTPS_SUPPORT */ + while (1) + { +#if DEBUG_STATES + MHD_DLOG (daemon, + MHD_SC_STATE_MACHINE_STATUS_REPORT, + _("In function %s handling connection at state: %s\n"), + __FUNCTION__, + MHD_state_to_string (request->state)); +#endif + switch (request->state) + { + case MHD_REQUEST_INIT: + case MHD_REQUEST_URL_RECEIVED: + case MHD_REQUEST_HEADER_PART_RECEIVED: + /* while reading headers, we always grow the + read buffer if needed, no size-check required */ + if ( (request->read_buffer_offset == request->read_buffer_size) && + (! try_grow_read_buffer (request)) ) + { + transmit_error_response (request, + MHD_SC_CLIENT_HEADER_TOO_BIG, + (NULL != request->url) + ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE + : MHD_HTTP_URI_TOO_LONG, + REQUEST_TOO_BIG); + continue; + } + if (! connection->read_closed) + request->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + request->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_REQUEST_HEADERS_RECEIVED: + mhd_assert (0); + break; + case MHD_REQUEST_HEADERS_PROCESSED: + mhd_assert (0); + break; + case MHD_REQUEST_CONTINUE_SENDING: + request->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_REQUEST_CONTINUE_SENT: + if (request->read_buffer_offset == request->read_buffer_size) + { + if ( (! try_grow_read_buffer (request)) && + (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) ) + { + /* 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 (request, + MHD_SC_APPLICATION_HUNG_CONNECTION_CLOSED, + MHD_HTTP_INTERNAL_SERVER_ERROR, + INTERNAL_ERROR); + continue; + } + } + if ( (request->read_buffer_offset < request->read_buffer_size) && + (! connection->read_closed) ) + request->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + request->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_REQUEST_BODY_RECEIVED: + case MHD_REQUEST_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, + MHD_SC_CONNECTION_READ_FAIL_CLOSED, + NULL); + continue; + } + request->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + /* transition to FOOTERS_RECEIVED + happens in read handler */ + break; + case MHD_REQUEST_FOOTERS_RECEIVED: + request->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_REQUEST_HEADERS_SENDING: + /* headers in buffer, keep writing */ + request->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_REQUEST_HEADERS_SENT: + mhd_assert (0); + break; + case MHD_REQUEST_NORMAL_BODY_READY: + request->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_REQUEST_NORMAL_BODY_UNREADY: + request->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_REQUEST_CHUNKED_BODY_READY: + request->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_REQUEST_CHUNKED_BODY_UNREADY: + request->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_REQUEST_BODY_SENT: + mhd_assert (0); + break; + case MHD_REQUEST_FOOTERS_SENDING: + request->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_REQUEST_FOOTERS_SENT: + mhd_assert (0); + break; + case MHD_REQUEST_CLOSED: + request->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + return; /* do nothing, not even reading */ + case MHD_REQUEST_IN_CLEANUP: + mhd_assert (0); + break; +#ifdef UPGRADE_SUPPORT + case MHD_REQUEST_UPGRADE: + mhd_assert (0); + break; +#endif /* UPGRADE_SUPPORT */ + default: + mhd_assert (0); + } + break; + } +} + + +/** * 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 @@ -3386,7 +3549,7 @@ MHD_request_handle_idle_ (struct MHD_Request *request) return true; } } - MHD_connection_update_event_loop_info_ (connection); + connection_update_event_loop_info (connection); ret = true; #ifdef EPOLL_SUPPORT if ( (! connection->suspended) && diff --git a/src/lib/connection_update_event_loop_info.c b/src/lib/connection_update_event_loop_info.c @@ -1,195 +0,0 @@ -/* - 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 @@ -1,42 +0,0 @@ -/* - 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/daemon_epoll.c b/src/lib/daemon_epoll.c @@ -477,7 +477,7 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon, } /* Finally, handle timed-out connections; we need to do this here - as the epoll mechanism won't call the 'MHD_connection_handle_idle()' on everything, + as the epoll mechanism won't call the 'MHD_request_handle_idle_()' on everything, as the other event loops do. As timeouts do not get an explicit event, we need to find those connections that might have timed out here. @@ -488,7 +488,7 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon, while (NULL != (pos = prev)) { prev = pos->prevX; - MHD_connection_handle_idle (pos); + MHD_request_handle_idle_ (&pos->request); } /* Connections with the default timeout are sorted by prepending them to the head of the list whenever we touch the connection; @@ -498,7 +498,7 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon, while (NULL != (pos = prev)) { prev = pos->prevX; - MHD_connection_handle_idle (pos); + MHD_request_handle_idle_ (&pos->request); if (MHD_REQUEST_CLOSED != pos->request.state) break; /* sorted by timeout, no need to visit the rest! */ } diff --git a/src/lib/internal.h b/src/lib/internal.h @@ -363,33 +363,6 @@ struct MHD_HTTP_Header /** - * What is this request waiting for? - */ -enum MHD_RequestEventLoopInfo -{ - /** - * We are waiting to be able to read. - */ - MHD_EVENT_LOOP_INFO_READ = 0, - - /** - * We are waiting to be able to write. - */ - MHD_EVENT_LOOP_INFO_WRITE = 1, - - /** - * We are waiting for the application to provide data. - */ - MHD_EVENT_LOOP_INFO_BLOCK = 2, - - /** - * We are finished and are awaiting cleanup. - */ - MHD_EVENT_LOOP_INFO_CLEANUP = 3 -}; - - -/** * State kept for each HTTP request. */ struct MHD_Request