libmicrohttpd

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

commit b90f356c47e467407ae407723ddb02161b849f6a
parent 21b2dd96aaffa8e2d0937a339bbdace882db0fee
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue,  6 Feb 2018 17:50:46 +0100

starting with mhd2 api implementation

Diffstat:
Mconfigure.ac | 7+++++++
Msrc/include/microhttpd2.h | 40+++++++++++++++++++++++++---------------
Asrc/lib/connection_options.c | 16++++++++++++++++
Asrc/lib/daemon.c | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/daemon_options.c | 713+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/internal.h | 412+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/request.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/daemon.c | 5+++--
8 files changed, 1416 insertions(+), 17 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -2003,6 +2003,13 @@ AC_SUBST(LDFLAGS) AC_SUBST([ac_configure_args]) AC_SUBST([EMPTY_VAR], [[]]) +# We define the paths here, because MinGW/GCC expands paths +# passed through the command line ("-DDIR=..."). This would +# lead to hard-coded paths ("C:\mingw\mingw\bin...") that do +# not contain the actual installation. +AC_DEFINE_DIR([MHD_PLUGIN_INSTALL_PREFIX], [libdir/libmicrohttpd], [tls plugins]) + + AC_CONFIG_FILES([libmicrohttpd.pc w32/common/microhttpd_dll_res_vc.rc po/configure.acT:po/configure.ac.in diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -145,6 +145,17 @@ enum MHD_StatusCode * supported by the selected backend. */ MHD_TLS_CIPHERS_INVALID = 50002 + + /** + * The application attempted to setup TLS paramters before + * enabling TLS. + */ + MHD_TLS_BACKEND_UNINITIALIZED = 50003, + + /** + * The selected TLS backend does not yet support this operation. + */ + MHD_TLS_BACKEND_OPERATION_UNSUPPORTED = 50004, }; @@ -403,8 +414,9 @@ typedef struct MHD_Action * * * @param cb function to be called for incoming requests * @param cb_cls closure for @a cb + * @return NULL on error */ -struct MHD_Daemon * +_MHD_EXTERN struct MHD_Daemon * MHD_daemon_create (MHD_RequestCallback cb, void *cb_cls); @@ -621,7 +633,7 @@ enum MHD_AddressFamily /** * Pick "best" available method automatically. */ - MHD_AF_AUTO, + MHD_AF_AUTO = 0, /** * Use IPv4. @@ -672,7 +684,7 @@ MHD_daemon_bind_port (struct MHD_Daemon *daemon, _MHD_EXTERN void MHD_daemon_bind_socket_address (struct MHD_Daemon *daemon, const struct sockaddr *sa, - size_t sa_lem); + size_t sa_len); /** @@ -683,8 +695,8 @@ MHD_daemon_bind_socket_address (struct MHD_Daemon *daemon, * @param listen_backlog backlog to use */ _MHD_EXTERN void -MHD_daemon_listen_queue (struct MHD_Daemon *daemon, - int listen_backlog); +MHD_daemon_listen_backlog (struct MHD_Daemon *daemon, + int listen_backlog); /** @@ -810,7 +822,7 @@ MHD_daemon_protocol_strict_level (struct MHD_Daemon *daemon, * @param daemon which instance should be configured * @param tls_backend which TLS backend should be used, * currently only "gnutls" is supported. You can - * also specify "NULL" for best-available (which is the default). + * also specify NULL for best-available (which is the default). * @param ciphers which ciphers should be used by TLS, default is * "NORMAL" * @return status code, #MHD_SC_OK upon success @@ -1054,8 +1066,6 @@ typedef void * @param daemon daemon to set callback for * @param ncc function to call to check the policy * @param ncc_cls closure for @a apc - * @param ccc function to call upon completion, NULL for none - * @param ccc_cls closure for @a ccc */ _MHD_EXTERN void MHD_daemon_set_notify_connection (struct MHD_Daemon *daemon, @@ -1064,7 +1074,7 @@ MHD_daemon_set_notify_connection (struct MHD_Daemon *daemon, /** - * Maximum memory size per connection (followed by a `size_t`). + * Maximum memory size per connection. * Default is 32 kb (#MHD_POOL_SIZE_DEFAULT). * Values above 128k are unlikely to result in much benefit, as half * of the memory will be typically used for IO, and TCP buffers are @@ -1178,15 +1188,15 @@ MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon, /** - * Size of the internal array holding the map of the nonce and + * Length of the internal array holding the map of the nonce and * the nonce counter. * * @param daemon daemon to configure * @param nc_length desired array length */ _MHD_EXTERN void -MHD_daemon_digest_auth_nc_size (struct MHD_Daemon *daemon, - size_t stack_limit_b); +MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, + size_t nc_length); /* ********************* connection options ************** */ @@ -1201,7 +1211,7 @@ MHD_daemon_digest_auth_nc_size (struct MHD_Daemon *daemon, * @param connection connection to configure timeout for * @param timeout_s new timeout in seconds */ -struct MHD_ConnectionOption +_MHD_EXTERN struct MHD_ConnectionOption MHD_connection_timeout (struct MHD_Connection *connection, unsigned int timeout_s); @@ -1443,7 +1453,7 @@ MHD_request_resume (struct MHD_Request *request); * as a response *is* an action. As no memory is * allocated, this operation cannot fail. */ -struct MHD_Action * +_MHD_EXTERN struct MHD_Action * MHD_action_from_response (struct MHD_Response *response, enum MHD_bool destroy_after_use); @@ -1484,7 +1494,7 @@ typedef void * @param termination_cb function to call * @param termination_cb_cls closure for @e termination_cb */ -void +_MHD_EXTERN void MHD_response_option_termination_callback (struct MHD_Response *response, MHD_RequestTerminationCallback termination_cb, void *termination_cb_cls); diff --git a/src/lib/connection_options.c b/src/lib/connection_options.c @@ -0,0 +1,16 @@ + +/** + * Generate option to set a custom timeout for the given connection. + * Specified as the number of seconds. Use zero for no timeout. If + * timeout was set to zero (or unset) before, setting of a new value + * by MHD_connection_set_option() will reset timeout timer. + * + * @param connection connection to configure timeout for + * @param timeout_s new timeout in seconds + */ +struct MHD_ConnectionOption +MHD_connection_timeout (struct MHD_Connection *connection, + unsigned int timeout_s); + + + diff --git a/src/lib/daemon.c b/src/lib/daemon.c @@ -0,0 +1,172 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/daemon.c + * @brief main functions to create, start, quiesce and destroy a daemon + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Logging implementation that logs to a file given + * as the @a cls. + * + * @param cls a `FILE *` to log to + * @param sc status code of the event (ignored) + * @param fm format string (`printf()`-style) + * @param ap arguments to @a fm + * @ingroup logging + */ +static void +file_logger (void *cls, + enum MHD_StatusCode sc, + const char *fm, + va_list ap) +{ + FILE *f = cls; + + (void) sc; + (void) vfprintf (f, + fm, + ap); +} + + +/** + * Process escape sequences ('%HH') Updates val in place; the + * result should be UTF-8 encoded and cannot be larger than the input. + * The result must also still be 0-terminated. + * + * @param cls closure (use NULL) + * @param req handle to request, not used + * @param val value to unescape (modified in the process) + * @return length of the resulting val (strlen(val) maybe + * shorter afterwards due to elimination of escape sequences) + */ +static size_t +unescape_wrapper (void *cls, + struct MHD_Request *req, + char *val) +{ + (void) cls; /* Mute compiler warning. */ + (void) req; /* Mute compiler warning. */ + return MHD_http_unescape (val); +} + + +/** + * Create (but do not yet start) an MHD daemon. + * Usually, you will want to set various options before + * starting the daemon with #MHD_daemon_start(). + * + * @param cb function to be called for incoming requests + * @param cb_cls closure for @a cb + * @return NULL on error + */ +struct MHD_Daemon * +MHD_daemon_create (MHD_RequestCallback cb, + void *cb_cls) +{ + struct MHD_Daemon *daemon; + + MHD_check_global_init_(); + if (NULL == cb) + return NULL; + if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon)))) + return NULL; + memset (daemon, + 0, + sizeof (struct MHD_Daemon)); + daemon->rc = cb; + daemon->rc_cls = cb_cls; + daemon->logger = &file_logger; + daemon->logger_cls = stderr; + daemon->unescape_cb = &unescape_wrapper; + daemon->tls_ciphers = TLS_CIPHERS_DEFAULT; + daemon->connection_memory_limit_b = MHD_POOL_SIZE_DEFAULT; + daemon->connection_memory_increment_b = BUF_INC_SIZE_DEFAULT; +#if ENABLE_DAUTH + daemon->digest_nc_length = DIGEST_NC_LENGTH_DEFAULT; +#endif + daemon->listen_backlog = LISTEN_BACKLOG_DEFAULT; + daemon->fo_queue_length = FO_QUEUE_LENGTH_DEFAULT; + daemon->listen_socket = MHD_INVALID_SOCKET; + return daemon; +} + + +/** + * Start a webserver. + * + * @param daemon daemon to start; you can no longer set + * options on this daemon after this call! + * @return #MHD_SC_OK on success + * @ingroup event + */ +enum MHD_StatusCode +MHD_daemon_start (struct MHD_Daemon *daemon) +{ + + return -1; +} + + +/** + * Stop accepting connections from the listening socket. Allows + * clients to continue processing, but stops accepting new + * connections. Note that the caller is responsible for closing the + * returned socket; however, if MHD is run using threads (anything but + * external select mode), it must not be closed until AFTER + * #MHD_stop_daemon has been called (as it is theoretically possible + * that an existing thread is still using it). + * + * Note that some thread modes require the caller to have passed + * #MHD_USE_ITC when using this API. If this daemon is + * in one of those modes and this option was not given to + * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET. + * + * @param daemon daemon to stop accepting new connections for + * @return old listen socket on success, #MHD_INVALID_SOCKET if + * the daemon was already not listening anymore, or + * was never started + * @ingroup specialized + */ +MHD_socket +MHD_daemon_quiesce (struct MHD_Daemon *daemon) +{ + return -1; +} + + +/** + * Shutdown and destroy an HTTP daemon. + * + * @param daemon daemon to stop + * @ingroup event + */ +void +MHD_daemon_destroy (struct MHD_Daemon *daemon) +{ + free (daemon); +} + + +/* end of daemon.c */ diff --git a/src/lib/daemon_options.c b/src/lib/daemon_options.c @@ -0,0 +1,713 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/daemon_options.c + * @brief boring functions to manipulate daemon options + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Set logging method. Specify NULL to disable logging entirely. By + * default (if this option is not given), we log error messages to + * stderr. + * + * @param daemon which instance to setup logging for + * @param logger function to invoke + * @param logger_cls closure for @a logger + */ +void +MHD_daemon_set_logger (struct MHD_Daemon *daemon, + MHD_LoggingCallback logger, + void *logger_cls) +{ + daemon->logger = logger; + daemon->logger_cls = logger_cls; +} + + +/** + * Suppress use of "Date" header as this system has no RTC. + * + * @param daemon which instance to disable clock for. + */ +void +MHD_daemon_suppress_date_no_clock (struct MHD_Daemon *daemon) +{ + daemon->suppress_date = true; +} + + +/** + * Disable use of inter-thread communication channel. + * #MHD_daemon_disable_itc() can be used with + * #MHD_daemon_thread_internal() to perform some additional + * optimizations (in particular, not creating a pipe for IPC + * signalling). If it is used, certain functions like + * #MHD_daemon_quiesce() or #MHD_connection_add() or + * #MHD_action_suspend() cannot be used anymore. + * #MHD_daemon_disable_itc() is not beneficial on platforms where + * select()/poll()/other signal shutdown() of a listen socket. + * + * You should only use this function if you are sure you do + * satisfy all of its requirements and need a generally minor + * boost in performance. + * + * @param daemon which instance to disable itc for + */ +void +MHD_daemon_disable_itc (struct MHD_Daemon *daemon) +{ + daemon->disable_itc = true; +} + + +/** + * Enable `turbo`. Disables certain calls to `shutdown()`, + * enables aggressive non-blocking optimistic reads and + * other potentially unsafe optimizations. + * Most effects only happen with #MHD_ELS_EPOLL. + * + * @param daemon which instance to enable turbo for + */ +void +MHD_daemon_enable_turbo (struct MHD_Daemon *daemon) +{ + daemon->enable_turbo = true; +} + + +/** + * Disable #MHD_action_suspend() functionality. + * + * You should only use this function if you are sure you do + * satisfy all of its requirements and need a generally minor + * boost in performance. + * + * @param daemon which instance to disable suspend for + */ +void +MHD_daemon_disallow_suspend_resume (struct MHD_Daemon *daemon) +{ + daemon->disallow_suspend_resume = true; +} + + +/** + * You need to set this option if you want to disable use of HTTP "Upgrade". + * "Upgrade" may require usage of additional internal resources, + * which we can avoid providing if they will not be used. + * + * You should only use this function if you are sure you do + * satisfy all of its requirements and need a generally minor + * boost in performance. + * + * @param daemon which instance to enable suspend/resume for + */ +void +MHD_daemon_disallow_upgrade (struct MHD_Daemon *daemon) +{ + daemon->disallow_upgrade; +} + + +/** + * Configure TCP_FASTOPEN option, including setting a + * custom @a queue_length. + * + * Note that having a larger queue size can cause resource exhaustion + * attack as the TCP stack has to now allocate resources for the SYN + * packet along with its DATA. + * + * @param daemon which instance to configure TCP_FASTOPEN for + * @param fom under which conditions should we use TCP_FASTOPEN? + * @param queue_length queue length to use, default is 50 if this + * option is never given. + * @return #MHD_YES upon success, #MHD_NO if #MHD_FOM_REQUIRE was + * given, but TCP_FASTOPEN is not available on the platform + */ +enum MHD_Bool +MHD_daemon_tcp_fastopen (struct MHD_Daemon *daemon, + enum MHD_FastOpenMethod fom, + unsigned int queue_length) +{ + daemon->fast_open_method = fom; + daemon->fast_open_queue_length = queue_length; + switch (fom) + { + case MHD_FOM_DISABLE: + return MHD_YES; + case MHD_FOM_AUTO: + return MHD_YES; + case MHD_FOM_REQUIRE: +#ifdef TCP_FASTOPEN + return MHD_YES; +#else + return MHD_NO; +#endif + } +} + + +/** + * Bind to the given TCP port and address family. + * + * Ineffective in conjunction with #MHD_daemon_listen_socket(). + * Ineffective in conjunction with #MHD_daemon_bind_sa(). + * + * If neither this option nor the other two mentioned above + * is specified, MHD will simply not listen on any socket! + * + * @param daemon which instance to configure the TCP port for + * @param af address family to use + * @param port port to use, 0 to bind to a random (free) port + */ +void +MHD_daemon_bind_port (struct MHD_Daemon *daemon, + enum MHD_AddressFamily af, + uint16_t port) +{ + daemon->listen_af = af; + daemon->listen_port = port; +} + + +/** + * Bind to the given socket address. + * Ineffective in conjunction with #MHD_daemon_listen_socket(). + * + * @param daemon which instance to configure the binding address for + * @param sa address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6) + * or even a UNIX domain socket (AF_UNIX) + * @param sa_len number of bytes in @a sa + */ +void +MHD_daemon_bind_socket_address (struct MHD_Daemon *daemon, + const struct sockaddr *sa, + size_t sa_len) +{ + daemon->sa_given = true; + memcpy (&daemon->listen_sa, + sa, + sa_len); + daemon->listen_sa_len = sa_len; +} + + +/** + * Use the given backlog for the listen() call. + * Ineffective in conjunction with #MHD_daemon_listen_socket(). + * + * @param daemon which instance to configure the backlog for + * @param listen_backlog backlog to use + */ +void +MHD_daemon_listen_backlog (struct MHD_Daemon *daemon, + int listen_backlog) +{ + daemon->listen_backlog = listen_backlog; +} + + +/** + * If present true, allow reusing address:port socket (by using + * SO_REUSEPORT on most platform, or platform-specific ways). If + * present and set to false, disallow reusing address:port socket + * (does nothing on most plaform, but uses SO_EXCLUSIVEADDRUSE on + * Windows). + * Ineffective in conjunction with #MHD_daemon_listen_socket(). + * + * @param daemon daemon to configure address reuse for + */ +void +MHD_daemon_listen_allow_address_reuse (struct MHD_Daemon *daemon) +{ + daemon->allow_address_reuse = true; +} + + +/** + * Accept connections from the given socket. Socket + * must be a TCP or UNIX domain (stream) socket. + * + * Unless -1 is given, this disables other listen options, including + * #MHD_daemon_bind_sa(), #MHD_daemon_bind_port(), + * #MHD_daemon_listen_queue() and + * #MHD_daemon_listen_allow_address_reuse(). + * + * @param daemon daemon to set listen socket for + * @param listen_socket listen socket to use, + * MHD_INVALID_SOCKET value will cause this call to be + * ignored (other binding options may still be effective) + */ +void +MHD_daemon_listen_socket (struct MHD_Daemon *daemon, + MHD_socket listen_socket) +{ + daemon->listen_socket = listen_socket; +} + + +/** + * Force use of a particular event loop system call. + * + * @param daemon daemon to set event loop style for + * @param els event loop syscall to use + * @return #MHD_NO on failure, #MHD_YES on success + */ +enum MHD_Bool +MHD_daemon_event_loop (struct MHD_Daemon *daemon, + enum MHD_EventLoopSyscall els) +{ + switch (els) + { + case MHD_ELS_AUTO: + break; /* should always be OK */ + case MHD_ELS_SELECT: + break; /* should always be OK */ + case MHD_ELS_POLL: +#ifdef HAVE_POLL + break; +#else + return MHD_NO; /* not supported */ +#endif + case MHD_ELS_EPOLL: +#ifdef EPOLL_SUPPORT + break; +#else + return MHD_NO; /* not supported */ +#endif + default: + return MHD_NO; /* not supported (presumably future ABI extension) */ + } + daemon->event_loop_syscall = els; + return MHD_YES; +} + + +/** + * Set how strictly MHD will enforce the HTTP protocol. + * + * @param daemon daemon to configure strictness for + * @param sl how strict should we be + */ +void +MHD_daemon_protocol_strict_level (struct MHD_Daemon *daemon, + enum MHD_ProtocolStrictLevel sl) +{ + daemon->protocol_strict_level = sl; +} + + +/** + * Enable and configure TLS. + * + * @param daemon which instance should be configured + * @param tls_backend which TLS backend should be used, + * currently only "gnutls" is supported. You can + * also specify NULL for best-available (which is the default). + * @param ciphers which ciphers should be used by TLS, default is + * "NORMAL" + * @return status code, #MHD_SC_OK upon success + * #MHD_TLS_BACKEND_UNSUPPORTED if the @a backend is unknown + * #MHD_TLS_DISABLED if this build of MHD does not support TLS + * #MHD_TLS_CIPHERS_INVALID if the given @a ciphers are not supported + * by this backend + */ +enum MHD_StatusCode +MHD_daemon_set_tls_backend (struct MHD_Daemon *daemon, + const char *tls_backend, + const char *ciphers) +{ +#ifndef HTTPS_SUPPORT + return MHD_TLS_DISABLED; +#else + char filename[1024]; + int res; + MHD_TLS_PluginInit init; + + /* todo: .dll on W32? */ + res = MHD_snprintf (filename, + sizeof (filename), + "%s/libmicrohttpd_tls_%s.so", + MHD_PLUGIN_INSTALL_PREFIX, + tls_backend); + if (0 >= res) + return MHD_BACKEND_UNSUPPORTED; /* string too long? */ + if (NULL == + (daemon->tls_backend_lib = dlopen (filename, + RTLD_NOW | RTLD_LOCAL))) + return MHD_BACKEND_UNSUPPORTED; /* plugin not found */ + if (NULL == (init = dlsym (daemon->tls_backend_lib, + "MHD_TLS_init_" MHD_TLS_ABI_VERSION_STR))) + + { + dlclose (daemon->tls_backend_lib); + daemon->tls_backend_lib = NULL; + return MHD_BACKEND_UNSUPPORTED; /* possibly wrong version installed */ + } + if (NULL == (daemon->tls_backend = init (ciphers))) + { + dlclose (daemon->tls_backend_lib); + daemon->tls_backend_lib = NULL; + return MHD_CIPHERS_INVALID; /* possibly wrong version installed */ + } + return MHD_SC_OK; +#endif +} + + +/** + * Provide TLS key and certificate data in-memory. + * + * @param daemon which instance should be configured + * @param mem_key private key (key.pem) to be used by the + * HTTPS daemon. Must be the actual data in-memory, not a filename. + * @param mem_cert certificate (cert.pem) to be used by the + * HTTPS daemon. Must be the actual data in-memory, not a filename. + * @param pass passphrase phrase to decrypt 'key.pem', NULL + * if @param mem_key is in cleartext already + * @return #MHD_SC_OK upon success; MHD_BACKEND_UNINITIALIZED + * if the TLS backend is not yet setup. + */ +enum MHD_StatusCode +MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon, + const char *mem_key, + const char *mem_cert, + const char *pass) +{ + struct MHD_TLS_Plugin *plugin; + + if (NULL == (plugin = daemon->tls_backend)) + return MHD_TLS_BACKEND_UNINITIALIZED; + return plugin->init_kcp (plugin->cls, + mem_key, + mem_cert, + pass); +} + + +/** + * Configure DH parameters (dh.pem) to use for the TLS key + * exchange. + * + * @param daemon daemon to configure tls for + * @param dh parameters to use + * @return #MHD_SC_OK upon success; MHD_BACKEND_UNINITIALIZED + * if the TLS backend is not yet setup. + */ +enum MHD_StatusCode +MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon, + const char *dh) +{ + struct MHD_TLS_Plugin *plugin; + + if (NULL == (plugin = daemon->tls_backend)) + return MHD_TLS_BACKEND_UNINITIALIZED; + return plugin->init_dhparams (plugin->cls, + dh); +} + + +/** + * Memory pointer for the certificate (ca.pem) to be used by the + * HTTPS daemon for client authentification. + * + * @param daemon daemon to configure tls for + * @param mem_trust memory pointer to the certificate + * @return #MHD_SC_OK upon success; MHD_BACKEND_UNINITIALIZED + * if the TLS backend is not yet setup. + */ +enum MHD_StatusCode +MHD_daemon_tls_mem_trust (struct MHD_Daemon *daemon, + const char *mem_trust) +{ + struct MHD_TLS_Plugin *plugin; + + if (NULL == (plugin = daemon->tls_backend)) + return MHD_TLS_BACKEND_UNINITIALIZED; + return plugin->init_mem_trust (plugin->cls, + mem_trust); +} + + +/** + * Configure daemon credentials type for GnuTLS. + * + * @param gnutls_credentials must be a value of + * type `gnutls_credentials_type_t` + * @return #MHD_SC_OK upon success; TODO: define failure modes + */ +enum MHD_StatusCode +MHD_daemon_gnutls_credentials (struct MHD_Daemon *daemon, + int gnutls_credentials) +{ + struct MHD_TLS_Plugin *plugin; + + if (NULL == (plugin = daemon->tls_backend)) + return MHD_TLS_BACKEND_UNINITIALIZED; + return MHD_TLS_BACKEND_OPERATION_UNSUPPORTED; +} + + +/** + * Provide TLS key and certificate data via callback. + * + * Use a callback to determine which X.509 certificate should be used + * for a given HTTPS connection. This option provides an alternative + * to #MHD_daemon_tls_key_and_cert_from_memory(). You must use this + * version if multiple domains are to be hosted at the same IP address + * using TLS's Server Name Indication (SNI) extension. In this case, + * the callback is expected to select the correct certificate based on + * the SNI information provided. The callback is expected to access + * the SNI data using `gnutls_server_name_get()`. Using this option + * requires GnuTLS 3.0 or higher. + * + * @param daemon daemon to configure callback for + * @param cb must be of type `gnutls_certificate_retrieve_function2 *`. + */ +void +MHD_daemon_gnutls_key_and_cert_from_callback (struct MHD_Daemon *daemon, + void *cb) +{ + struct MHD_TLS_Plugin *plugin; + + if (NULL == (plugin = daemon->tls_backend)) + return MHD_TLS_BACKEND_UNINITIALIZED; + return MHD_TLS_BACKEND_OPERATION_UNSUPPORTED; +} + + +/** + * Specify threading model to use. + * + * @param daemon daemon to configure + * @param tm model to use (positive values indicate the + * number of worker threads to be used) + */ +void +MHD_daemon_threading_model (struct MHD_Daemon *daemon, + enum MHD_ThreadingModel tm) +{ + daemon->threading_model = tm; +} + + +/** + * Set a policy callback that accepts/rejects connections + * based on the client's IP address. This function will be called + * before a connection object is created. + * + * @param daemon daemon to set policy for + * @param apc function to call to check the policy + * @param apc_cls closure for @a apc + */ +void +MHD_daemon_accept_policy (struct MHD_Daemon *daemon, + MHD_AcceptPolicyCallback apc, + void *apc_cls) +{ + daemon->accept_policy_cb = apc; + daemon->accept_policy_cb_cls = apc_cls; +} + + +/** + * Register a callback to be called first for every request + * (before any parsing of the header). Makes it easy to + * log the full URL. + * + * @param daemon daemon for which to set the logger + * @param cb function to call + * @param cb_cls closure for @a cb + */ +void +MHD_daemon_set_early_uri_logger (struct MHD_Daemon *daemon, + MHD_EarlyUriLogCallback cb, + void *cb_cls) +{ + daemon->early_uri_logger_cb = cb; + daemon->early_uri_logger_cb_cls = cb_cls; +} + + +/** + * Register a function that should be called whenever a connection is + * started or closed. + * + * @param daemon daemon to set callback for + * @param ncc function to call to check the policy + * @param ncc_cls closure for @a apc + */ +void +MHD_daemon_set_notify_connection (struct MHD_Daemon *daemon, + MHD_NotifyConnectionCallback ncc, + void *ncc_cls) +{ + daemon->notify_connection_cb = ncc; + daemon->notify_connection_cb_cls = ncc_cls; +} + + +/** + * Maximum memory size per connection. + * Default is 32 kb (#MHD_POOL_SIZE_DEFAULT). + * Values above 128k are unlikely to result in much benefit, as half + * of the memory will be typically used for IO, and TCP buffers are + * unlikely to support window sizes above 64k on most systems. + * + * @param daemon daemon to configure + * @param memory_limit_b connection memory limit to use in bytes + * @param memory_increment_b increment to use when growing the read buffer, must be smaller than @a memory_limit_b + */ +void +MHD_daemon_connection_memory_limit (struct MHD_Daemon *daemon, + size_t memory_limit_b, + size_t memory_increment_b) +{ + if (memory_increment_b >= memory_limit_b) + MHD_PANIC ("sane memory increment must be below memory limit"); + daemon->connection_memory_limit_b = memory_limit_b; + daemon->connection_memory_increment_b = memory_increment_b; +} + + +/** + * Desired size of the stack for threads created by MHD. Use 0 for + * system default. Only useful if the selected threading model + * is not #MHD_TM_EXTERNAL_EVENT_LOOP. + * + * @param daemon daemon to configure + * @param stack_limit_b stack size to use in bytes + */ +void +MHD_daemon_thread_stack_size (struct MHD_Daemon *daemon, + size_t stack_limit_b) +{ + daemon->thread_stack_limit_b = stack_limit_b; +} + + +/** + * Set maximum number of concurrent connections to accept. If not + * given, MHD will not enforce any limits (modulo running into + * OS limits). Values of 0 mean no limit. + * + * @param daemon daemon to configure + * @param global_connection_limit maximum number of (concurrent) + connections + * @param ip_connection_limit limit on the number of (concurrent) + * connections made to the server from the same IP address. + * Can be used to prevent one IP from taking over all of + * the allowed connections. If the same IP tries to + * establish more than the specified number of + * connections, they will be immediately rejected. + */ +void +MHD_daemon_connection_limits (struct MHD_Daemon *daemon, + unsigned int global_connection_limit, + unsigned int ip_connection_limit) +{ + daemon->global_connection_limit = global_connection_limit; + daemon->ip_connection_limit = ip_connection_limit; +} + + +/** + * After how many seconds of inactivity should a + * connection automatically be timed out? + * Use zero for no timeout, which is also the (unsafe!) default. + * + * @param daemon daemon to configure + * @param timeout_s number of seconds of timeout to use + */ +void +MHD_daemon_connection_default_timeout (struct MHD_Daemon *daemon, + unsigned int timeout_s) +{ + daemon->connection_default_timeout_s = timeout_s; +} + + +/** + * Specify a function that should be called for unescaping escape + * sequences in URIs and URI arguments. Note that this function + * will NOT be used by the `struct MHD_PostProcessor`. If this + * option is not specified, the default method will be used which + * decodes escape sequences of the form "%HH". + * + * @param daemon daemon to configure + * @param unescape_cb function to use, NULL for default + * @param unescape_cb_cls closure for @a unescape_cb + */ +void +MHD_daemon_unescape_cb (struct MHD_Daemon *daemon, + MHD_UnescapeCallback unescape_cb, + void *unescape_cb_cls) +{ + daemon->unescape_cb = unescape_cb; + daemon->unescape_cb_cls = unescape_cb_cls; +} + + +/** + * Set random values to be used by the Digest Auth module. Note that + * the application must ensure that @a buf remains allocated and + * unmodified while the deamon is running. + * + * @param daemon daemon to configure + * @param buf_size number of bytes in @a buf + * @param buf entropy buffer + */ +void +MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon, + size_t buf_size, + const void *buf) +{ +#if ENABLE_DAUTH + daemon->digest_auth_random_buf = buf; + daemon->digest_auth_random_buf_size = buf_size; +#else + MHD_PANIC ("digest authentication not supported by this build"); +#endif +} + + +/** + * Length of the internal array holding the map of the nonce and + * the nonce counter. + * + * @param daemon daemon to configure + * @param nc_length desired array length + */ +void +MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, + size_t nc_length) +{ +#if ENABLE_DAUTH + daemon->digest_nc_length = nc_length; +#else + MHD_PANIC ("digest authentication not supported by this build"); +#endif +} + + +/* end of daemon_options.c */ diff --git a/src/lib/internal.h b/src/lib/internal.h @@ -0,0 +1,412 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2017 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file microhttpd/internal.h + * @brief internal shared structures + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#ifndef INTERNAL_H +#define INTERNAL_H + +#include "mhd_options.h" +#include "platform.h" +#include "microhttpd2.h" +#include "microhttpd_tls.h" +#include "mhd_assert.h" + +#ifdef HTTPS_SUPPORT +#include <gnutls/gnutls.h> +#if GNUTLS_VERSION_MAJOR >= 3 +#include <gnutls/abstract.h> +#endif +#endif /* HTTPS_SUPPORT */ + +#ifdef HAVE_STDBOOL_H +#include <stdbool.h> +#endif +#ifdef MHD_PANIC +/* Override any defined MHD_PANIC macro with proper one */ +#undef MHD_PANIC +#endif /* MHD_PANIC */ + +#ifdef HAVE_MESSAGES +/** + * Trigger 'panic' action based on fatal errors. + * + * @param msg error message (const char *) + */ +#define MHD_PANIC(msg) do { mhd_panic (mhd_panic_cls, __FILE__, __LINE__, msg); BUILTIN_NOT_REACHED; } while (0) +#else +/** + * Trigger 'panic' action based on fatal errors. + * + * @param msg error message (const char *) + */ +#define MHD_PANIC(msg) do { mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); BUILTIN_NOT_REACHED; } while (0) +#endif + +#include "mhd_threads.h" +#include "mhd_locks.h" +#include "mhd_sockets.h" +#include "mhd_itc_types.h" + + +/** + * Close FD and abort execution if error is detected. + * @param fd the FD to close + */ +#define MHD_fd_close_chk_(fd) do { \ + if (0 == close ((fd)) && (EBADF == errno)) \ + MHD_PANIC(_("Failed to close FD.\n")); \ + } while(0) + +/** + * Should we perform additional sanity checks at runtime (on our internal + * invariants)? This may lead to aborts, but can be useful for debugging. + */ +#define EXTRA_CHECKS MHD_NO + +#define MHD_MAX(a,b) (((a)<(b)) ? (b) : (a)) +#define MHD_MIN(a,b) (((a)<(b)) ? (a) : (b)) + + +/** + * Minimum size by which MHD tries to increment read/write buffers. + * We usually begin with half the available pool space for the + * IO-buffer, but if absolutely needed we additively grow by the + * number of bytes given here (up to -- theoretically -- the full pool + * space). + */ +#define MHD_BUF_INC_SIZE 1024 + + +/** + * Handler for fatal errors. + */ +extern MHD_PanicCallback mhd_panic; + +/** + * Closure argument for "mhd_panic". + */ +extern void *mhd_panic_cls; + +/* If we have Clang or gcc >= 4.5, use __buildin_unreachable() */ +#if defined(__clang__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#define BUILTIN_NOT_REACHED __builtin_unreachable() +#elif defined(_MSC_FULL_VER) +#define BUILTIN_NOT_REACHED __assume(0) +#else +#define BUILTIN_NOT_REACHED +#endif + +#ifndef MHD_STATICSTR_LEN_ +/** + * Determine length of static string / macro strings at compile time. + */ +#define MHD_STATICSTR_LEN_(macro) (sizeof(macro)/sizeof(char) - 1) +#endif /* ! MHD_STATICSTR_LEN_ */ + + +/** + * State kept for each MHD daemon. All connections are kept in two + * doubly-linked lists. The first one reflects the state of the + * connection in terms of what operations we are waiting for (read, + * write, locally blocked, cleanup) whereas the second is about its + * timeout state (default or custom). + */ +struct MHD_Daemon +{ + /** + * Function to call to handle incoming requests. + */ + MHD_RequestCallback rc; + + /** + * Closure for @e rc. + */ + void *rc_cls; + + /** + * Function to call for logging. + */ + MHD_LoggingCallback logger; + + /** + * Closure for @e logger. + */ + void *logger_cls; + + /** + * Function to call to accept/reject connections based on + * the client's IP address. + */ + MHD_AcceptPolicyCallback accept_policy_cb; + + /** + * Closure for @e accept_policy_cb. + */ + void *accept_policy_cb_cls; + + /** + * Function to call on the full URL early for logging. + */ + MHD_EarlyUriLogCallback early_uri_logger_cb; + + /** + * Closure for @e early_uri_logger_cb. + */ + void *early_uri_logger_cls; + + /** + * Function to call whenever a connection is started or + * closed. + */ + MHD_NotifyConnectionCallback notify_connection_cb; + + /** + * Closure for @e notify_connection_cb. + */ + void *notify_connection_cb_cls; + + /** + * Function to call to unescape sequences in URIs and URI arguments. + * See #MHD_daemon_unescape_cb(). + */ + MHD_UnescapeCallback unescape_cb; + + /** + * Closure for @e unescape_cb. + */ + void *unescape_cb_cls; + +#if HTTPS_SUPPORT + /** + * Which TLS backend should be used. NULL for no TLS. + * This is merely the handle to the dlsym() object, not + * the API. + */ + void *tls_backend_lib; + + /** + * Callback functions to use for TLS operations. + */ + struct MHD_TLS_Plugin *tls_api; +#endif +#if ENABLE_DAUTH + + /** + * Random values to be used by digest authentication module. + * Size given in @e digest_auth_random_buf_size. + */ + const void *digest_auth_random_buf; +#endif + + /** + * Socket address to bind to for the listen socket. + */ + struct sockaddr_storage listen_sa; + + /** + * Number of (valid) bytes in @e listen_sa. Zero + * if @e listen_sa is not initialized. + */ + size_t listen_sa_len; + + /** + * Buffer size to use for each connection. Default + * is #MHD_POOL_SIZE_DEFAULT. + */ + size_t connection_memory_limit_b; + +/** + * Default minimum size by which MHD tries to increment read/write + * buffers. We usually begin with half the available pool space for + * the IO-buffer, but if absolutely needed we additively grow by the + * number of bytes given here (up to -- theoretically -- the full pool + * space). + */ +#define BUF_INC_SIZE_DEFAULT 1024 + + /** + * Increment to use when growing the read buffer. Smaller + * than @e connection_memory_limit_b. + */ + size_t connection_memory_increment_b; + + /** + * Desired size of the stack for threads created by MHD, + * 0 for system default. + */ + size_t thread_stack_limit_b; + +#if ENABLE_DAUTH + + /** + * Size of @e digest_auth_random_buf. + */ + size_t digest_auth_random_buf_size; + + /** + * Default value for @e digest_nc_length. + */ +#define DIGEST_NC_LENGTH_DEFAULT 4 + + /** + * Desired length of the internal array with the nonce and + * nonce counters for digest authentication. + */ + size_t digest_nc_length; +#endif + + /** + * Default value we use for the listen backlog. + */ +#ifdef SOMAXCONN +#define LISTEN_BACKLOG_DEFAULT SOMAXCONN +#else /* !SOMAXCONN */ +#define LISTEN_BACKLOG_DEFAULT 511 +#endif + + /** + * Backlog argument to use for listen. See + * #MHD_daemon_listen_backlog(). + */ + int listen_backlog; + + /** + * Default queue length to use with fast open. + */ +#define FO_QUEUE_LENGTH_DEFAULT 50 + + /** + * Queue length to use with fast open. + */ + unsigned int fo_queue_length; + + /** + * Maximum number of connections MHD accepts. 0 for unlimited. + */ + unsigned int global_connection_limit; + + /** + * Maximum number of connections we accept per IP, 0 for unlimited. + */ + unsigned int ip_connection_limit; + + /** + * Default timeout in seconds for idle connections. + */ + unsigned int connection_default_timeout_s; + + /** + * Listen socket we should use, MHD_INVALID_SOCKET means + * we are to initialize the socket from the other options given. + */ + MHD_socket listen_socket; + + /** + * Which threading model do we use? Postive + * numbers indicate the number of worker threads to be used. + */ + enum MHD_ThreadingModel threading_model; + + /** + * When should we use TCP_FASTOPEN? + * See #MHD_daemon_tcp_fastopen(). + */ + enum MHD_FastOpenMethod fast_open_method; + + /** + * Address family to use when listening. + * Default is #MHD_AF_AUTO. + */ + enum MHD_AddressFamily listen_af; + + /** + * Sets active/desired style of the event loop. + * (Auto only possible during initialization, later set to + * the actual style we use.) + */ + enum MHD_EventLoopSyscall event_loop_syscall; + + /** + * How strictly do we enforce the HTTP protocol? + * See #MHD_daemon_protocol_strict_level(). + */ + enum MHD_ProtocolStrictLevel protocol_strict_level; + + /** + * On which port should we listen on? Only effective if we were not + * given a listen socket or a full address via + * #MHD_daemon_bind_sa(). 0 means not set, which means to default + * to 80 (http) or 443 (https) respectively. + */ + uint16_t listen_port; + + /** + * Suppress generating the "Date:" header, this system + * lacks an RTC (or developer is hyper-optimizing). See + * #MHD_daemon_suppress_date_no_clock(). + */ + bool suppress_date; + + /** + * The use of the inter-thread communication channel is disabled. + * See #MHD_daemon_disable_itc(). + */ + bool disable_itc; + + /** + * Disable #MHD_action_suspend() functionality. See + * #MHD_daemon_disallow_suspend_resume(). + */ + bool disallow_suspend_resume; + + /** + * Disable #MHD_action_upgrade() functionality. See + * #MHD_daemon_disallow_upgrade(). + */ + bool disallow_upgrade; + + /** + * Disables optional calls to `shutdown()` and enables aggressive + * non-blocking optimistic reads and other potentially unsafe + * optimizations. See #MHD_daemon_enable_turbo(). + */ + bool enable_turbo; + + /** + * Allow reusing the address:port combination when binding. + * See #MHD_daemon_listen_allow_address_reuse(). + */ + bool allow_address_reuse; + + + +}; + + + + + + +#endif diff --git a/src/lib/request.c b/src/lib/request.c @@ -0,0 +1,68 @@ +/** + * Get all of the headers from the request. + * + * @param request request to get values from + * @param kind types of values to iterate over, can be a bitmask + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to @a iterator + * @return number of entries iterated over + * @ingroup request + */ +_MHD_EXTERN unsigned int +MHD_request_get_values (struct MHD_Request *request, + enum MHD_ValueKind kind, + MHD_KeyValueIterator iterator, + void *iterator_cls); + + +/** + * This function can be used to add an entry to the HTTP headers of a + * request (so that the #MHD_request_get_values function will + * return them -- and the `struct MHD_PostProcessor` will also see + * them). This maybe required in certain situations (see Mantis + * #1399) where (broken) HTTP implementations fail to supply values + * needed by the post processor (or other parts of the application). + * + * This function MUST only be called from within the + * request callbacks (otherwise, access maybe improperly + * synchronized). Furthermore, the client must guarantee that the key + * and value arguments are 0-terminated strings that are NOT freed + * until the connection is closed. (The easiest way to do this is by + * passing only arguments to permanently allocated strings.). + * + * @param request the request for which a + * value should be set + * @param kind kind of the value + * @param key key for the value + * @param value the value itself + * @return #MHD_NO if the operation could not be + * performed due to insufficient memory; + * #MHD_YES on success + * @ingroup request + */ +_MHD_EXTERN enum MHD_Bool +MHD_request_set_value (struct MHD_Request *request, + enum MHD_ValueKind kind, + const char *key, + const char *value); + + +/** + * Get a particular header value. If multiple + * values match the kind, return any one of them. + * + * @param request request to get values from + * @param kind what kind of value are we looking for + * @param key the header to look for, NULL to lookup 'trailing' value without a key + * @return NULL if no such item was found + * @ingroup request + */ +_MHD_EXTERN const char * +MHD_request_lookup_value (struct MHD_Request *request, + enum MHD_ValueKind kind, + const char *key); + + + + diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -4456,8 +4456,8 @@ unescape_wrapper (void *cls, struct MHD_Connection *connection, char *val) { - (void)cls; /* Mute compiler warning. */ - (void)connection; /* Mute compiler warning. */ + (void) cls; /* Mute compiler warning. */ + (void) connection; /* Mute compiler warning. */ return MHD_http_unescape (val); } @@ -5425,6 +5425,7 @@ MHD_start_daemon_va (unsigned int flags, MHD_DLOG (daemon, _("Using debug build of libmicrohttpd.\n") ); #endif /* HAVE_MESSAGES */ #endif /* ! NDEBUG */ + if ( (0 != (*pflags & MHD_USE_ITC)) && (0 == daemon->worker_pool_size) ) {