From f73873bc1925b1553effb57a1cc0dd19ad5e3302 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 25 Jul 2019 14:42:56 +0200 Subject: fix regression introduced in cc5032b85 --- ChangeLog | 11 ++++++++--- src/include/microhttpd.h | 2 +- src/microhttpd/connection.c | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a057b73..c45326df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ +Thu 25 Jul 2019 02:40:12 PM CEST + Fixing regression introduced in cc5032b85 (bit mask matching + of the header kinds in MHD_lookup_connection_value()), as + reported by Jose Bollo on the mailinglist. -CG/JB + Tue Jul 16 19:56:14 CEST 2019 - Add MHD_OPTION_HTTPS_CERT_CALLBACK2 to allow OCSP stapling - and MHD_FEATURE_HTTPS_CERT_CALLBACK2 to check for. -TR + Add MHD_OPTION_HTTPS_CERT_CALLBACK2 to allow OCSP stapling + and MHD_FEATURE_HTTPS_CERT_CALLBACK2 to check for. -TR Fri Jul 05 2019 22:30:40 MSK Releasing libmicrohttpd 0.9.65. -EG @@ -102,7 +107,7 @@ Sun Apr 21 16:40:00 MSK 2019 Fri Apr 19 23:00:00 MSK 2019 Rewritten SHA-256 calculations from scratch to avoid changing LGPL version; - Added usage of GCC/Clang built-ins for bytes swap to significantly improve + Added usage of GCC/Clang built-ins for bytes swap to significantly improve speed of MD5 and SHA-256 calculation on platforms with known endianness. Added test for SHA-256 calculations. -EG diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 9d28cdb1..4c05ffac 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h @@ -132,7 +132,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00096502 +#define MHD_VERSION 0x00096503 /** * MHD-internal return code for "YES". diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 877f514b..fd977708 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c @@ -970,7 +970,7 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection, { for (pos = connection->headers_received; NULL != pos; pos = pos->next) { - if ( (kind == pos->kind) && + if ( (0 != (kind & pos->kind)) && (NULL == pos->header) ) break; } @@ -979,7 +979,7 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection, { for (pos = connection->headers_received; NULL != pos; pos = pos->next) { - if ( (kind == pos->kind) && + if ( (0 != (kind & pos->kind)) && (key_size == pos->header_size) && ( (key == pos->header) || (MHD_str_equal_caseless_bin_n_ (key, -- cgit v1.2.3 From 5ee6886a3bb3a498ee4116831f5f77f97116d69e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 29 Jul 2019 18:08:50 +0200 Subject: indentation --- src/microhttpd/daemon.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index d3595fe0..b312c305 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c @@ -3041,12 +3041,12 @@ resume_suspended_connections (struct MHD_Daemon *daemon) { /* Wake up suspended connections. */ if (! MHD_itc_activate_(daemon->itc, "w")) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Failed to signal resume of connection via inter-thread communication channel.")); + MHD_DLOG (daemon, + _("Failed to signal resume of connection via inter-thread communication channel.")); #endif - } + } } return ret; } @@ -3081,11 +3081,12 @@ resume_suspended_connections (struct MHD_Daemon *daemon) */ int MHD_add_connection (struct MHD_Daemon *daemon, - MHD_socket client_socket, - const struct sockaddr *addr, - socklen_t addrlen) + MHD_socket client_socket, + const struct sockaddr *addr, + socklen_t addrlen) { bool sk_nonbl; + if (! MHD_socket_nonblocking_ (client_socket)) { #ifdef HAVE_MESSAGES @@ -3116,11 +3117,11 @@ MHD_add_connection (struct MHD_Daemon *daemon, #endif } return internal_add_connection (daemon, - client_socket, - addr, + client_socket, + addr, addrlen, - true, - sk_nonbl); + true, + sk_nonbl); } @@ -3253,9 +3254,9 @@ MHD_accept_connection (struct MHD_Daemon *daemon) #endif (void) internal_add_connection (daemon, s, - addr, + addr, addrlen, - false, + false, sk_nonbl); return MHD_YES; } @@ -3381,7 +3382,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) */ int MHD_get_timeout (struct MHD_Daemon *daemon, - MHD_UNSIGNED_LONG_LONG *timeout) + MHD_UNSIGNED_LONG_LONG *timeout) { time_t earliest_deadline; time_t now; -- cgit v1.2.3 From 1aaff72582b6093f0dcf8c187d125e5fca2d2e8b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 29 Jul 2019 18:13:18 +0200 Subject: is this year --- doc/libmicrohttpd.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/libmicrohttpd.texi b/doc/libmicrohttpd.texi index 6f34d799..4424337f 100644 --- a/doc/libmicrohttpd.texi +++ b/doc/libmicrohttpd.texi @@ -12,7 +12,7 @@ This manual is for GNU libmicrohttpd (version @value{VERSION}, @value{UPDATED}), a library for embedding an HTTP(S) server into C applications. -Copyright @copyright{} 2007--2017 Christian Grothoff +Copyright @copyright{} 2007--2019 Christian Grothoff @quotation Permission is granted to copy, distribute and/or modify this document -- cgit v1.2.3 From 40bf201dc53465be1d2805039ef5963a21e44c08 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 29 Jul 2019 19:23:35 +0200 Subject: indentation fixes, adding test_upgrade_large.c test for issue reported by Viet --- src/microhttpd/.gitignore | 2 + src/microhttpd/Makefile.am | 34 +- src/microhttpd/daemon.c | 167 ++--- src/microhttpd/response.c | 88 +-- src/microhttpd/test_upgrade_large.c | 1353 +++++++++++++++++++++++++++++++++++ 5 files changed, 1513 insertions(+), 131 deletions(-) create mode 100644 src/microhttpd/test_upgrade_large.c diff --git a/src/microhttpd/.gitignore b/src/microhttpd/.gitignore index ec2e027d..611f88ec 100644 --- a/src/microhttpd/.gitignore +++ b/src/microhttpd/.gitignore @@ -57,3 +57,5 @@ test_shutdown_poll test_shutdown_select test_md5 test_sha256 +test_upgrade_large +test_upgrade_large_tls diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am index 3fb65fe1..8bc60879 100644 --- a/src/microhttpd/Makefile.am +++ b/src/microhttpd/Makefile.am @@ -165,17 +165,17 @@ check_PROGRAMS = \ if HAVE_POSIX_THREADS if ENABLE_UPGRADE if USE_POSIX_THREADS - check_PROGRAMS += test_upgrade + check_PROGRAMS += test_upgrade test_upgrade_large endif if USE_W32_THREADS - check_PROGRAMS += test_upgrade + check_PROGRAMS += test_upgrade test_upgrade_large endif if ENABLE_HTTPS if USE_POSIX_THREADS -check_PROGRAMS += test_upgrade_tls +check_PROGRAMS += test_upgrade_tls test_upgrade_large_tls endif if USE_W32_THREADS -check_PROGRAMS += test_upgrade_tls +check_PROGRAMS += test_upgrade_tls test_upgrade_large_tls endif endif endif @@ -230,6 +230,19 @@ test_upgrade_LDADD = \ $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ $(PTHREAD_LIBS) +test_upgrade_large_SOURCES = \ + test_upgrade_large.c test_helpers.h mhd_sockets.h +test_upgrade_large_CPPFLAGS = \ + $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS) +test_upgrade_large_CFLAGS = \ + $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(MHD_TLS_LIB_CFLAGS) +test_upgrade_large_LDFLAGS = \ + $(MHD_TLS_LIB_LDFLAGS) +test_upgrade_large_LDADD = \ + $(top_builddir)/src/microhttpd/libmicrohttpd.la \ + $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ + $(PTHREAD_LIBS) + test_upgrade_tls_SOURCES = \ test_upgrade.c test_helpers.h mhd_sockets.h test_upgrade_tls_CPPFLAGS = \ @@ -243,6 +256,19 @@ test_upgrade_tls_LDADD = \ $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ $(PTHREAD_LIBS) +test_upgrade_large_tls_SOURCES = \ + test_upgrade_large.c test_helpers.h mhd_sockets.h +test_upgrade_large_tls_CPPFLAGS = \ + $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS) +test_upgrade_large_tls_CFLAGS = \ + $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(MHD_TLS_LIB_CFLAGS) +test_upgrade_large_tls_LDFLAGS = \ + $(MHD_TLS_LIB_LDFLAGS) +test_upgrade_large_tls_LDADD = \ + $(top_builddir)/src/microhttpd/libmicrohttpd.la \ + $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) \ + $(PTHREAD_LIBS) + test_postprocessor_SOURCES = \ test_postprocessor.c test_postprocessor_CPPFLAGS = \ diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index b312c305..3fc992de 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c @@ -4178,28 +4178,29 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) struct MHD_UpgradeResponseHandle * prev; num_events = MAX_EVENTS; - while (MAX_EVENTS == num_events) + while (0 != num_events) { unsigned int i; /* update event masks */ num_events = epoll_wait (daemon->epoll_upgrade_fd, - events, + events, MAX_EVENTS, 0); if (-1 == num_events) - { + { const int err = MHD_socket_get_error_ (); + if (MHD_SCKT_ERR_IS_EINTR_ (err)) - return MHD_YES; + return MHD_YES; #ifdef HAVE_MESSAGES MHD_DLOG (daemon, _("Call to epoll_wait failed: %s\n"), MHD_socket_strerr_ (err)); #endif - return MHD_NO; - } + return MHD_NO; + } for (i = 0; i < (unsigned int) num_events; i++) - { + { struct UpgradeEpollHandle * const ueh = events[i].data.ptr; struct MHD_UpgradeResponseHandle * const urh = ueh->urh; bool new_err_state = false; @@ -4217,24 +4218,24 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) if ( (0 == (ueh->celi & MHD_EPOLL_STATE_ERROR)) && (0 != (events[i].events & (EPOLLERR | EPOLLPRI))) ) - { + { /* Process new error state only one time * and avoid continuously marking this connection * as 'ready'. */ ueh->celi |= MHD_EPOLL_STATE_ERROR; new_err_state = true; - } + } if (! urh->in_eready_list) { if (new_err_state || - is_urh_ready(urh)) - { - EDLL_insert (daemon->eready_urh_head, - daemon->eready_urh_tail, - urh); - urh->in_eready_list = true; - } + is_urh_ready(urh)) + { + EDLL_insert (daemon->eready_urh_head, + daemon->eready_urh_tail, + urh); + urh->in_eready_list = true; + } } } } @@ -4246,8 +4247,8 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) if (! is_urh_ready(pos)) { EDLL_remove (daemon->eready_urh_head, - daemon->eready_urh_tail, - pos); + daemon->eready_urh_tail, + pos); pos->in_eready_list = false; } /* Finished forwarding? */ @@ -4287,7 +4288,7 @@ static const char * const epoll_itc_marker = "itc_marker"; */ static int MHD_epoll (struct MHD_Daemon *daemon, - int may_block) + int may_block) { #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) static const char * const upgrade_marker = "upgrade_ptr"; @@ -4302,7 +4303,7 @@ MHD_epoll (struct MHD_Daemon *daemon, unsigned int i; MHD_socket ls; #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) - int run_upgraded = MHD_NO; + bool run_upgraded = false; #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ if (-1 == daemon->epoll_fd) @@ -4318,31 +4319,31 @@ MHD_epoll (struct MHD_Daemon *daemon, event.events = EPOLLIN; event.data.ptr = daemon; if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_ADD, - ls, - &event)) - { + EPOLL_CTL_ADD, + ls, + &event)) + { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, _("Call to epoll_ctl failed: %s\n"), MHD_socket_last_strerr_ ()); #endif - return MHD_NO; - } + return MHD_NO; + } daemon->listen_socket_in_epoll = true; } if ( (daemon->was_quiesced) && (daemon->listen_socket_in_epoll) ) - { - if ( (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_DEL, - ls, - NULL)) && - (ENOENT != errno) ) /* ENOENT can happen due to race with - #MHD_quiesce_daemon() */ - MHD_PANIC ("Failed to remove listen FD from epoll set\n"); - daemon->listen_socket_in_epoll = false; - } + { + if ( (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_DEL, + ls, + NULL)) && + (ENOENT != errno) ) /* ENOENT can happen due to race with + #MHD_quiesce_daemon() */ + MHD_PANIC ("Failed to remove listen FD from epoll set\n"); + daemon->listen_socket_in_epoll = false; + } #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) if ( (! daemon->upgrade_fd_in_epoll) && @@ -4351,17 +4352,17 @@ MHD_epoll (struct MHD_Daemon *daemon, event.events = EPOLLIN | EPOLLOUT; event.data.ptr = (void *) upgrade_marker; if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_ADD, - daemon->epoll_upgrade_fd, - &event)) - { + EPOLL_CTL_ADD, + daemon->epoll_upgrade_fd, + &event)) + { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, _("Call to epoll_ctl failed: %s\n"), MHD_socket_last_strerr_ ()); #endif - return MHD_NO; - } + return MHD_NO; + } daemon->upgrade_fd_in_epoll = true; } #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ @@ -4373,10 +4374,10 @@ MHD_epoll (struct MHD_Daemon *daemon, /* we're at the connection limit, disable listen socket for event loop for now */ if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_DEL, - ls, - NULL)) - MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); + EPOLL_CTL_DEL, + ls, + NULL)) + MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); daemon->listen_socket_in_epoll = false; } @@ -4388,14 +4389,14 @@ MHD_epoll (struct MHD_Daemon *daemon, { if (MHD_YES == MHD_get_timeout (daemon, &timeout_ll)) - { - if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX) - timeout_ms = INT_MAX; - else - timeout_ms = (int) timeout_ll; - } + { + if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX) + timeout_ms = INT_MAX; + else + timeout_ms = (int) timeout_ll; + } else - timeout_ms = -1; + timeout_ms = -1; } else timeout_ms = 0; @@ -4414,33 +4415,33 @@ MHD_epoll (struct MHD_Daemon *daemon, { /* update event masks */ num_events = epoll_wait (daemon->epoll_fd, - events, + events, MAX_EVENTS, timeout_ms); if (-1 == num_events) - { + { const int err = MHD_socket_get_error_ (); if (MHD_SCKT_ERR_IS_EINTR_ (err)) - return MHD_YES; + return MHD_YES; #ifdef HAVE_MESSAGES MHD_DLOG (daemon, _("Call to epoll_wait failed: %s\n"), MHD_socket_strerr_ (err)); #endif - return MHD_NO; - } + return MHD_NO; + } for (i=0;i<(unsigned int) num_events;i++) - { + { /* First, check for the values of `ptr` that would indicate that this event is not about a normal connection. */ - if (NULL == events[i].data.ptr) - continue; /* shutdown signal! */ + if (NULL == events[i].data.ptr) + continue; /* shutdown signal! */ #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) if (upgrade_marker == events[i].data.ptr) { /* activity on an upgraded connection, we process those in a separate epoll() */ - run_upgraded = MHD_YES; + run_upgraded = true; continue; } #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ @@ -4451,8 +4452,8 @@ MHD_epoll (struct MHD_Daemon *daemon, MHD_itc_clear_ (daemon->itc); continue; } - if (daemon == events[i].data.ptr) - { + if (daemon == events[i].data.ptr) + { /* Check for error conditions on listen socket. */ /* FIXME: Initiate MHD_quiesce_daemon() to prevent busy waiting? */ if (0 == (events[i].events & (EPOLLERR | EPOLLHUP))) @@ -4467,9 +4468,9 @@ MHD_epoll (struct MHD_Daemon *daemon, (daemon->connections < daemon->connection_limit) && (! daemon->at_limit) ) series_length++; - } + } continue; - } + } /* this is an event relating to a 'normal' connection, remember the event and if appropriate mark the connection as 'eready'. */ @@ -4518,7 +4519,7 @@ MHD_epoll (struct MHD_Daemon *daemon, } #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) - if (MHD_YES == run_upgraded) + if (run_upgraded) run_epoll_for_upgrade (daemon); #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ @@ -4606,22 +4607,22 @@ MHD_run (struct MHD_Daemon *daemon) (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) ) return MHD_NO; if (0 != (daemon->options & MHD_USE_POLL)) - { - MHD_poll (daemon, MHD_NO); - MHD_cleanup_connections (daemon); - } + { + MHD_poll (daemon, MHD_NO); + MHD_cleanup_connections (daemon); + } #ifdef EPOLL_SUPPORT else if (0 != (daemon->options & MHD_USE_EPOLL)) - { - MHD_epoll (daemon, MHD_NO); - MHD_cleanup_connections (daemon); - } + { + MHD_epoll (daemon, MHD_NO); + MHD_cleanup_connections (daemon); + } #endif else - { - MHD_select (daemon, MHD_NO); - /* MHD_select does MHD_cleanup_connections already */ - } + { + MHD_select (daemon, MHD_NO); + /* MHD_select does MHD_cleanup_connections already */ + } return MHD_YES; } @@ -6494,10 +6495,10 @@ thread_failed: if (daemon->upgrade_fd_in_epoll) { if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_DEL, - daemon->epoll_upgrade_fd, - NULL)) - MHD_PANIC (_("Failed to remove FD from epoll set\n")); + EPOLL_CTL_DEL, + daemon->epoll_upgrade_fd, + NULL)) + MHD_PANIC (_("Failed to remove FD from epoll set\n")); daemon->upgrade_fd_in_epoll = false; } #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index 035e3054..3e9fb053 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c @@ -80,9 +80,9 @@ */ static int add_response_entry (struct MHD_Response *response, - enum MHD_ValueKind kind, - const char *header, - const char *content) + enum MHD_ValueKind kind, + const char *header, + const char *content) { struct MHD_HTTP_Header *hdr; @@ -195,7 +195,7 @@ MHD_add_response_footer (struct MHD_Response *response, int MHD_del_response_header (struct MHD_Response *response, const char *header, - const char *content) + const char *content) { struct MHD_HTTP_Header *pos; struct MHD_HTTP_Header *prev; @@ -280,7 +280,7 @@ MHD_get_response_headers (struct MHD_Response *response, */ const char * MHD_get_response_header (struct MHD_Response *response, - const char *key) + const char *key) { struct MHD_HTTP_Header *pos; size_t key_size; @@ -558,8 +558,8 @@ free_callback (void *cls) */ struct MHD_Response * MHD_create_response_from_fd_at_offset (size_t size, - int fd, - off_t offset) + int fd, + off_t offset) { return MHD_create_response_from_fd_at_offset64 (size, fd, @@ -627,7 +627,7 @@ MHD_create_response_from_fd_at_offset64 (uint64_t size, */ struct MHD_Response * MHD_create_response_from_fd (size_t size, - int fd) + int fd) { return MHD_create_response_from_fd_at_offset64 (size, fd, @@ -732,8 +732,8 @@ MHD_create_response_from_data (size_t size, */ struct MHD_Response * MHD_create_response_from_buffer (size_t size, - void *buffer, - enum MHD_ResponseMemoryMode mode) + void *buffer, + enum MHD_ResponseMemoryMode mode) { return MHD_create_response_from_data (size, buffer, @@ -754,15 +754,15 @@ MHD_create_response_from_buffer (size_t size, */ _MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_with_free_callback (size_t size, - void *buffer, - MHD_ContentReaderFreeCallback crfc) + void *buffer, + MHD_ContentReaderFreeCallback crfc) { struct MHD_Response *r; r = MHD_create_response_from_data (size, - buffer, - MHD_YES, - MHD_NO); + buffer, + MHD_YES, + MHD_NO); if (NULL == r) return r; r->crfc = crfc; @@ -997,17 +997,17 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, EPOLL_CTL_ADD, connection->socket_fd, &event)) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Call to epoll_ctl failed: %s\n"), - MHD_socket_last_strerr_ ()); + MHD_DLOG (daemon, + _("Call to epoll_ctl failed: %s\n"), + MHD_socket_last_strerr_ ()); #endif - MHD_socket_close_chk_ (sv[0]); - MHD_socket_close_chk_ (sv[1]); - free (urh); - return MHD_NO; - } + MHD_socket_close_chk_ (sv[0]); + MHD_socket_close_chk_ (sv[1]); + free (urh); + return MHD_NO; + } /* Second, add our end of the UNIX socketpair() */ event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; @@ -1016,28 +1016,28 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, EPOLL_CTL_ADD, urh->mhd.socket, &event)) - { - event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; - event.data.ptr = &urh->app; - if (0 != epoll_ctl (daemon->epoll_upgrade_fd, - EPOLL_CTL_DEL, - connection->socket_fd, - &event)) - MHD_PANIC (_("Error cleaning up while handling epoll error")); + { + event.events = EPOLLIN | EPOLLOUT | EPOLLPRI; + event.data.ptr = &urh->app; + if (0 != epoll_ctl (daemon->epoll_upgrade_fd, + EPOLL_CTL_DEL, + connection->socket_fd, + &event)) + MHD_PANIC (_("Error cleaning up while handling epoll error")); #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Call to epoll_ctl failed: %s\n"), - MHD_socket_last_strerr_ ()); + MHD_DLOG (daemon, + _("Call to epoll_ctl failed: %s\n"), + MHD_socket_last_strerr_ ()); #endif - MHD_socket_close_chk_ (sv[0]); - MHD_socket_close_chk_ (sv[1]); - free (urh); - return MHD_NO; - } - EDLL_insert (daemon->eready_urh_head, - daemon->eready_urh_tail, - urh); - urh->in_eready_list = true; + MHD_socket_close_chk_ (sv[0]); + MHD_socket_close_chk_ (sv[1]); + free (urh); + return MHD_NO; + } + EDLL_insert (daemon->eready_urh_head, + daemon->eready_urh_tail, + urh); + urh->in_eready_list = true; } #endif /* EPOLL_SUPPORT */ if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) diff --git a/src/microhttpd/test_upgrade_large.c b/src/microhttpd/test_upgrade_large.c new file mode 100644 index 00000000..fdf2edf7 --- /dev/null +++ b/src/microhttpd/test_upgrade_large.c @@ -0,0 +1,1353 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2016, 2019 Christian Grothoff + + libmicrohttpd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + libmicrohttpd 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file test_upgrade_large.c + * @brief Testcase for libmicrohttpd upgrading a connection, + * modified to test the "large" corner case reported + * by Viet on the mailinglist in 6'2019 + * @author Christian Grothoff + * @author Karlson2k (Evgeny Grin) + */ + +#include "mhd_options.h" +#include +#include +#include +#include +#include +#include +#ifndef WINDOWS +#include +#endif +#ifdef HAVE_STDBOOL_H +#include +#endif /* HAVE_STDBOOL_H */ + +#include "mhd_sockets.h" +#ifdef HAVE_NETINET_IP_H +#include +#endif /* HAVE_NETINET_IP_H */ + +#include "platform.h" +#include "microhttpd.h" + +#include "test_helpers.h" + +#define LARGE_STRING "HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello" + +#define LARGE_REPLY_STRING "WorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorldWorld" + +#ifdef HTTPS_SUPPORT +#include +#include "../testcurl/https/tls_test_keys.h" + +#if defined(HAVE_FORK) && defined(HAVE_WAITPID) +#include +#include +#endif /* HAVE_FORK && HAVE_WAITPID */ +#endif /* HTTPS_SUPPORT */ + +static int verbose = 0; + +enum tls_tool +{ + TLS_CLI_NO_TOOL = 0, + TLS_CLI_GNUTLS, + TLS_CLI_OPENSSL, + TLS_LIB_GNUTLS +}; + +enum tls_tool use_tls_tool; + +#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) +/** + * Fork child that connects via GnuTLS-CLI to our @a port. Allows us to + * talk to our port over a socket in @a sp without having to worry + * about TLS. + * + * @param location where the socket is returned + * @return -1 on error, otherwise PID of TLS child process + */ +static pid_t +gnutlscli_connect (int *sock, + uint16_t port) +{ + pid_t chld; + int sp[2]; + char destination[30]; + + if (0 != socketpair (AF_UNIX, + SOCK_STREAM, + 0, + sp)) + return -1; + chld = fork (); + if (0 != chld) + { + *sock = sp[1]; + MHD_socket_close_chk_ (sp[0]); + return chld; + } + MHD_socket_close_chk_ (sp[1]); + (void) close (0); + (void) close (1); + if (-1 == dup2 (sp[0], 0)) + abort (); + if (-1 == dup2 (sp[0], 1)) + abort (); + MHD_socket_close_chk_ (sp[0]); + if (TLS_CLI_GNUTLS == use_tls_tool) + { + snprintf (destination, + sizeof(destination), + "%u", + (unsigned int) port); + execlp ("gnutls-cli", + "gnutls-cli", + "--insecure", + "-p", + destination, + "127.0.0.1", + (char *) NULL); + } + else if (TLS_CLI_OPENSSL == use_tls_tool) + { + snprintf (destination, + sizeof(destination), + "127.0.0.1:%u", + (unsigned int) port); + execlp ("openssl", + "openssl", + "s_client", + "-connect", + destination, + "-verify", + "1", + (char *) NULL); + } + _exit (1); +} +#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ + + +/** + * Wrapper structure for plain&TLS sockets + */ +struct wr_socket +{ + /** + * Real network socket + */ + MHD_socket fd; + + /** + * Type of this socket + */ + enum wr_type + { + wr_invalid = 0, + wr_plain = 1, + wr_tls = 2 + } t; +#ifdef HTTPS_SUPPORT + /** + * TLS credentials + */ + gnutls_certificate_credentials_t tls_crd; + + /** + * TLS session. + */ + gnutls_session_t tls_s; + + /** + * TLS handshake already succeed? + */ + bool tls_connected; +#endif +}; + + +/** + * Get underlying real socket. + * @return FD of real socket + */ +#define wr_fd(s) ((s)->fd) + + +/** + * Create wr_socket with plain TCP underlying socket + * @return created socket on success, NULL otherwise + */ +static struct wr_socket * +wr_create_plain_sckt(void) +{ + struct wr_socket *s = malloc(sizeof(struct wr_socket)); + if (NULL == s) + return NULL; + s->t = wr_plain; + s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (MHD_INVALID_SOCKET != s->fd) + return s; + free(s); + return NULL; +} + + +/** + * Create wr_socket with TLS TCP underlying socket + * @return created socket on success, NULL otherwise + */ +static struct wr_socket * +wr_create_tls_sckt(void) +{ +#ifdef HTTPS_SUPPORT + struct wr_socket *s = malloc(sizeof(struct wr_socket)); + if (NULL == s) + return NULL; + s->t = wr_tls; + s->tls_connected = 0; + s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (MHD_INVALID_SOCKET != s->fd) + { + if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT)) + { + if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s)) + { + if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials (&(s->tls_crd))) + { + if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, GNUTLS_CRD_CERTIFICATE, s->tls_crd)) + { +#if GNUTLS_VERSION_NUMBER+0 >= 0x030109 + gnutls_transport_set_int (s->tls_s, (int)(s->fd)); +#else /* GnuTLS before 3.1.9 */ + gnutls_transport_set_ptr (s->tls_s, (gnutls_transport_ptr_t)(intptr_t)(s->fd)); +#endif /* GnuTLS before 3.1.9 */ + return s; + } + gnutls_certificate_free_credentials (s->tls_crd); + } + } + gnutls_deinit (s->tls_s); + } + (void)MHD_socket_close_ (s->fd); + } + free(s); +#endif /* HTTPS_SUPPORT */ + return NULL; +} + + +/** + * Create wr_socket with plain TCP underlying socket + * from already created TCP socket. + * @param plain_sk real TCP socket + * @return created socket on success, NULL otherwise + */ +static struct wr_socket * +wr_create_from_plain_sckt(MHD_socket plain_sk) +{ + struct wr_socket *s = malloc(sizeof(struct wr_socket)); + + if (NULL == s) + return NULL; + s->t = wr_plain; + s->fd = plain_sk; + return s; +} + + +/** + * Connect socket to specified address. + * @param s socket to use + * @param addr address to connect + * @param length of sturcture pointed by @a addr + * @return zero on success, -1 otherwise. + */ +static int +wr_connect(struct wr_socket *s, + const struct sockaddr *addr, + int length) +{ + if (0 != connect (s->fd, addr, length)) + return -1; + if (wr_plain == s->t) + return 0; +#ifdef HTTPS_SUPPORT + if (wr_tls == s->t) + { + /* Do not try handshake here as + * it require processing on MHD side and + * when testing with "external" polling, + * test will call MHD processing only + * after return from wr_connect(). */ + s->tls_connected = 0; + return 0; + } +#endif /* HTTPS_SUPPORT */ + return -1; +} + +#ifdef HTTPS_SUPPORT +/* Only to be called from wr_send() and wr_recv() ! */ +static bool +wr_handshake(struct wr_socket *s) +{ + int res = gnutls_handshake (s->tls_s); + if (GNUTLS_E_SUCCESS == res) + s->tls_connected = true; + else if (GNUTLS_E_AGAIN == res) + MHD_socket_set_error_ (MHD_SCKT_EAGAIN_); + else + MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ + return s->tls_connected; +} +#endif /* HTTPS_SUPPORT */ + + +/** + * Send data to remote by socket. + * @param s the socket to use + * @param buf the buffer with data to send + * @param len the length of data in @a buf + * @return number of bytes were sent if succeed, + * -1 if failed. Use #MHD_socket_get_error_() + * to get socket error. + */ +static ssize_t +wr_send (struct wr_socket *s, + const void *buf, + size_t len) +{ + if (wr_plain == s->t) + return MHD_send_(s->fd, buf, len); +#ifdef HTTPS_SUPPORT + if (wr_tls == s->t) + { + ssize_t ret; + if (!s->tls_connected && !wr_handshake (s)) + return -1; + + ret = gnutls_record_send (s->tls_s, buf, len); + if (ret > 0) + return ret; + if (GNUTLS_E_AGAIN == ret) + MHD_socket_set_error_ (MHD_SCKT_EAGAIN_); + else + MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ + } +#endif /* HTTPS_SUPPORT */ + return -1; +} + + +/** + * Receive data from remote by socket. + * @param s the socket to use + * @param buf the buffer to store received data + * @param len the length of @a buf + * @return number of bytes were received if succeed, + * -1 if failed. Use #MHD_socket_get_error_() + * to get socket error. + */ +static ssize_t +wr_recv (struct wr_socket *s, + void *buf, + size_t len) +{ + if (wr_plain == s->t) + return MHD_recv_ (s->fd, buf, len); +#ifdef HTTPS_SUPPORT + if (wr_tls == s->t) + { + ssize_t ret; + if (!s->tls_connected && !wr_handshake (s)) + return -1; + + ret = gnutls_record_recv (s->tls_s, buf, len); + if (ret > 0) + return ret; + if (GNUTLS_E_AGAIN == ret) + MHD_socket_set_error_ (MHD_SCKT_EAGAIN_); + else + MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ + } +#endif /* HTTPS_SUPPORT */ + return -1; +} + + +/** + * Close socket and release allocated resourced + * @param s the socket to close + * @return zero on succeed, -1 otherwise + */ +static int +wr_close (struct wr_socket *s) +{ + int ret = (MHD_socket_close_(s->fd)) ? 0 : -1; +#ifdef HTTPS_SUPPORT + if (wr_tls == s->t) + { + gnutls_deinit (s->tls_s); + gnutls_certificate_free_credentials (s->tls_crd); + } +#endif /* HTTPS_SUPPORT */ + free (s); + return ret; +} + + +/** + * Thread we use to run the interaction with the upgraded socket. + */ +static pthread_t pt; + +/** + * Will be set to the upgraded socket. + */ +static struct wr_socket *usock; + +/** + * Thread we use to run the interaction with the upgraded socket. + */ +static pthread_t pt_client; + +/** + * Flag set to 1 once the test is finished. + */ +static volatile bool done; + + +/** + * Callback used by MHD to notify the application about completed + * requests. Frees memory. + * + * @param cls client-defined closure + * @param connection connection handle + * @param con_cls value as set by the last call to + * the #MHD_AccessHandlerCallback + * @param toe reason for request termination + */ +static void +notify_completed_cb (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + pthread_t* ppth = *con_cls; + + (void) cls; + (void) connection; /* Unused. Silent compiler warning. */ + if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) && + (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) && + (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) ) + abort (); + if (! pthread_equal (**((pthread_t**)con_cls), + pthread_self ())) + abort (); + if (NULL != ppth) + free (*con_cls); + *con_cls = NULL; +} + + +/** + * Logging callback. + * + * @param cls logging closure (NULL) + * @param uri access URI + * @param connection connection handle + * @return #TEST_PTR + */ +static void * +log_cb (void *cls, + const char *uri, + struct MHD_Connection *connection) +{ + pthread_t *ppth; + + (void) cls; + (void) connection; /* Unused. Silent compiler warning. */ + if (0 != strcmp (uri, + "/")) + abort (); + ppth = malloc (sizeof (pthread_t)); + if (NULL == ppth) + abort(); + *ppth = pthread_self (); + return (void *) ppth; +} + + +/** + * Function to check that MHD properly notifies about starting + * and stopping. + * + * @param cls client-defined closure + * @param connection connection handle + * @param socket_context socket-specific pointer where the + * client can associate some state specific + * to the TCP connection; note that this is + * different from the "con_cls" which is per + * HTTP request. The client can initialize + * during #MHD_CONNECTION_NOTIFY_STARTED and + * cleanup during #MHD_CONNECTION_NOTIFY_CLOSED + * and access in the meantime using + * #MHD_CONNECTION_INFO_SOCKET_CONTEXT. + * @param toe reason for connection notification + * @see #MHD_OPTION_NOTIFY_CONNECTION + * @ingroup request + */ +static void +notify_connection_cb (void *cls, + struct MHD_Connection *connection, + void **socket_context, + enum MHD_ConnectionNotificationCode toe) +{ + static int started; + + (void) cls; + (void) connection; /* Unused. Silent compiler warning. */ + switch (toe) + { + case MHD_CONNECTION_NOTIFY_STARTED: + if (MHD_NO != started) + abort (); + started = MHD_YES; + *socket_context = &started; + break; + case MHD_CONNECTION_NOTIFY_CLOSED: + if (MHD_YES != started) + abort (); + if (&started != *socket_context) + abort (); + *socket_context = NULL; + started = MHD_NO; + break; + } +} + + +/** + * Change socket to blocking. + * + * @param fd the socket to manipulate + * @return non-zero if succeeded, zero otherwise + */ +static void +make_blocking (MHD_socket fd) +{ +#if defined(MHD_POSIX_SOCKETS) + int flags; + + flags = fcntl (fd, F_GETFL); + if (-1 == flags) + return; + if ((flags & ~O_NONBLOCK) != flags) + if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK)) + abort (); +#elif defined(MHD_WINSOCK_SOCKETS) + unsigned long flags = 1; + + ioctlsocket (fd, FIONBIO, &flags); +#endif /* MHD_WINSOCK_SOCKETS */ + +} + + +static void +send_all (struct wr_socket *sock, + const char *text) +{ + size_t len = strlen (text); + ssize_t ret; + size_t off; + + make_blocking (wr_fd (sock)); + for (off = 0; off < len; off += ret) + { + ret = wr_send (sock, + &text[off], + len - off); + if (0 > ret) + { + if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) + { + ret = 0; + continue; + } + abort (); + } + } +} + + +/** + * Read character-by-character until we + * get '\r\n\r\n'. + */ +static void +recv_hdr (struct wr_socket *sock) +{ + unsigned int i; + char next; + char c; + ssize_t ret; + + make_blocking (wr_fd (sock)); + next = '\r'; + i = 0; + while (i < 4) + { + ret = wr_recv (sock, + &c, + 1); + if (0 > ret) + { + if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) + continue; + abort (); + } + if (0 == ret) + continue; + if (c == next) + { + i++; + if (next == '\r') + next = '\n'; + else + next = '\r'; + continue; + } + if (c == '\r') + { + i = 1; + next = '\n'; + continue; + } + i = 0; + next = '\r'; + } +} + + +static void +recv_all (struct wr_socket *sock, + const char *text) +{ + size_t len = strlen (text); + char buf[len]; + ssize_t ret; + size_t off; + + make_blocking (wr_fd (sock)); + for (off = 0; off < len; off += ret) + { + ret = wr_recv (sock, + &buf[off], + len - off); + if (0 > ret) + { + if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) + { + ret = 0; + continue; + } + abort (); + } + } + if (0 != strncmp (text, buf, len)) + abort(); +} + + +/** + * Main function for the thread that runs the interaction with + * the upgraded socket. + * + * @param cls the handle for the upgrade + */ +static void * +run_usock (void *cls) +{ + struct MHD_UpgradeResponseHandle *urh = cls; + + send_all (usock, + LARGE_STRING); + recv_all (usock, + LARGE_REPLY_STRING); + send_all (usock, + "Finished"); + MHD_upgrade_action (urh, + MHD_UPGRADE_ACTION_CLOSE); + free (usock); + usock = NULL; + return NULL; +} + + +/** + * Main function for the thread that runs the client-side of the + * interaction with the upgraded socket. + * + * @param cls the client socket + */ +static void * +run_usock_client (void *cls) +{ + struct wr_socket *sock = cls; + + send_all (sock, + "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n"); + recv_hdr (sock); + recv_all (sock, + LARGE_STRING); + send_all (sock, + LARGE_REPLY_STRING); + recv_all (sock, + "Finished"); + wr_close (sock); + done = true; + return NULL; +} + + +/** + * Function called after a protocol "upgrade" response was sent + * successfully and the socket should now be controlled by some + * protocol other than HTTP. + * + * Any data already received on the socket will be made available in + * @e extra_in. This can happen if the application sent extra data + * before MHD send the upgrade response. The application should + * treat data from @a extra_in as if it had read it from the socket. + * + * Note that the application must not close() @a sock directly, + * but instead use #MHD_upgrade_action() for special operations + * on @a sock. + * + * Except when in 'thread-per-connection' mode, implementations + * of this function should never block (as it will still be called + * from within the main event loop). + * + * @param cls closure, whatever was given to #MHD_create_response_for_upgrade(). + * @param connection original HTTP connection handle, + * giving the function a last chance + * to inspect the original HTTP request + * @param con_cls last value left in `con_cls` of the `MHD_AccessHandlerCallback` + * @param extra_in if we happened to have read bytes after the + * HTTP header already (because the client sent + * more than the HTTP header of the request before + * we sent the upgrade response), + * these are the extra bytes already read from @a sock + * by MHD. The application should treat these as if + * it had read them from @a sock. + * @param extra_in_size number of bytes in @a extra_in + * @param sock socket to use for bi-directional communication + * with the client. For HTTPS, this may not be a socket + * that is directly connected to the client and thus certain + * operations (TCP-specific setsockopt(), getsockopt(), etc.) + * may not work as expected (as the socket could be from a + * socketpair() or a TCP-loopback). The application is expected + * to perform read()/recv() and write()/send() calls on the socket. + * The application may also call shutdown(), but must not call + * close() directly. + * @param urh argument for #MHD_upgrade_action()s on this @a connection. + * Applications must eventually use this callback to (indirectly) + * perform the close() action on the @a sock. + */ +static void +upgrade_cb (void *cls, + struct MHD_Connection *connection, + void *con_cls, + const char *extra_in, + size_t extra_in_size, + MHD_socket sock, + struct MHD_UpgradeResponseHandle *urh) +{ + (void) cls; + (void) connection; + (void) con_cls; + (void) extra_in; /* Unused. Silent compiler warning. */ + + usock = wr_create_from_plain_sckt (sock); + if (0 != extra_in_size) + abort (); + if (0 != pthread_create (&pt, + NULL, + &run_usock, + urh)) + abort (); +} + + +/** + * A client has requested the given url using the given method + * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, + * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback + * must call MHD callbacks to provide content to give back to the + * client and return an HTTP status code (i.e. #MHD_HTTP_OK, + * #MHD_HTTP_NOT_FOUND, etc.). + * + * @param cls argument given together with the function + * pointer when the handler was registered with MHD + * @param url the requested url + * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, + * #MHD_HTTP_METHOD_PUT, etc.) + * @param version the HTTP version string (i.e. + * #MHD_HTTP_VERSION_1_1) + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of #MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * @a upload_data) + * @param upload_data_size set initially to the size of the + * @a upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param con_cls pointer that the callback can set to some + * address and that will be preserved by MHD for future + * calls for this request; since the access handler may + * be called many times (i.e., for a PUT/POST operation + * with plenty of upload data) this allows the application + * to easily associate some request-specific state. + * If necessary, this state can be cleaned up in the + * global #MHD_RequestCompletedCallback (which + * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). + * Initially, `*con_cls` will be NULL. + * @return #MHD_YES if the connection was handled successfully, + * #MHD_NO if the socket must be closed due to a serios + * error while handling the request + */ +static int +ahc_upgrade (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + struct MHD_Response *resp; + int ret; + (void) cls; + (void) url; + (void) method; /* Unused. Silent compiler warning. */ + (void) version; + (void) upload_data; + (void) upload_data_size; /* Unused. Silent compiler warning. */ + + if (NULL == *con_cls) + abort (); + if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ())) + abort (); + resp = MHD_create_response_for_upgrade (&upgrade_cb, + NULL); + MHD_add_response_header (resp, + MHD_HTTP_HEADER_UPGRADE, + "Hello World Protocol"); + ret = MHD_queue_response (connection, + MHD_HTTP_SWITCHING_PROTOCOLS, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** + * Run the MHD external event loop using select. + * + * @param daemon daemon to run it for + */ +static void +run_mhd_select_loop (struct MHD_Daemon *daemon) +{ + fd_set rs; + fd_set ws; + fd_set es; + MHD_socket max_fd; + MHD_UNSIGNED_LONG_LONG to; + struct timeval tv; + + while (! done) + { + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + max_fd = -1; + to = 1000; + + if (MHD_YES != + MHD_get_fdset (daemon, + &rs, + &ws, + &es, + &max_fd)) + abort (); + (void) MHD_get_timeout (daemon, + &to); + if (1000 < to) + to = 1000; + tv.tv_sec = to / 1000; + tv.tv_usec = 1000 * (to % 1000); + if (0 > MHD_SYS_select_ (max_fd + 1, + &rs, + &ws, + &es, + &tv)) + abort (); + MHD_run_from_select (daemon, + &rs, + &ws, + &es); + } +} + +#ifdef HAVE_POLL + +/** + * Run the MHD external event loop using select. + * + * @param daemon daemon to run it for + */ +static void +run_mhd_poll_loop (struct MHD_Daemon *daemon) +{ + (void)daemon; /* Unused. Silent compiler warning. */ + abort (); /* currently not implementable with existing MHD API */ +} +#endif /* HAVE_POLL */ + + +#ifdef EPOLL_SUPPORT +/** + * Run the MHD external event loop using select. + * + * @param daemon daemon to run it for + */ +static void +run_mhd_epoll_loop (struct MHD_Daemon *daemon) +{ + const union MHD_DaemonInfo *di; + MHD_socket ep; + fd_set rs; + MHD_UNSIGNED_LONG_LONG to; + struct timeval tv; + int ret; + + di = MHD_get_daemon_info (daemon, + MHD_DAEMON_INFO_EPOLL_FD); + ep = di->listen_fd; + while (! done) + { + FD_ZERO (&rs); + to = 1000; + + FD_SET (ep, &rs); + (void) MHD_get_timeout (daemon, + &to); + if (1000 < to) + to = 1000; + tv.tv_sec = to / 1000; + tv.tv_usec = 1000 * (to % 1000); + ret = select (ep + 1, + &rs, + NULL, + NULL, + &tv); + if ( (-1 == ret) && + (EAGAIN != errno) && + (EINTR != errno) ) + abort (); + MHD_run (daemon); + } +} +#endif /* EPOLL_SUPPORT */ + +/** + * Run the MHD external event loop using select. + * + * @param daemon daemon to run it for + */ +static void +run_mhd_loop (struct MHD_Daemon *daemon, + int flags) +{ + if (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL))) + run_mhd_select_loop (daemon); +#ifdef HAVE_POLL + else if (0 != (flags & MHD_USE_POLL)) + run_mhd_poll_loop (daemon); +#endif /* HAVE_POLL */ +#if EPOLL_SUPPORT + else if (0 != (flags & MHD_USE_EPOLL)) + run_mhd_epoll_loop (daemon); +#endif + else + abort (); +} + + +static bool test_tls; + +/** + * Test upgrading a connection. + * + * @param flags which event loop style should be tested + * @param pool size of the thread pool, 0 to disable + */ +static int +test_upgrade (int flags, + unsigned int pool) +{ + struct MHD_Daemon *d = NULL; + struct wr_socket *sock; + struct sockaddr_in sa; + const union MHD_DaemonInfo *real_flags; + const union MHD_DaemonInfo *dinfo; +#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) + pid_t pid = -1; +#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ + + done = false; + + if (! test_tls) + d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE, + MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ? + 0 : 1090, + NULL, NULL, + &ahc_upgrade, NULL, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, 512, + MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, + MHD_OPTION_NOTIFY_COMPLETED, ¬ify_completed_cb, NULL, + MHD_OPTION_NOTIFY_CONNECTION, ¬ify_connection_cb, NULL, + MHD_OPTION_THREAD_POOL_SIZE, pool, + MHD_OPTION_END); +#ifdef HTTPS_SUPPORT + else + d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE | MHD_USE_TLS, + MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ? + 0 : 1090, + NULL, NULL, + &ahc_upgrade, NULL, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, 512, + MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, + MHD_OPTION_NOTIFY_COMPLETED, ¬ify_completed_cb, NULL, + MHD_OPTION_NOTIFY_CONNECTION, ¬ify_connection_cb, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem, + MHD_OPTION_THREAD_POOL_SIZE, pool, + MHD_OPTION_END); +#endif /* HTTPS_SUPPORT */ + if (NULL == d) + return 2; + real_flags = MHD_get_daemon_info (d, + MHD_DAEMON_INFO_FLAGS); + if (NULL == real_flags) + abort (); + dinfo = MHD_get_daemon_info (d, + MHD_DAEMON_INFO_BIND_PORT); + if ( (NULL == dinfo) || + (0 == dinfo->port) ) + abort (); + if (!test_tls || TLS_LIB_GNUTLS == use_tls_tool) + { + sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt (); + if (NULL == sock) + abort (); + sa.sin_family = AF_INET; + sa.sin_port = htons (dinfo->port); + sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (0 != wr_connect (sock, + (struct sockaddr *) &sa, + sizeof (sa))) + abort (); + } + else + { +#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) + MHD_socket tls_fork_sock; + uint16_t port; + + /* make address sanitizer happy */ + memcpy (&port, + dinfo /* ->port */, + sizeof (port)); + if (-1 == (pid = gnutlscli_connect (&tls_fork_sock, + port))) + { + MHD_stop_daemon (d); + return 4; + } + + sock = wr_create_from_plain_sckt (tls_fork_sock); + if (NULL == sock) + abort (); +#else /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */ + abort (); +#endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */ + } + + if (0 != pthread_create (&pt_client, + NULL, + &run_usock_client, + sock)) + abort (); + if (0 == (flags & MHD_USE_INTERNAL_POLLING_THREAD) ) + { + enum MHD_FLAG flags; + + /* make address sanitizer happy */ + memcpy (&flags, + real_flags /* ->flags */, + sizeof (flags)); + run_mhd_loop (d, flags); + } + pthread_join (pt_client, + NULL); + pthread_join (pt, + NULL); +#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) + if (test_tls && TLS_LIB_GNUTLS != use_tls_tool) + waitpid (pid, NULL, 0); +#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ + MHD_stop_daemon (d); + return 0; +} + + +int +main (int argc, + char *const *argv) +{ + int error_count = 0; + int res; + + use_tls_tool = TLS_CLI_NO_TOOL; + test_tls = has_in_name(argv[0], "_tls"); + + verbose = 1; + if (has_param(argc, argv, "-q") || + has_param(argc, argv, "--quiet")) + verbose = 0; + + if (test_tls) + { +#ifdef HTTPS_SUPPORT + if (has_param(argc, argv, "--use-gnutls-cli")) + use_tls_tool = TLS_CLI_GNUTLS; + else if (has_param(argc, argv, "--use-openssl")) + use_tls_tool = TLS_CLI_OPENSSL; + else if (has_param(argc, argv, "--use-gnutls-lib")) + use_tls_tool = TLS_LIB_GNUTLS; +#if defined(HAVE_FORK) && defined(HAVE_WAITPID) + else if (0 == system ("gnutls-cli --version 1> /dev/null 2> /dev/null")) + use_tls_tool = TLS_CLI_GNUTLS; + else if (0 == system ("openssl version 1> /dev/null 2> /dev/null")) + use_tls_tool = TLS_CLI_OPENSSL; +#endif /* HAVE_FORK && HAVE_WAITPID */ + else + use_tls_tool = TLS_LIB_GNUTLS; /* Should be available as MHD use it. */ + if (verbose) + { + switch (use_tls_tool) + { + case TLS_CLI_GNUTLS: + printf ("GnuTLS-CLI will be used for testing.\n"); + break; + case TLS_CLI_OPENSSL: + printf ("Command line version of OpenSSL will be used for testing.\n"); + break; + case TLS_LIB_GNUTLS: + printf ("GnuTLS library will be used for testing.\n"); + break; + default: + abort (); + } + } + if ( (TLS_LIB_GNUTLS == use_tls_tool) && + (GNUTLS_E_SUCCESS != gnutls_global_init()) ) + abort (); + +#else /* ! HTTPS_SUPPORT */ + fprintf (stderr, "HTTPS support was disabled by configure.\n"); + return 77; +#endif /* ! HTTPS_SUPPORT */ + } + + /* run tests */ + if (verbose) + printf ("Starting HTTP \"Upgrade\" tests with %s connections.\n", + test_tls ? "TLS" : "plain"); + /* try external select */ + res = test_upgrade (0, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with external select, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with external select.\n"); + + /* Try external auto */ + res = test_upgrade (MHD_USE_AUTO, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with external 'auto', return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with external 'auto'.\n"); + +#ifdef EPOLL_SUPPORT + res = test_upgrade (MHD_USE_EPOLL, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with external select with EPOLL, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with external select with EPOLL.\n"); +#endif + + /* Test thread-per-connection */ + res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with thread per connection, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with thread per connection.\n"); + + res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with thread per connection and 'auto', return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with thread per connection and 'auto'.\n"); +#ifdef HAVE_POLL + res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with thread per connection and poll, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with thread per connection and poll.\n"); +#endif /* HAVE_POLL */ + + /* Test different event loops, with and without thread pool */ + res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal select, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal select.\n"); + res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD, + 2); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal select with thread pool, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal select with thread pool.\n"); + res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal 'auto' return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal 'auto'.\n"); + res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, + 2); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal 'auto' with thread pool, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal 'auto' with thread pool.\n"); +#ifdef HAVE_POLL + res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD, + 0); + error_count += res; + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal poll, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal poll.\n"); + res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD, + 2); + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal poll with thread pool, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal poll with thread pool.\n"); +#endif +#ifdef EPOLL_SUPPORT + res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD, + 0); + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal epoll, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal epoll.\n"); + res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD, + 2); + if (res) + fprintf (stderr, + "FAILED: Upgrade with internal epoll, return code %d.\n", + res); + else if (verbose) + printf ("PASSED: Upgrade with internal epoll.\n"); +#endif + /* report result */ + if (0 != error_count) + fprintf (stderr, + "Error (code: %u)\n", + error_count); +#ifdef HTTPS_SUPPORT + if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool)) + gnutls_global_deinit(); +#endif /* HTTPS_SUPPORT */ + return error_count != 0; /* 0 == pass */ +} -- cgit v1.2.3 From 9c15b24f596dfd7374d8909a254ec2df76366300 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 29 Jul 2019 20:00:58 +0200 Subject: ensure event loop keeps going in test, and indentation fixes --- src/microhttpd/daemon.c | 114 ++++++++++++++++++------------------ src/microhttpd/test_upgrade_large.c | 39 +++++++++++- 2 files changed, 93 insertions(+), 60 deletions(-) diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 3fc992de..7ce0fbb3 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c @@ -721,8 +721,8 @@ int MHD_get_fdset (struct MHD_Daemon *daemon, fd_set *read_fd_set, fd_set *write_fd_set, - fd_set *except_fd_set, - MHD_socket *max_fd) + fd_set *except_fd_set, + MHD_socket *max_fd) { return MHD_get_fdset2 (daemon, read_fd_set, @@ -2344,11 +2344,11 @@ psk_gnutls_adapter (gnutls_session_t session, */ static int internal_add_connection (struct MHD_Daemon *daemon, - MHD_socket client_socket, - const struct sockaddr *addr, - socklen_t addrlen, - bool external_add, - bool non_blck) + MHD_socket client_socket, + const struct sockaddr *addr, + socklen_t addrlen, + bool external_add, + bool non_blck) { struct MHD_Connection *connection; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) @@ -2362,8 +2362,8 @@ internal_add_connection (struct MHD_Daemon *daemon, if ((external_add) && (NULL != daemon->worker_pool)) { /* have a pool, try to find a pool with capacity; we use the - socket as the initial offset into the pool for load - balancing */ + socket as the initial offset into the pool for load + balancing */ for (i = 0; i < daemon->worker_pool_size; ++i) { struct MHD_Daemon * const worker = @@ -2448,7 +2448,7 @@ internal_add_connection (struct MHD_Daemon *daemon, /* apply connection acceptance policy if present */ if ( (NULL != daemon->apc) && (MHD_NO == daemon->apc (daemon->apc_cls, - addr, + addr, addrlen)) ) { #if DEBUG_CLOSE @@ -2472,8 +2472,8 @@ internal_add_connection (struct MHD_Daemon *daemon, eno = errno; #ifdef HAVE_MESSAGES MHD_DLOG (daemon, - "Error allocating memory: %s\n", - MHD_strerror_ (errno)); + "Error allocating memory: %s\n", + MHD_strerror_ (errno)); #endif MHD_socket_close_chk_ (client_socket); MHD_ip_limit_del (daemon, @@ -2487,8 +2487,8 @@ internal_add_connection (struct MHD_Daemon *daemon, { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, - _("Error allocating memory: %s\n"), - MHD_strerror_ (errno)); + _("Error allocating memory: %s\n"), + MHD_strerror_ (errno)); #endif MHD_socket_close_chk_ (client_socket); MHD_ip_limit_del (daemon, @@ -2507,8 +2507,8 @@ internal_add_connection (struct MHD_Daemon *daemon, eno = errno; #ifdef HAVE_MESSAGES MHD_DLOG (daemon, - _("Error allocating memory: %s\n"), - MHD_strerror_ (errno)); + _("Error allocating memory: %s\n"), + MHD_strerror_ (errno)); #endif MHD_socket_close_chk_ (client_socket); MHD_ip_limit_del (daemon, @@ -2566,8 +2566,8 @@ internal_add_connection (struct MHD_Daemon *daemon, /* set needed credentials for certificate authentication. */ case GNUTLS_CRD_CERTIFICATE: gnutls_credentials_set (connection->tls_session, - GNUTLS_CRD_CERTIFICATE, - daemon->x509_cred); + GNUTLS_CRD_CERTIFICATE, + daemon->x509_cred); break; case GNUTLS_CRD_PSK: gnutls_credentials_set (connection->tls_session, @@ -2596,18 +2596,18 @@ internal_add_connection (struct MHD_Daemon *daemon, } #if (GNUTLS_VERSION_NUMBER+0 >= 0x030109) && !defined(_WIN64) gnutls_transport_set_int (connection->tls_session, - (int)(client_socket)); + (int)(client_socket)); #else /* GnuTLS before 3.1.9 or Win x64 */ gnutls_transport_set_ptr (connection->tls_session, - (gnutls_transport_ptr_t)(intptr_t)(client_socket)); + (gnutls_transport_ptr_t)(intptr_t)(client_socket)); #endif /* GnuTLS before 3.1.9 */ #ifdef MHD_TLSLIB_NEED_PUSH_FUNC gnutls_transport_set_push_function (connection->tls_session, - MHD_tls_push_func_); + MHD_tls_push_func_); #endif /* MHD_TLSLIB_NEED_PUSH_FUNC */ if (daemon->https_mem_trust) gnutls_certificate_server_set_request (connection->tls_session, - GNUTLS_CERT_REQUEST); + GNUTLS_CERT_REQUEST); #else /* ! HTTPS_SUPPORT */ eno = EINVAL; goto cleanup; @@ -2641,8 +2641,8 @@ internal_add_connection (struct MHD_Daemon *daemon, connection); } DLL_insert (daemon->connections_head, - daemon->connections_tail, - connection); + daemon->connections_tail, + connection); #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); #endif @@ -2661,13 +2661,13 @@ internal_add_connection (struct MHD_Daemon *daemon, &thread_main_handle_connection, connection)) { - eno = errno; + eno = errno; #ifdef HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create a thread: %s\n", MHD_strerror_ (eno)); #endif - goto cleanup; + goto cleanup; } } else @@ -2683,9 +2683,9 @@ internal_add_connection (struct MHD_Daemon *daemon, event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; event.data.ptr = connection; if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_ADD, - client_socket, - &event)) + EPOLL_CTL_ADD, + client_socket, + &event)) { eno = errno; #ifdef HAVE_MESSAGES @@ -2702,8 +2702,8 @@ internal_add_connection (struct MHD_Daemon *daemon, connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY | MHD_EPOLL_STATE_IN_EREADY_EDLL; EDLL_insert (daemon->eready_head, - daemon->eready_tail, - connection); + daemon->eready_tail, + connection); } } else /* This 'else' is combined with next 'if'. */ @@ -4263,7 +4263,7 @@ run_epoll_for_upgrade (struct MHD_Daemon *daemon) * will be moved immediately to cleanup list. Otherwise * connection will stay in suspended list until 'pos' will * be marked with 'was_closed' by application. */ - MHD_resume_connection(pos->connection); + MHD_resume_connection (pos->connection); } } @@ -4346,8 +4346,8 @@ MHD_epoll (struct MHD_Daemon *daemon, } #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) - if ( (! daemon->upgrade_fd_in_epoll) && - (-1 != daemon->epoll_upgrade_fd) ) + if ( ( (! daemon->upgrade_fd_in_epoll) && + (-1 != daemon->epoll_upgrade_fd) ) ) { event.events = EPOLLIN | EPOLLOUT; event.data.ptr = (void *) upgrade_marker; @@ -4388,7 +4388,7 @@ MHD_epoll (struct MHD_Daemon *daemon, if (MHD_YES == may_block) { if (MHD_YES == MHD_get_timeout (daemon, - &timeout_ll)) + &timeout_ll)) { if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX) timeout_ms = INT_MAX; @@ -4824,26 +4824,26 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon) if (NULL != daemon->worker_pool) for (i = 0; i < daemon->worker_pool_size; i++) { - daemon->worker_pool[i].was_quiesced = true; + daemon->worker_pool[i].was_quiesced = true; #ifdef EPOLL_SUPPORT - if ( (0 != (daemon->options & MHD_USE_EPOLL)) && - (-1 != daemon->worker_pool[i].epoll_fd) && - (daemon->worker_pool[i].listen_socket_in_epoll) ) - { - if (0 != epoll_ctl (daemon->worker_pool[i].epoll_fd, - EPOLL_CTL_DEL, - ret, - NULL)) - MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); - daemon->worker_pool[i].listen_socket_in_epoll = false; - } - else -#endif - if (MHD_ITC_IS_VALID_(daemon->worker_pool[i].itc)) + if ( (0 != (daemon->options & MHD_USE_EPOLL)) && + (-1 != daemon->worker_pool[i].epoll_fd) && + (daemon->worker_pool[i].listen_socket_in_epoll) ) { - if (! MHD_itc_activate_ (daemon->worker_pool[i].itc, "q")) - MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel")); + if (0 != epoll_ctl (daemon->worker_pool[i].epoll_fd, + EPOLL_CTL_DEL, + ret, + NULL)) + MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); + daemon->worker_pool[i].listen_socket_in_epoll = false; } + else +#endif + if (MHD_ITC_IS_VALID_(daemon->worker_pool[i].itc)) + { + if (! MHD_itc_activate_ (daemon->worker_pool[i].itc, "q")) + MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel")); + } } #endif daemon->was_quiesced = true; @@ -4858,7 +4858,7 @@ MHD_quiesce_daemon (struct MHD_Daemon *daemon) NULL)) && (ENOENT != errno) ) /* ENOENT can happen due to race with #MHD_epoll() */ - MHD_PANIC ("Failed to remove listen FD from epoll set\n"); + MHD_PANIC ("Failed to remove listen FD from epoll set\n"); daemon->listen_socket_in_epoll = false; } #endif @@ -4892,8 +4892,8 @@ typedef void */ static int parse_options_va (struct MHD_Daemon *daemon, - const struct sockaddr **servaddr, - va_list ap); + const struct sockaddr **servaddr, + va_list ap); /** @@ -4931,8 +4931,8 @@ parse_options (struct MHD_Daemon *daemon, */ static int parse_options_va (struct MHD_Daemon *daemon, - const struct sockaddr **servaddr, - va_list ap) + const struct sockaddr **servaddr, + va_list ap) { enum MHD_OPTION opt; struct MHD_OptionItem *oa; diff --git a/src/microhttpd/test_upgrade_large.c b/src/microhttpd/test_upgrade_large.c index fdf2edf7..6f2a1b94 100644 --- a/src/microhttpd/test_upgrade_large.c +++ b/src/microhttpd/test_upgrade_large.c @@ -67,6 +67,8 @@ static int verbose = 0; +static int kicker[2] = {-1, -1} ; + enum tls_tool { TLS_CLI_NO_TOOL = 0, @@ -570,7 +572,17 @@ make_blocking (MHD_socket fd) ioctlsocket (fd, FIONBIO, &flags); #endif /* MHD_WINSOCK_SOCKETS */ +} + +static void +kick_select () +{ + if (-1 != kicker[1]) + { + write (kicker[1], "K", 1); + fprintf (stderr, "KICKING\n"); + } } @@ -588,6 +600,7 @@ send_all (struct wr_socket *sock, ret = wr_send (sock, &text[off], len - off); + kick_select (); if (0 > ret) { if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) @@ -621,6 +634,7 @@ recv_hdr (struct wr_socket *sock) ret = wr_recv (sock, &c, 1); + kick_select (); if (0 > ret) { if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) @@ -889,7 +903,10 @@ run_mhd_select_loop (struct MHD_Daemon *daemon) MHD_socket max_fd; MHD_UNSIGNED_LONG_LONG to; struct timeval tv; + char drain[128]; + if (0 != pipe (kicker)) + abort (); while (! done) { FD_ZERO (&rs); @@ -898,6 +915,7 @@ run_mhd_select_loop (struct MHD_Daemon *daemon) max_fd = -1; to = 1000; + FD_SET (kicker[0], &rs); if (MHD_YES != MHD_get_fdset (daemon, &rs, @@ -917,11 +935,17 @@ run_mhd_select_loop (struct MHD_Daemon *daemon) &es, &tv)) abort (); + if (FD_ISSET (kicker[0], &rs)) + (void) read (kicker[0], drain, sizeof (drain)); MHD_run_from_select (daemon, &rs, &ws, &es); } + close (kicker[0]); + close (kicker[1]); + kicker[0] = -1; + kicker[1] = -1; } #ifdef HAVE_POLL @@ -955,15 +979,18 @@ run_mhd_epoll_loop (struct MHD_Daemon *daemon) MHD_UNSIGNED_LONG_LONG to; struct timeval tv; int ret; + char drain[128]; di = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_EPOLL_FD); ep = di->listen_fd; + if (0 != pipe (kicker)) + abort (); while (! done) { FD_ZERO (&rs); to = 1000; - + FD_SET (kicker[0], &rs); FD_SET (ep, &rs); (void) MHD_get_timeout (daemon, &to); @@ -980,8 +1007,14 @@ run_mhd_epoll_loop (struct MHD_Daemon *daemon) (EAGAIN != errno) && (EINTR != errno) ) abort (); + if (FD_ISSET (kicker[0], &rs)) + (void) read (kicker[0], drain, sizeof (drain)); MHD_run (daemon); } + close (kicker[0]); + close (kicker[1]); + kicker[0] = -1; + kicker[1] = -1; } #endif /* EPOLL_SUPPORT */ @@ -1080,8 +1113,8 @@ test_upgrade (int flags, sa.sin_port = htons (dinfo->port); sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); if (0 != wr_connect (sock, - (struct sockaddr *) &sa, - sizeof (sa))) + (struct sockaddr *) &sa, + sizeof (sa))) abort (); } else -- cgit v1.2.3 From bafd078984be5f846287107824eca99e6c6c42cc Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 29 Jul 2019 20:03:41 +0200 Subject: fix hang reported by Viet on 24.6.2019 on the mailinglist: do not just consider nested epoll, but also already ready connections --- ChangeLog | 5 +++++ src/include/microhttpd.h | 2 +- src/microhttpd/daemon.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c45326df..b4c065c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon 29 Jul 2019 08:01:50 PM CEST + Fix hanging situation with large transmission over upgraded + (i.e. Web socket) connection with epoll() and HTTPS enabled + (as reported by Viet on the mailinglist). -CG + Thu 25 Jul 2019 02:40:12 PM CEST Fixing regression introduced in cc5032b85 (bit mask matching of the header kinds in MHD_lookup_connection_value()), as diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 4c05ffac..f141967c 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h @@ -132,7 +132,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00096503 +#define MHD_VERSION 0x00096504 /** * MHD-internal return code for "YES". diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 7ce0fbb3..bf01ba9b 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c @@ -4519,7 +4519,7 @@ MHD_epoll (struct MHD_Daemon *daemon, } #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) - if (run_upgraded) + if (run_upgraded || (NULL != daemon->eready_urh_head)) run_epoll_for_upgrade (daemon); #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ -- cgit v1.2.3 From de315d36e01a089063c2e76bb26a6e705365cf66 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 1 Aug 2019 00:54:42 +0200 Subject: attempt to fix issue with upload data discovered by FD --- ChangeLog | 4 ++++ src/include/microhttpd.h | 2 +- src/microhttpd/connection.c | 26 +++++++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4c065c8..87de3ef9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Thu 01 Aug 2019 12:53:49 AM CEST + Fix issue with discarding unhandled upload data discovered + by Florian Dold. -CG + Mon 29 Jul 2019 08:01:50 PM CEST Fix hanging situation with large transmission over upgraded (i.e. Web socket) connection with epoll() and HTTPS enabled diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index f141967c..a2196b9d 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h @@ -132,7 +132,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00096504 +#define MHD_VERSION 0x00096505 /** * MHD-internal return code for "YES". diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index fd977708..6f33dbc1 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c @@ -2624,7 +2624,19 @@ process_request_body (struct MHD_Connection *connection) char *buffer_head; if (NULL != connection->response) - return; /* already queued a response */ + { + /* already queued a response, discard remaining upload + (but not more, there might be another request after it) */ + uint64_t purge = MHD_MIN (connection->remaining_upload_size, + connection->read_buffer_offset); + connection->remaining_upload_size -= purge; + if (connection->read_buffer_offset > purge) + memmove (connection->read_buffer, + &connection->read_buffer[purge], + connection->read_buffer_offset - purge); + connection->read_buffer_offset -= purge; + return; + } buffer_head = connection->read_buffer; available = connection->read_buffer_offset; @@ -2759,19 +2771,19 @@ process_request_body (struct MHD_Connection *connection) { /* no chunked encoding, give all to the client */ if ( (0 != connection->remaining_upload_size) && - (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && - (connection->remaining_upload_size < available) ) - { + (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && + (connection->remaining_upload_size < available) ) + { to_be_processed = (size_t)connection->remaining_upload_size; - } + } else - { + { /** * 1. no chunked encoding, give all to the client * 2. client may send large chunked data, but only a smaller part is available at one time. */ to_be_processed = available; - } + } } left_unprocessed = to_be_processed; connection->client_aware = true; -- cgit v1.2.3 From 91826f50011e76014dc307e370e6b1f45b2df151 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 1 Aug 2019 13:38:40 +0200 Subject: releasing v0.9.66 --- ChangeLog | 3 + configure.ac | 6 +- po/libmicrohttpd.pot | 297 ++++++++++++++++++++++++----------------------- src/include/microhttpd.h | 2 +- 4 files changed, 158 insertions(+), 150 deletions(-) diff --git a/ChangeLog b/ChangeLog index 87de3ef9..92161c6f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +Thu 01 Aug 2019 01:23:36 PM CEST + Releasing libmicrohttpd 0.9.66. -CG + Thu 01 Aug 2019 12:53:49 AM CEST Fix issue with discarding unhandled upload data discovered by Florian Dold. -CG diff --git a/configure.ac b/configure.ac index 61b0c6f1..5292798a 100644 --- a/configure.ac +++ b/configure.ac @@ -22,15 +22,15 @@ # AC_PREREQ([2.64]) LT_PREREQ([2.4.0]) -AC_INIT([GNU Libmicrohttpd],[0.9.65],[libmicrohttpd@gnu.org]) +AC_INIT([GNU Libmicrohttpd],[0.9.66],[libmicrohttpd@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([silent-rules] [subdir-objects]) AC_CONFIG_HEADERS([MHD_config.h]) AC_CONFIG_MACRO_DIR([m4]) -LIB_VERSION_CURRENT=64 +LIB_VERSION_CURRENT=65 LIB_VERSION_REVISION=0 -LIB_VERSION_AGE=52 +LIB_VERSION_AGE=53 AC_SUBST(LIB_VERSION_CURRENT) AC_SUBST(LIB_VERSION_REVISION) AC_SUBST(LIB_VERSION_AGE) diff --git a/po/libmicrohttpd.pot b/po/libmicrohttpd.pot index feb037c6..0f089638 100644 --- a/po/libmicrohttpd.pot +++ b/po/libmicrohttpd.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: GNU libmicrohttpd 0.9.65\n" +"Project-Id-Version: GNU libmicrohttpd 0.9.66\n" "Report-Msgid-Bugs-To: libmicrohttpd@gnu.org\n" -"POT-Creation-Date: 2019-07-05 22:27+0300\n" +"POT-Creation-Date: 2019-08-01 13:26+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -104,513 +104,518 @@ msgstr "" msgid "Previously-added IP address had counter of zero\n" msgstr "" -#: src/microhttpd/daemon.c:614 +#: src/microhttpd/daemon.c:622 msgid "" "Failed to setup x509 certificate/key: pre 3.X.X version of GnuTLS does not " "support setting key password" msgstr "" -#: src/microhttpd/daemon.c:668 +#: src/microhttpd/daemon.c:680 #, c-format msgid "Error: invalid credentials type %d specified.\n" msgstr "" -#: src/microhttpd/daemon.c:1067 +#: src/microhttpd/daemon.c:1079 #, c-format msgid "Maximum socket in select set: %d\n" msgstr "" -#: src/microhttpd/daemon.c:1128 +#: src/microhttpd/daemon.c:1140 msgid "" "MHD_get_fdset2() called with except_fd_set set to NULL. Such behavior is " "unsupported.\n" msgstr "" -#: src/microhttpd/daemon.c:1334 src/microhttpd/daemon.c:6573 +#: src/microhttpd/daemon.c:1346 src/microhttpd/daemon.c:6611 msgid "" "Initiated daemon shutdown while \"upgraded\" connection was not closed.\n" msgstr "" -#: src/microhttpd/daemon.c:1348 src/microhttpd/daemon.c:1583 +#: src/microhttpd/daemon.c:1360 src/microhttpd/daemon.c:1595 msgid "Failed to forward to application " msgstr "" -#: src/microhttpd/daemon.c:1515 src/microhttpd/daemon.c:1637 +#: src/microhttpd/daemon.c:1527 src/microhttpd/daemon.c:1649 msgid "Failed to forward to remote client " msgstr "" -#: src/microhttpd/daemon.c:1702 +#: src/microhttpd/daemon.c:1714 msgid "Error preparing select\n" msgstr "" -#: src/microhttpd/daemon.c:1736 src/microhttpd/daemon.c:1888 -#: src/microhttpd/daemon.c:2032 +#: src/microhttpd/daemon.c:1748 src/microhttpd/daemon.c:1900 +#: src/microhttpd/daemon.c:2044 #, c-format msgid "Error during select (%d): `%s'\n" msgstr "" -#: src/microhttpd/daemon.c:1785 src/microhttpd/daemon.c:1909 -#: src/microhttpd/daemon.c:2101 +#: src/microhttpd/daemon.c:1797 src/microhttpd/daemon.c:1921 +#: src/microhttpd/daemon.c:2113 #, c-format msgid "Error during poll: `%s'\n" msgstr "" -#: src/microhttpd/daemon.c:1872 src/microhttpd/daemon.c:2014 +#: src/microhttpd/daemon.c:1884 src/microhttpd/daemon.c:2026 msgid "Failed to add FD to fd_set\n" msgstr "" -#: src/microhttpd/daemon.c:2153 +#: src/microhttpd/daemon.c:2165 msgid "Processing thread terminating. Closing connection\n" msgstr "" -#: src/microhttpd/daemon.c:2182 +#: src/microhttpd/daemon.c:2194 msgid "" "Failed to signal thread termination via inter-thread communication channel." msgstr "" -#: src/microhttpd/daemon.c:2253 +#: src/microhttpd/daemon.c:2265 msgid "Internal server error. This should be impossible.\n" msgstr "" -#: src/microhttpd/daemon.c:2263 src/microhttpd/daemon.c:2300 +#: src/microhttpd/daemon.c:2275 src/microhttpd/daemon.c:2312 msgid "PSK not supported by this server.\n" msgstr "" -#: src/microhttpd/daemon.c:2277 +#: src/microhttpd/daemon.c:2289 msgid "PSK authentication failed: gnutls_malloc failed to allocate memory\n" msgstr "" -#: src/microhttpd/daemon.c:2286 +#: src/microhttpd/daemon.c:2298 msgid "PSK authentication failed: PSK too long\n" msgstr "" -#: src/microhttpd/daemon.c:2382 src/microhttpd/daemon.c:6217 +#: src/microhttpd/daemon.c:2394 src/microhttpd/daemon.c:6255 #, c-format msgid "Socket descriptor larger than FD_SETSIZE: %d > %d\n" msgstr "" -#: src/microhttpd/daemon.c:2398 +#: src/microhttpd/daemon.c:2410 #, c-format msgid "Failed to set SO_NOSIGPIPE on accepted socket: %s\n" msgstr "" -#: src/microhttpd/daemon.c:2415 src/microhttpd/daemon.c:3238 +#: src/microhttpd/daemon.c:2427 src/microhttpd/daemon.c:3251 #, c-format msgid "Accepted connection on socket %d\n" msgstr "" -#: src/microhttpd/daemon.c:2427 src/microhttpd/daemon.c:2617 +#: src/microhttpd/daemon.c:2439 src/microhttpd/daemon.c:2629 msgid "Server reached connection limit. Closing inbound connection.\n" msgstr "" -#: src/microhttpd/daemon.c:2445 +#: src/microhttpd/daemon.c:2457 msgid "Connection rejected by application. Closing connection.\n" msgstr "" -#: src/microhttpd/daemon.c:2478 src/microhttpd/daemon.c:2498 -#: src/microhttpd/daemon.c:3824 +#: src/microhttpd/daemon.c:2490 src/microhttpd/daemon.c:2510 +#: src/microhttpd/daemon.c:3837 #, c-format msgid "Error allocating memory: %s\n" msgstr "" -#: src/microhttpd/daemon.c:2570 +#: src/microhttpd/daemon.c:2582 #, c-format msgid "Failed to setup TLS credentials: unknown credential type %d\n" msgstr "" -#: src/microhttpd/daemon.c:2579 +#: src/microhttpd/daemon.c:2591 msgid "Unknown credential type" msgstr "" -#: src/microhttpd/daemon.c:2681 src/microhttpd/daemon.c:4314 -#: src/microhttpd/daemon.c:4347 src/microhttpd/daemon.c:5509 -#: src/microhttpd/daemon.c:5526 src/microhttpd/connection.c:4130 +#: src/microhttpd/daemon.c:2693 src/microhttpd/daemon.c:4328 +#: src/microhttpd/daemon.c:4361 src/microhttpd/daemon.c:5547 +#: src/microhttpd/daemon.c:5564 src/microhttpd/connection.c:4142 #: src/microhttpd/response.c:1003 src/microhttpd/response.c:1029 #, c-format msgid "Call to epoll_ctl failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:2706 +#: src/microhttpd/daemon.c:2718 msgid "Failed to signal new connection via inter-thread communication channel." msgstr "" -#: src/microhttpd/daemon.c:2811 src/microhttpd/daemon.c:3322 -#: src/microhttpd/daemon.c:6463 src/microhttpd/connection.c:1190 +#: src/microhttpd/daemon.c:2823 src/microhttpd/daemon.c:3335 +#: src/microhttpd/daemon.c:6501 src/microhttpd/connection.c:1190 #: src/microhttpd/connection.c:1209 msgid "Failed to remove FD from epoll set\n" msgstr "" -#: src/microhttpd/daemon.c:2860 +#: src/microhttpd/daemon.c:2872 msgid "Cannot suspend connections without enabling MHD_ALLOW_SUSPEND_RESUME!\n" msgstr "" -#: src/microhttpd/daemon.c:2866 +#: src/microhttpd/daemon.c:2878 msgid "Error: connection scheduled for \"upgrade\" cannot be suspended" msgstr "" -#: src/microhttpd/daemon.c:2889 +#: src/microhttpd/daemon.c:2901 msgid "Cannot resume connections without enabling MHD_ALLOW_SUSPEND_RESUME!\n" msgstr "" -#: src/microhttpd/daemon.c:2903 +#: src/microhttpd/daemon.c:2915 msgid "Failed to signal resume via inter-thread communication channel." msgstr "" -#: src/microhttpd/daemon.c:3035 +#: src/microhttpd/daemon.c:3047 msgid "" "Failed to signal resume of connection via inter-thread communication channel." msgstr "" -#: src/microhttpd/daemon.c:3081 +#: src/microhttpd/daemon.c:3094 #, c-format msgid "Failed to set nonblocking mode on new client socket: %s\n" msgstr "" -#: src/microhttpd/daemon.c:3094 +#: src/microhttpd/daemon.c:3107 msgid "Failed to set noninheritable mode on new client socket.\n" msgstr "" -#: src/microhttpd/daemon.c:3103 +#: src/microhttpd/daemon.c:3116 msgid "Failed to reset buffering mode on new client socket.\n" msgstr "" -#: src/microhttpd/daemon.c:3176 +#: src/microhttpd/daemon.c:3189 #, c-format msgid "Error accepting connection: %s\n" msgstr "" -#: src/microhttpd/daemon.c:3193 +#: src/microhttpd/daemon.c:3206 msgid "" "Hit process or system resource limit at FIRST connection. This is really bad " "as there is no sane way to proceed. Will try busy waiting for system " "resources to become magically available.\n" msgstr "" -#: src/microhttpd/daemon.c:3207 +#: src/microhttpd/daemon.c:3220 #, c-format msgid "" "Hit process or system resource limit at %u connections, temporarily " "suspending accept(). Consider setting a lower MHD_OPTION_CONNECTION_LIMIT.\n" msgstr "" -#: src/microhttpd/daemon.c:3219 +#: src/microhttpd/daemon.c:3232 #, c-format msgid "Failed to set nonblocking mode on incoming connection socket: %s\n" msgstr "" -#: src/microhttpd/daemon.c:3231 +#: src/microhttpd/daemon.c:3244 msgid "Failed to set noninheritable mode on incoming connection socket.\n" msgstr "" -#: src/microhttpd/daemon.c:3279 src/microhttpd/daemon.c:6615 -#: src/microhttpd/daemon.c:6647 src/microhttpd/daemon.c:6747 +#: src/microhttpd/daemon.c:3292 src/microhttpd/daemon.c:6653 +#: src/microhttpd/daemon.c:6685 src/microhttpd/daemon.c:6785 msgid "Failed to join a thread\n" msgstr "" -#: src/microhttpd/daemon.c:3383 +#: src/microhttpd/daemon.c:3396 msgid "Illegal call to MHD_get_timeout\n" msgstr "" -#: src/microhttpd/daemon.c:3580 +#: src/microhttpd/daemon.c:3593 msgid "" "MHD_run_from_select() called with except_fd_set set to NULL. Such behavior " "is deprecated.\n" msgstr "" -#: src/microhttpd/daemon.c:3660 +#: src/microhttpd/daemon.c:3673 msgid "Could not obtain daemon fdsets" msgstr "" -#: src/microhttpd/daemon.c:3677 +#: src/microhttpd/daemon.c:3690 msgid "Could not add listen socket to fdset" msgstr "" -#: src/microhttpd/daemon.c:3705 +#: src/microhttpd/daemon.c:3718 msgid "Could not add control inter-thread communication channel FD to fdset" msgstr "" -#: src/microhttpd/daemon.c:3761 +#: src/microhttpd/daemon.c:3774 #, c-format msgid "select failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:3906 src/microhttpd/daemon.c:4053 +#: src/microhttpd/daemon.c:3919 src/microhttpd/daemon.c:4066 #, c-format msgid "poll failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:4183 src/microhttpd/daemon.c:4414 +#: src/microhttpd/daemon.c:4197 src/microhttpd/daemon.c:4428 #, c-format msgid "Call to epoll_wait failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:4366 src/microhttpd/daemon.c:4823 +#: src/microhttpd/daemon.c:4380 src/microhttpd/daemon.c:4837 msgid "Failed to remove listen FD from epoll set\n" msgstr "" -#: src/microhttpd/daemon.c:4831 +#: src/microhttpd/daemon.c:4845 msgid "Failed to signal quiesce via inter-thread communication channel" msgstr "" -#: src/microhttpd/daemon.c:4853 +#: src/microhttpd/daemon.c:4867 msgid "failed to signal quiesce via inter-thread communication channel" msgstr "" -#: src/microhttpd/daemon.c:4964 +#: src/microhttpd/daemon.c:4981 msgid "Warning: Too large timeout value, ignored.\n" msgstr "" -#: src/microhttpd/daemon.c:5003 +#: src/microhttpd/daemon.c:5020 msgid "" "Warning: Zero size, specified for thread pool size, is ignored. Thread pool " "is not used.\n" msgstr "" -#: src/microhttpd/daemon.c:5011 +#: src/microhttpd/daemon.c:5028 msgid "" "Warning: \"1\", specified for thread pool size, is ignored. Thread pool is " "not used.\n" msgstr "" -#: src/microhttpd/daemon.c:5023 +#: src/microhttpd/daemon.c:5040 #, c-format msgid "Specified thread pool size (%u) too big\n" msgstr "" -#: src/microhttpd/daemon.c:5034 +#: src/microhttpd/daemon.c:5051 msgid "" "MHD_OPTION_THREAD_POOL_SIZE option is specified but " "MHD_USE_INTERNAL_POLLING_THREAD flag is not specified.\n" msgstr "" -#: src/microhttpd/daemon.c:5043 +#: src/microhttpd/daemon.c:5060 msgid "" "Both MHD_OPTION_THREAD_POOL_SIZE option and MHD_USE_THREAD_PER_CONNECTION " "flag are specified.\n" msgstr "" -#: src/microhttpd/daemon.c:5060 src/microhttpd/daemon.c:5072 -#: src/microhttpd/daemon.c:5084 src/microhttpd/daemon.c:5096 -#: src/microhttpd/daemon.c:5147 src/microhttpd/daemon.c:5175 -#: src/microhttpd/daemon.c:5194 +#: src/microhttpd/daemon.c:5077 src/microhttpd/daemon.c:5089 +#: src/microhttpd/daemon.c:5101 src/microhttpd/daemon.c:5113 +#: src/microhttpd/daemon.c:5164 src/microhttpd/daemon.c:5192 +#: src/microhttpd/daemon.c:5211 src/microhttpd/daemon.c:5231 #, c-format msgid "MHD HTTPS option %d passed to MHD but MHD_USE_TLS not set\n" msgstr "" -#: src/microhttpd/daemon.c:5116 +#: src/microhttpd/daemon.c:5133 msgid "Error initializing DH parameters\n" msgstr "" -#: src/microhttpd/daemon.c:5126 +#: src/microhttpd/daemon.c:5143 msgid "Diffie-Hellman parameters string too long\n" msgstr "" -#: src/microhttpd/daemon.c:5137 +#: src/microhttpd/daemon.c:5154 msgid "Bad Diffie-Hellman parameters format\n" msgstr "" -#: src/microhttpd/daemon.c:5164 +#: src/microhttpd/daemon.c:5181 #, c-format msgid "Setting priorities to `%s' failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:5183 +#: src/microhttpd/daemon.c:5200 msgid "" "MHD_OPTION_HTTPS_CERT_CALLBACK requires building MHD with GnuTLS >= 3.0\n" msgstr "" -#: src/microhttpd/daemon.c:5217 +#: src/microhttpd/daemon.c:5220 +msgid "" +"MHD_OPTION_HTTPS_CERT_CALLBACK2 requires building MHD with GnuTLS >= 3.6.3\n" +msgstr "" + +#: src/microhttpd/daemon.c:5254 msgid "" "MHD_OPTION_LISTEN_SOCKET specified for daemon with MHD_USE_NO_LISTEN_SOCKET " "flag set.\n" msgstr "" -#: src/microhttpd/daemon.c:5253 +#: src/microhttpd/daemon.c:5290 msgid "TCP fastopen is not supported on this platform\n" msgstr "" -#: src/microhttpd/daemon.c:5272 +#: src/microhttpd/daemon.c:5309 msgid "" "Flag MHD_USE_PEDANTIC_CHECKS is ignored because another behavior is " "specified by MHD_OPTION_STRICT_CLIENT.\n" msgstr "" -#: src/microhttpd/daemon.c:5404 +#: src/microhttpd/daemon.c:5442 #, c-format msgid "MHD HTTPS option %d passed to MHD compiled without GNUtls >= 3\n" msgstr "" -#: src/microhttpd/daemon.c:5417 +#: src/microhttpd/daemon.c:5455 #, c-format msgid "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n" msgstr "" -#: src/microhttpd/daemon.c:5423 +#: src/microhttpd/daemon.c:5461 #, c-format msgid "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n" msgstr "" -#: src/microhttpd/daemon.c:5453 +#: src/microhttpd/daemon.c:5491 #, c-format msgid "Call to epoll_create1 failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:5463 +#: src/microhttpd/daemon.c:5501 msgid "Failed to set noninheritable mode on epoll FD.\n" msgstr "" -#: src/microhttpd/daemon.c:5706 +#: src/microhttpd/daemon.c:5744 msgid "" "Warning: MHD_USE_THREAD_PER_CONNECTION must be used only with " "MHD_USE_INTERNAL_POLLING_THREAD. Flag MHD_USE_INTERNAL_POLLING_THREAD was " "added. Consider setting MHD_USE_INTERNAL_POLLING_THREAD explicitly.\n" msgstr "" -#: src/microhttpd/daemon.c:5754 +#: src/microhttpd/daemon.c:5792 msgid "Using debug build of libmicrohttpd.\n" msgstr "" -#: src/microhttpd/daemon.c:5768 +#: src/microhttpd/daemon.c:5806 #, c-format msgid "Failed to create inter-thread communication channel: %s\n" msgstr "" -#: src/microhttpd/daemon.c:5784 +#: src/microhttpd/daemon.c:5822 msgid "" "file descriptor for inter-thread communication channel exceeds maximum " "value\n" msgstr "" -#: src/microhttpd/daemon.c:5804 +#: src/microhttpd/daemon.c:5842 msgid "Specified value for NC_SIZE too large\n" msgstr "" -#: src/microhttpd/daemon.c:5818 +#: src/microhttpd/daemon.c:5856 #, c-format msgid "Failed to allocate memory for nonce-nc map: %s\n" msgstr "" -#: src/microhttpd/daemon.c:5835 +#: src/microhttpd/daemon.c:5873 msgid "MHD failed to initialize nonce-nc mutex\n" msgstr "" -#: src/microhttpd/daemon.c:5855 +#: src/microhttpd/daemon.c:5893 msgid "MHD thread pooling only works with MHD_USE_INTERNAL_POLLING_THREAD\n" msgstr "" -#: src/microhttpd/daemon.c:5879 +#: src/microhttpd/daemon.c:5917 #, c-format msgid "Failed to create socket for listening: %s\n" msgstr "" -#: src/microhttpd/daemon.c:5900 src/microhttpd/daemon.c:5919 -#: src/microhttpd/daemon.c:5942 src/microhttpd/daemon.c:5979 -#: src/microhttpd/daemon.c:6056 src/microhttpd/daemon.c:6087 +#: src/microhttpd/daemon.c:5938 src/microhttpd/daemon.c:5957 +#: src/microhttpd/daemon.c:5980 src/microhttpd/daemon.c:6017 +#: src/microhttpd/daemon.c:6094 src/microhttpd/daemon.c:6125 #, c-format msgid "setsockopt failed: %s\n" msgstr "" -#: src/microhttpd/daemon.c:5952 +#: src/microhttpd/daemon.c:5990 msgid "Cannot allow listening address reuse: SO_REUSEPORT not defined\n" msgstr "" -#: src/microhttpd/daemon.c:5987 +#: src/microhttpd/daemon.c:6025 msgid "" "Cannot disallow listening address reuse: SO_EXCLUSIVEADDRUSE not defined\n" msgstr "" -#: src/microhttpd/daemon.c:6067 +#: src/microhttpd/daemon.c:6105 #, c-format msgid "Failed to bind to port %u: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6098 +#: src/microhttpd/daemon.c:6136 #, c-format msgid "Failed to listen for connections: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6129 +#: src/microhttpd/daemon.c:6167 #, c-format msgid "Failed to get listen port number: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6139 +#: src/microhttpd/daemon.c:6177 msgid "" "Failed to get listen port number (`struct sockaddr_storage` too small!?)\n" msgstr "" -#: src/microhttpd/daemon.c:6180 +#: src/microhttpd/daemon.c:6218 msgid "Unknown address family!\n" msgstr "" -#: src/microhttpd/daemon.c:6194 +#: src/microhttpd/daemon.c:6232 #, c-format msgid "Failed to set nonblocking mode on listening socket: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6236 +#: src/microhttpd/daemon.c:6274 msgid "" "Combining MHD_USE_THREAD_PER_CONNECTION and MHD_USE_EPOLL is not supported.\n" msgstr "" -#: src/microhttpd/daemon.c:6250 src/microhttpd/daemon.c:6263 +#: src/microhttpd/daemon.c:6288 src/microhttpd/daemon.c:6301 msgid "MHD failed to initialize IP connection limit mutex\n" msgstr "" -#: src/microhttpd/daemon.c:6282 +#: src/microhttpd/daemon.c:6320 msgid "Failed to initialize TLS support\n" msgstr "" -#: src/microhttpd/daemon.c:6309 +#: src/microhttpd/daemon.c:6347 #, c-format msgid "Failed to create listen thread: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6357 +#: src/microhttpd/daemon.c:6395 #, c-format msgid "Failed to create worker inter-thread communication channel: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6368 +#: src/microhttpd/daemon.c:6406 msgid "" "File descriptor for worker inter-thread communication channel exceeds " "maximum value\n" msgstr "" -#: src/microhttpd/daemon.c:6393 +#: src/microhttpd/daemon.c:6431 msgid "MHD failed to initialize cleanup connection mutex\n" msgstr "" -#: src/microhttpd/daemon.c:6407 +#: src/microhttpd/daemon.c:6445 #, c-format msgid "Failed to create pool thread: %s\n" msgstr "" -#: src/microhttpd/daemon.c:6560 src/microhttpd/daemon.c:6591 +#: src/microhttpd/daemon.c:6598 src/microhttpd/daemon.c:6629 msgid "MHD_stop_daemon() called while we have suspended connections.\n" msgstr "" -#: src/microhttpd/daemon.c:6600 src/microhttpd/daemon.c:6729 +#: src/microhttpd/daemon.c:6638 src/microhttpd/daemon.c:6767 msgid "Failed to signal shutdown via inter-thread communication channel" msgstr "" -#: src/microhttpd/daemon.c:6692 +#: src/microhttpd/daemon.c:6730 msgid "Failed to signal shutdown via inter-thread communication channel." msgstr "" -#: src/microhttpd/daemon.c:7159 +#: src/microhttpd/daemon.c:7203 msgid "Failed to initialize winsock\n" msgstr "" -#: src/microhttpd/daemon.c:7162 +#: src/microhttpd/daemon.c:7206 msgid "Winsock version 2.2 is not available\n" msgstr "" -#: src/microhttpd/daemon.c:7170 src/microhttpd/daemon.c:7174 +#: src/microhttpd/daemon.c:7214 src/microhttpd/daemon.c:7218 msgid "Failed to initialise multithreading in libgcrypt\n" msgstr "" -#: src/microhttpd/daemon.c:7179 +#: src/microhttpd/daemon.c:7223 msgid "libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 or newer\n" msgstr "" @@ -637,17 +642,17 @@ msgid "" "connection.\n" msgstr "" -#: src/microhttpd/connection.c:2055 src/microhttpd/connection.c:3068 +#: src/microhttpd/connection.c:2055 src/microhttpd/connection.c:3080 msgid "Closing connection (failed to queue response)\n" msgstr "" -#: src/microhttpd/connection.c:2065 src/microhttpd/connection.c:3842 -#: src/microhttpd/connection.c:3965 +#: src/microhttpd/connection.c:2065 src/microhttpd/connection.c:3854 +#: src/microhttpd/connection.c:3977 msgid "Closing connection (failed to create response header)\n" msgstr "" -#: src/microhttpd/connection.c:2111 src/microhttpd/connection.c:3223 -#: src/microhttpd/connection.c:3291 src/microhttpd/connection.c:3607 +#: src/microhttpd/connection.c:2111 src/microhttpd/connection.c:3235 +#: src/microhttpd/connection.c:3303 src/microhttpd/connection.c:3619 #, c-format msgid "In function %s handling connection at state: %s\n" msgstr "" @@ -660,96 +665,96 @@ msgstr "" msgid "Not enough memory in pool to parse cookies!\n" msgstr "" -#: src/microhttpd/connection.c:2605 src/microhttpd/connection.c:2790 +#: src/microhttpd/connection.c:2605 src/microhttpd/connection.c:2802 msgid "Application reported internal error, closing connection.\n" msgstr "" -#: src/microhttpd/connection.c:2658 src/microhttpd/connection.c:2735 +#: src/microhttpd/connection.c:2670 src/microhttpd/connection.c:2747 msgid "" "Received malformed HTTP request (bad chunked encoding). Closing connection.\n" msgstr "" -#: src/microhttpd/connection.c:2798 +#: src/microhttpd/connection.c:2810 msgid "libmicrohttpd API violation" msgstr "" -#: src/microhttpd/connection.c:2813 +#: src/microhttpd/connection.c:2825 msgid "" "WARNING: incomplete upload processing and connection not suspended may " "result in hung connection.\n" msgstr "" -#: src/microhttpd/connection.c:2884 +#: src/microhttpd/connection.c:2896 msgid "Received malformed line (no colon). Closing connection.\n" msgstr "" -#: src/microhttpd/connection.c:3046 +#: src/microhttpd/connection.c:3058 msgid "Received HTTP 1.1 request without `Host' header.\n" msgstr "" -#: src/microhttpd/connection.c:3057 +#: src/microhttpd/connection.c:3069 msgid "Closing connection (failed to create response)\n" msgstr "" -#: src/microhttpd/connection.c:3202 +#: src/microhttpd/connection.c:3214 msgid "Socket disconnected while reading request.\n" msgstr "" -#: src/microhttpd/connection.c:3208 +#: src/microhttpd/connection.c:3220 msgid "Connection socket is closed due to error when reading request.\n" msgstr "" -#: src/microhttpd/connection.c:3317 +#: src/microhttpd/connection.c:3329 #, c-format msgid "Failed to send data in request for %s.\n" msgstr "" -#: src/microhttpd/connection.c:3326 +#: src/microhttpd/connection.c:3338 #, c-format msgid "Sent 100 continue response: `%.*s'\n" msgstr "" -#: src/microhttpd/connection.c:3350 +#: src/microhttpd/connection.c:3362 msgid "Connection was closed while sending response headers.\n" msgstr "" -#: src/microhttpd/connection.c:3391 +#: src/microhttpd/connection.c:3403 msgid "Data offset exceeds limit" msgstr "" -#: src/microhttpd/connection.c:3400 +#: src/microhttpd/connection.c:3412 #, c-format msgid "Sent %d-byte DATA response: `%.*s'\n" msgstr "" -#: src/microhttpd/connection.c:3417 +#: src/microhttpd/connection.c:3429 #, c-format msgid "Failed to send data in request for `%s'.\n" msgstr "" -#: src/microhttpd/connection.c:3445 src/microhttpd/connection.c:3473 +#: src/microhttpd/connection.c:3457 src/microhttpd/connection.c:3485 msgid "Connection was closed while sending response body.\n" msgstr "" -#: src/microhttpd/connection.c:3496 +#: src/microhttpd/connection.c:3508 msgid "Internal error\n" msgstr "" -#: src/microhttpd/connection.c:3569 +#: src/microhttpd/connection.c:3581 msgid "" "Failed to signal end of connection via inter-thread communication channel" msgstr "" -#: src/microhttpd/connection.c:4316 +#: src/microhttpd/connection.c:4328 msgid "Attempted to queue response on wrong thread!\n" msgstr "" -#: src/microhttpd/connection.c:4327 +#: src/microhttpd/connection.c:4339 msgid "" "Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n" msgstr "" -#: src/microhttpd/connection.c:4336 +#: src/microhttpd/connection.c:4348 msgid "Application used invalid status code for 'upgrade' response!\n" msgstr "" diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index a2196b9d..c2fc90a4 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h @@ -132,7 +132,7 @@ typedef intptr_t ssize_t; * Current version of the library. * 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00096505 +#define MHD_VERSION 0x00096600 /** * MHD-internal return code for "YES". -- cgit v1.2.3