libmicrohttpd

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

commit dc9b5154aeff904ec8801d4144e3c0a996e15be5
parent 9b4146730b3fab0bfb98ddfd4c8ca3b03c4b9bdb
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon, 17 Oct 2016 14:38:38 +0200

add test logic to check that callbacks are invoked properly (and from the right thread), fix when callbacks are invoked where issues exist

Diffstat:
Msrc/microhttpd/daemon.c | 92+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/microhttpd/test_upgrade.c | 8++++++++
Msrc/microhttpd/test_upgrade_common.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/test_upgrade_ssl.c | 3+++
4 files changed, 147 insertions(+), 40 deletions(-)

diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -3672,6 +3672,39 @@ MHD_run (struct MHD_Daemon *daemon) /** + * Close the given connection, remove it from all of its + * DLLs and move it into the cleanup queue. + * + * @param pos connection to move to cleanup + */ +static void +close_connection (struct MHD_Connection *pos) +{ + struct MHD_Daemon *daemon = pos->daemon; + + MHD_connection_close_ (pos, + MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); + if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + return; /* must let thread to the rest */ + if (pos->connection_timeout == pos->daemon->connection_timeout) + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + pos); + else + XDLL_remove (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + pos); + DLL_remove (daemon->connections_head, + daemon->connections_tail, + pos); + pos->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + DLL_insert (daemon->cleanup_head, + daemon->cleanup_tail, + pos); +} + + +/** * Thread that runs the select loop until the daemon * is explicitly shut down. * @@ -3682,6 +3715,7 @@ static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ MHD_select_thread (void *cls) { struct MHD_Daemon *daemon = cls; + struct MHD_Connection *pos; while (MHD_YES != daemon->shutdown) { @@ -3695,6 +3729,17 @@ MHD_select_thread (void *cls) MHD_select (daemon, MHD_YES); MHD_cleanup_connections (daemon); } + + /* give resumed formerly suspended connections a chance to + be included in the cleanup */ + resume_suspended_connections (daemon); + /* run clean up in this thread as well */ + if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + /* We did everything in this thread, so also the clean up */ + while (NULL != (pos = daemon->connections_head)) + close_connection (pos); + } return (MHD_THRD_RTRN_TYPE_)0; } @@ -5040,11 +5085,11 @@ MHD_start_daemon_va (unsigned int flags, } /* Spawn the worker thread */ - if (! MHD_create_named_thread_(&d->pid, - "MHD-worker", - daemon->thread_stack_size, - &MHD_select_thread, - d)) + if (! MHD_create_named_thread_ (&d->pid, + "MHD-worker", + daemon->thread_stack_size, + &MHD_select_thread, + d)) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, @@ -5128,39 +5173,6 @@ thread_failed: /** - * Close the given connection, remove it from all of its - * DLLs and move it into the cleanup queue. - * - * @param pos connection to move to cleanup - */ -static void -close_connection (struct MHD_Connection *pos) -{ - struct MHD_Daemon *daemon = pos->daemon; - - MHD_connection_close_ (pos, - MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); - if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) - return; /* must let thread to the rest */ - if (pos->connection_timeout == pos->daemon->connection_timeout) - XDLL_remove (daemon->normal_timeout_head, - daemon->normal_timeout_tail, - pos); - else - XDLL_remove (daemon->manual_timeout_head, - daemon->manual_timeout_tail, - pos); - DLL_remove (daemon->connections_head, - daemon->connections_tail, - pos); - pos->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; - DLL_insert (daemon->cleanup_head, - daemon->cleanup_tail, - pos); -} - - -/** * Close all connections for the daemon; must only be called after * all of the threads have been joined and there is no more concurrent * activity on the connection lists. @@ -5347,7 +5359,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) if (! MHD_itc_activate_ (daemon->worker_pool[i].itc, "e")) MHD_PANIC (_("Failed to signal shutdown via inter-thread communication channel.")); } - if (!MHD_join_thread_ (daemon->worker_pool[i].pid)) + if (! MHD_join_thread_ (daemon->worker_pool[i].pid)) MHD_PANIC (_("Failed to join a thread\n")); close_all_connections (&daemon->worker_pool[i]); MHD_mutex_destroy_chk_ (&daemon->worker_pool[i].cleanup_connection_mutex); @@ -5377,7 +5389,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) ( (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) && (0 == daemon->worker_pool_size) ) ) { - if (!MHD_join_thread_ (daemon->pid)) + if (! MHD_join_thread_ (daemon->pid)) { MHD_PANIC (_("Failed to join a thread\n")); } diff --git a/src/microhttpd/test_upgrade.c b/src/microhttpd/test_upgrade.c @@ -63,6 +63,9 @@ test_upgrade (int flags, 1080, NULL, NULL, &ahc_upgrade, NULL, + MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, + MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL, + MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL, MHD_OPTION_THREAD_POOL_SIZE, pool, MHD_OPTION_END); if (NULL == d) @@ -101,6 +104,8 @@ main (int argc, int error_count = 0; /* try external select */ +#if 0 + error_count += test_upgrade (0, 0); #ifdef EPOLL_SUPPORT @@ -117,6 +122,9 @@ main (int argc, /* Test different event loops, with and without thread pool */ error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY, 0); + +#endif + error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY, 2); #ifdef HAVE_POLL diff --git a/src/microhttpd/test_upgrade_common.c b/src/microhttpd/test_upgrade_common.c @@ -46,6 +46,88 @@ static pthread_t pt_client; static int done; +static void +notify_completed_cb (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) && + (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) && + (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) ) + abort (); + if (((long) *con_cls) != (long) pthread_self ()) + abort (); + *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) +{ + if (0 != strcmp (uri, + "/")) + abort (); + return (void *) (long) pthread_self (); +} + + +/** + * 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; + + 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 non-blocking. @@ -354,6 +436,8 @@ ahc_upgrade (void *cls, struct MHD_Response *resp; int ret; + if (((long) *con_cls) != (long) pthread_self ()) + abort (); resp = MHD_create_response_for_upgrade (&upgrade_cb, NULL); MHD_add_response_header (resp, diff --git a/src/microhttpd/test_upgrade_ssl.c b/src/microhttpd/test_upgrade_ssl.c @@ -117,6 +117,9 @@ test_upgrade (int flags, 1080, NULL, NULL, &ahc_upgrade, NULL, + MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, + MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL, + MHD_OPTION_NOTIFY_CONNECTION, &notify_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,