libmicrohttpd

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

commit bf5c5c10f480a01da85ac47ef288f2c2bfea3444
parent 48dd53c7eb6a0ec3f47c23511bcf94d3f6f52e24
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 14 Feb 2018 04:19:04 +0100

fixing misc build issues, mostly in the new src/lib/

Diffstat:
M.gitignore | 1+
Msrc/include/microhttpd2.h | 669+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/include/microhttpd_tls.h | 2+-
Msrc/lib/action_continue.c | 6++++--
Msrc/lib/action_from_response.c | 35+++++++++++++++++------------------
Msrc/lib/action_process_upload.c | 10++++++----
Msrc/lib/action_suspend.c | 7+++++--
Msrc/lib/connection_options.c | 1+
Msrc/lib/daemon_options.c | 63++++++++++++++++++++++++++++++++-------------------------------
Msrc/lib/daemon_start.c | 8++++----
Msrc/lib/init.c | 2++
Msrc/lib/internal.c | 51+++++++++++++++++++++++++++------------------------
Msrc/lib/internal.h | 160++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/lib/request.c | 1+
Msrc/lib/response.c | 4++--
Msrc/lib/response_from_buffer.c | 10+++++-----
Msrc/lib/response_from_fd.c | 4++--
Msrc/lib/version.c | 4++--
Msrc/microhttpd/mhd_sockets.h | 4++--
19 files changed, 923 insertions(+), 119 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -43,3 +43,4 @@ po/configure.acT po/Makevars.template po/POTFILES po/configargs.stamp +**~ diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -74,6 +74,57 @@ #define MICROHTTPD2_H +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/* While we generally would like users to use a configure-driven + build process which detects which headers are present and + hence works on any platform, we use "standard" includes here + to build out-of-the-box for beginning users on common systems. + + If generic headers don't work on your platform, include headers + which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', + 'uint16_t', 'uint32_t', 'uint64_t', 'off_t', 'struct sockaddr', + 'socklen_t', 'fd_set' and "#define MHD_PLATFORM_H" before + including "microhttpd.h". Then the following "standard" + includes won't be used (which might be a good idea, especially + on platforms where they do not exist). + */ +#ifndef MHD_PLATFORM_H +#include <stdarg.h> +#include <stdint.h> +#include <sys/types.h> +#if defined(_WIN32) && !defined(__CYGWIN__) +#include <ws2tcpip.h> +#if defined(_MSC_FULL_VER) && !defined (_SSIZE_T_DEFINED) +#define _SSIZE_T_DEFINED +typedef intptr_t ssize_t; +#endif /* !_SSIZE_T_DEFINED */ +#else +#include <unistd.h> +#include <sys/time.h> +#include <sys/socket.h> +#endif +#endif + +#if defined(__CYGWIN__) && !defined(_SYS_TYPES_FD_SET) +/* Do not define __USE_W32_SOCKETS under Cygwin! */ +#error Cygwin with winsock fd_set is not supported +#endif + +/** + * Current version of the library. + * 0x01093001 = 1.9.30-1. + */ +#define MHD_VERSION 0x01000000 + + + /** * Representation of 'bool' in the public API as stdbool.h may not * always be available. @@ -96,6 +147,144 @@ enum MHD_Bool /** + * Constant used to indicate unknown size (use when + * creating a response). + */ +#ifdef UINT64_MAX +#define MHD_SIZE_UNKNOWN UINT64_MAX +#else +#define MHD_SIZE_UNKNOWN ((uint64_t) -1LL) +#endif + +#ifdef SIZE_MAX +#define MHD_CONTENT_READER_END_OF_STREAM SIZE_MAX +#define MHD_CONTENT_READER_END_WITH_ERROR (SIZE_MAX - 1) +#else +#define MHD_CONTENT_READER_END_OF_STREAM ((size_t) -1LL) +#define MHD_CONTENT_READER_END_WITH_ERROR (((size_t) -1LL) - 1) +#endif + +#ifndef _MHD_EXTERN +#if defined(_WIN32) && defined(MHD_W32LIB) +#define _MHD_EXTERN extern +#elif defined (_WIN32) && defined(MHD_W32DLL) +/* Define MHD_W32DLL when using MHD as W32 .DLL to speed up linker a little */ +#define _MHD_EXTERN __declspec(dllimport) +#else +#define _MHD_EXTERN extern +#endif +#endif + +#ifndef MHD_SOCKET_DEFINED +/** + * MHD_socket is type for socket FDs + */ +#if !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) +#define MHD_POSIX_SOCKETS 1 +typedef int MHD_socket; +#define MHD_INVALID_SOCKET (-1) +#else /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ +#define MHD_WINSOCK_SOCKETS 1 +#include <winsock2.h> +typedef SOCKET MHD_socket; +#define MHD_INVALID_SOCKET (INVALID_SOCKET) +#endif /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ +#define MHD_SOCKET_DEFINED 1 +#endif /* MHD_SOCKET_DEFINED */ + +/** + * Define MHD_NO_DEPRECATION before including "microhttpd.h" to disable deprecation messages + */ +#ifdef MHD_NO_DEPRECATION +#define _MHD_DEPR_MACRO(msg) +#define _MHD_NO_DEPR_IN_MACRO 1 +#define _MHD_DEPR_IN_MACRO(msg) +#define _MHD_NO_DEPR_FUNC 1 +#define _MHD_DEPR_FUNC(msg) +#endif /* MHD_NO_DEPRECATION */ + +#ifndef _MHD_DEPR_MACRO +#if defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1500 +/* VS 2008 or later */ +/* Stringify macros */ +#define _MHD_INSTRMACRO(a) #a +#define _MHD_STRMACRO(a) _MHD_INSTRMACRO(a) +/* deprecation message */ +#define _MHD_DEPR_MACRO(msg) __pragma(message(__FILE__ "(" _MHD_STRMACRO(__LINE__)"): warning: " msg)) +#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg) +#elif defined(__clang__) || defined (__GNUC_PATCHLEVEL__) +/* clang or GCC since 3.0 */ +#define _MHD_GCC_PRAG(x) _Pragma (#x) +#if (defined(__clang__) && (__clang_major__+0 >= 5 || \ + (!defined(__apple_build_version__) && (__clang_major__+0 > 3 || (__clang_major__+0 == 3 && __clang_minor__ >= 3))))) || \ + __GNUC__+0 > 4 || (__GNUC__+0 == 4 && __GNUC_MINOR__+0 >= 8) +/* clang >= 3.3 (or XCode's clang >= 5.0) or + GCC >= 4.8 */ +#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG(GCC warning msg) +#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg) +#else /* older clang or GCC */ +/* clang < 3.3, XCode's clang < 5.0, 3.0 <= GCC < 4.8 */ +#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG(message msg) +#if (defined(__clang__) && (__clang_major__+0 > 2 || (__clang_major__+0 == 2 && __clang_minor__ >= 9))) /* FIXME: clang >= 2.9, earlier versions not tested */ +/* clang handles inline pragmas better than GCC */ +#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg) +#endif /* clang >= 2.9 */ +#endif /* older clang or GCC */ +/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ +#endif /* clang || GCC >= 3.0 */ +#endif /* !_MHD_DEPR_MACRO */ + +#ifndef _MHD_DEPR_MACRO +#define _MHD_DEPR_MACRO(msg) +#endif /* !_MHD_DEPR_MACRO */ + +#ifndef _MHD_DEPR_IN_MACRO +#define _MHD_NO_DEPR_IN_MACRO 1 +#define _MHD_DEPR_IN_MACRO(msg) +#endif /* !_MHD_DEPR_IN_MACRO */ + +#ifndef _MHD_DEPR_FUNC +#if defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1400 +/* VS 2005 or later */ +#define _MHD_DEPR_FUNC(msg) __declspec(deprecated(msg)) +#elif defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1310 +/* VS .NET 2003 deprecation do not support custom messages */ +#define _MHD_DEPR_FUNC(msg) __declspec(deprecated) +#elif (__GNUC__+0 >= 5) || (defined (__clang__) && \ + (__clang_major__+0 > 2 || (__clang_major__+0 == 2 && __clang_minor__ >= 9))) /* FIXME: earlier versions not tested */ +/* GCC >= 5.0 or clang >= 2.9 */ +#define _MHD_DEPR_FUNC(msg) __attribute__((deprecated(msg))) +#elif defined (__clang__) || __GNUC__+0 > 3 || (__GNUC__+0 == 3 && __GNUC_MINOR__+0 >= 1) +/* 3.1 <= GCC < 5.0 or clang < 2.9 */ +/* old GCC-style deprecation do not support custom messages */ +#define _MHD_DEPR_FUNC(msg) __attribute__((__deprecated__)) +/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ +#endif /* clang < 2.9 || GCC >= 3.1 */ +#endif /* !_MHD_DEPR_FUNC */ + +#ifndef _MHD_DEPR_FUNC +#define _MHD_NO_DEPR_FUNC 1 +#define _MHD_DEPR_FUNC(msg) +#endif /* !_MHD_DEPR_FUNC */ + +/** + * Not all architectures and `printf()`'s support the `long long` type. + * This gives the ability to replace `long long` with just a `long`, + * standard `int` or a `short`. + */ +#ifndef MHD_UNSIGNED_LONG_LONG +#define MHD_UNSIGNED_LONG_LONG unsigned long long +#endif +/** + * Format string for printing a variable of type #MHD_LONG_LONG. + * You should only redefine this if you also define #MHD_LONG_LONG. + */ +#ifndef MHD_UNSIGNED_LONG_LONG_PRINTF +#define MHD_UNSIGNED_LONG_LONG_PRINTF "%llu" +#endif + + +/** * @brief Handle for a connection / HTTP request. * * With HTTP/1.1, multiple requests can be run over the same @@ -112,6 +301,14 @@ struct MHD_Request; /** + * A connection corresponds to the network/stream abstraction. + * A single network (i.e. TCP) stream may be used for multiple + * requests, which in HTTP/1.1 must be processed sequentially. + */ +struct MHD_Connection; + + +/** * Return values for reporting errors, also used * for logging. * @@ -164,7 +361,7 @@ enum MHD_StatusCode * The application requested a TLS cipher suite which is not * supported by the selected backend. */ - MHD_SC_TLS_CIPHERS_INVALID = 50002 + MHD_SC_TLS_CIPHERS_INVALID = 50002, /** * The application attempted to setup TLS paramters before @@ -301,6 +498,19 @@ enum MHD_StatusCode MHD_SC_THREAD_POOL_CREATE_MUTEX_FAILURE = 50027, /** + * There was an attempt to upgrade a connection on + * a daemon where upgrades are disallowed. + */ + MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED = 50028, + + /** + * Queueing a response failed because the respective + * daemon is already too deep inside of the shutdown + * activity and the reponse cannot be sent any longer. + */ + MHD_SC_DAEMON_ALREADY_SHUTDOWN = 50029, + + /** * We failed to initialize the main thread for listening. */ MHD_SC_THREAD_MAIN_LAUNCH_FAILURE = 50030, @@ -1069,8 +1279,9 @@ MHD_daemon_gnutls_credentials (struct MHD_Daemon *daemon, * * @param daemon daemon to configure callback for * @param cb must be of type `gnutls_certificate_retrieve_function2 *`. + * @return #MHD_SC_OK on success */ -_MHD_EXTERN void +_MHD_EXTERN enum MHD_StatusCode MHD_daemon_gnutls_key_and_cert_from_callback (struct MHD_Daemon *daemon, void *cb); @@ -1174,9 +1385,9 @@ MHD_daemon_accept_policy (struct MHD_Daemon *daemon, * @return value to set for the "request_context" of @a request */ typedef void * -(MHD_EarlyUriLogCallback)(void *cls, - const char *uri, - struct MHD_Request *request); +(*MHD_EarlyUriLogCallback)(void *cls, + const char *uri, + struct MHD_Request *request); /** @@ -1195,6 +1406,29 @@ MHD_daemon_set_early_uri_logger (struct MHD_Daemon *daemon, /** + * The `enum MHD_ConnectionNotificationCode` specifies types + * of connection notifications. + * @ingroup request + */ +enum MHD_ConnectionNotificationCode +{ + + /** + * A new connection has been started. + * @ingroup request + */ + MHD_CONNECTION_NOTIFY_STARTED = 0, + + /** + * A connection is closed. + * @ingroup request + */ + MHD_CONNECTION_NOTIFY_CLOSED = 1 + +}; + + +/** * Signature of the callback used by MHD to notify the * application about started/stopped connections * @@ -1214,9 +1448,9 @@ MHD_daemon_set_early_uri_logger (struct MHD_Daemon *daemon, * @ingroup request */ typedef void -(*MHD_ConnectionCompletedCallback) (void *cls, - struct MHD_Connection *connection, - enum MHD_ConnectionNotificationCode toe); +(*MHD_NotifyConnectionCallback) (void *cls, + struct MHD_Connection *connection, + enum MHD_ConnectionNotificationCode toe); /** @@ -1310,9 +1544,9 @@ MHD_daemon_connection_default_timeout (struct MHD_Daemon *daemon, * @return number of characters in @a s (excluding 0-terminator) */ typedef size_t -MHD_UnescapeCallback (void *cls, - struct MHD_Request *req, - char *s); +(*MHD_UnescapeCallback) (void *cls, + struct MHD_Request *req, + char *s); /** @@ -1377,6 +1611,69 @@ MHD_connection_set_timeout (struct MHD_Connection *connection, /* **************** Request handling functions ***************** */ + +/** + * The `enum MHD_ValueKind` specifies the source of + * the key-value pairs in the HTTP protocol. + */ +enum MHD_ValueKind +{ + + /** + * HTTP header (request/response). + */ + MHD_HEADER_KIND = 1, + + /** + * Cookies. Note that the original HTTP header containing + * the cookie(s) will still be available and intact. + */ + MHD_COOKIE_KIND = 2, + + /** + * POST data. This is available only if a content encoding + * supported by MHD is used (currently only URL encoding), + * and only if the posted content fits within the available + * memory pool. Note that in that case, the upload data + * given to the #MHD_AccessHandlerCallback will be + * empty (since it has already been processed). + */ + MHD_POSTDATA_KIND = 4, + + /** + * GET (URI) arguments. + */ + MHD_GET_ARGUMENT_KIND = 8, + + /** + * HTTP footer (only for HTTP 1.1 chunked encodings). + */ + MHD_FOOTER_KIND = 16 +}; + + + +/** + * Iterator over key-value pairs. This iterator can be used to + * iterate over all of the cookies, headers, or POST-data fields of a + * request, and also to iterate over the headers that have been added + * to a response. + * + * @param cls closure + * @param kind kind of the header we are looking at + * @param key key for the value, can be an empty string + * @param value corresponding value, can be NULL + * @return #MHD_YES to continue iterating, + * #MHD_NO to abort the iteration + * @ingroup request + */ +typedef int +(*MHD_KeyValueIterator) (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *value); + + /** * Get all of the headers from the request. * @@ -1596,6 +1893,14 @@ MHD_request_resume (struct MHD_Request *request); /** + * Data transmitted in response to an HTTP request. + * Usually the final action taken in response to + * receiving a request. + */ +struct MHD_Response; + + +/** * Converts a @a response to an action. If @a consume * is set, the reference to the @a response is consumed * by the conversion. If @a consume is #MHD_NO, then @@ -1614,7 +1919,7 @@ MHD_request_resume (struct MHD_Request *request); */ _MHD_EXTERN struct MHD_Action * MHD_action_from_response (struct MHD_Response *response, - enum MHD_bool destroy_after_use); + enum MHD_Bool destroy_after_use); /** @@ -1628,9 +1933,67 @@ _MHD_EXTERN void MHD_response_option_v10_only (struct MHD_Response *response); +/** + * The `enum MHD_RequestTerminationCode` specifies reasons + * why a request has been terminated (or completed). + * @ingroup request + */ +enum MHD_RequestTerminationCode +{ + + /** + * We finished sending the response. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_COMPLETED_OK = 0, + + /** + * Error handling the connection (resources + * exhausted, other side closed connection, + * application error accepting request, etc.) + * @ingroup request + */ + MHD_REQUEST_TERMINATED_WITH_ERROR = 1, + + /** + * No activity on the connection for the number + * of seconds specified using + * #MHD_OPTION_CONNECTION_TIMEOUT. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2, + + /** + * We had to close the session since MHD was being + * shut down. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3, + + /** + * We tried to read additional data, but the other side closed the + * connection. This error is similar to + * #MHD_REQUEST_TERMINATED_WITH_ERROR, but specific to the case where + * the connection died because the other side did not send expected + * data. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_READ_ERROR = 4, + + /** + * The client terminated the connection by closing the socket + * for writing (TCP half-closed); MHD aborted sending the + * response according to RFC 2616, section 8.1.4. + * @ingroup request + */ + MHD_REQUEST_TERMINATED_CLIENT_ABORT = 5 + +}; + + /** - * Signature of the callback used by MHD to notify the - * application about completed requests. + * Signature of the callback used by MHD to notify the application + * about completed requests. * * @param cls client-defined closure * @param toe reason for request termination @@ -1660,6 +2023,69 @@ MHD_response_option_termination_callback (struct MHD_Response *response, /** + * Callback used by libmicrohttpd in order to obtain content. The + * callback is to copy at most @a max bytes of content into @a buf. The + * total number of bytes that has been placed into @a buf should be + * returned. + * + * Note that returning zero will cause libmicrohttpd to try again. + * Thus, returning zero should only be used in conjunction + * with MHD_suspend_connection() to avoid busy waiting. + * + * @param cls extra argument to the callback + * @param pos position in the datastream to access; + * note that if a `struct MHD_Response` object is re-used, + * it is possible for the same content reader to + * be queried multiple times for the same data; + * however, if a `struct MHD_Response` is not re-used, + * libmicrohttpd guarantees that "pos" will be + * the sum of all non-negative return values + * obtained from the content reader so far. + * @param buf where to copy the data + * @param max maximum number of bytes to copy to @a buf (size of @a buf) + * @return number of bytes written to @a buf; + * 0 is legal unless we are running in internal select mode (since + * this would cause busy-waiting); 0 in external select mode + * will cause this function to be called again once the external + * select calls MHD again; + * #MHD_CONTENT_READER_END_OF_STREAM (-1) for the regular + * end of transmission (with chunked encoding, MHD will then + * terminate the chunk and send any HTTP footers that might be + * present; without chunked encoding and given an unknown + * response size, MHD will simply close the connection; note + * that while returning #MHD_CONTENT_READER_END_OF_STREAM is not technically + * legal if a response size was specified, MHD accepts this + * and treats it just as #MHD_CONTENT_READER_END_WITH_ERROR; + * #MHD_CONTENT_READER_END_WITH_ERROR (-2) to indicate a server + * error generating the response; this will cause MHD to simply + * close the connection immediately. If a response size was + * given or if chunked encoding is in use, this will indicate + * an error to the client. Note, however, that if the client + * does not know a response size and chunked encoding is not in + * use, then clients will not be able to tell the difference between + * #MHD_CONTENT_READER_END_WITH_ERROR and #MHD_CONTENT_READER_END_OF_STREAM. + * This is not a limitation of MHD but rather of the HTTP protocol. + */ +typedef ssize_t +(*MHD_ContentReaderCallback) (void *cls, + uint64_t pos, + char *buf, + size_t max); + + +/** + * This method is called by libmicrohttpd if we are done with a + * content reader. It should be used to free resources associated + * with the content reader. + * + * @param cls closure + * @ingroup response + */ +typedef void +(*MHD_ContentReaderFreeCallback) (void *cls); + + +/** * Create a response action. The response object can be extended with * header information and then be used any number of times. * @@ -2505,4 +2931,219 @@ MHD_daemon_get_information_sz (struct MHD_Daemon *daemon, MHD_daemon_get_information_sz((daemon), (info_type), (return_value), sizeof(union MHD_DaemonInformation)); +/** + * Callback for serious error condition. The default action is to print + * an error message and `abort()`. + * + * @param cls user specified value + * @param file where the error occured + * @param line where the error occured + * @param reason error detail, may be NULL + * @ingroup logging + */ +typedef void +(*MHD_PanicCallback) (void *cls, + const char *file, + unsigned int line, + const char *reason); + + +/** + * Sets the global error handler to a different implementation. @a cb + * will only be called in the case of typically fatal, serious + * internal consistency issues. These issues should only arise in the + * case of serious memory corruption or similar problems with the + * architecture. While @a cb is allowed to return and MHD will then + * try to continue, this is never safe. + * + * The default implementation that is used if no panic function is set + * simply prints an error message and calls `abort()`. Alternative + * implementations might call `exit()` or other similar functions. + * + * @param cb new error handler + * @param cls passed to @a cb + * @ingroup logging + */ +_MHD_EXTERN void +MHD_set_panic_func (MHD_PanicCallback cb, + void *cls); + + + +/** + * Types of information about MHD features, + * used by #MHD_is_feature_supported(). + */ +enum MHD_Feature +{ + /** + * Get whether messages are supported. If supported then in debug + * mode messages can be printed to stderr or to external logger. + */ + MHD_FEATURE_MESSAGES = 1, + + /** + * Get whether HTTPS is supported. If supported then flag + * #MHD_USE_TLS and options #MHD_OPTION_HTTPS_MEM_KEY, + * #MHD_OPTION_HTTPS_MEM_CERT, #MHD_OPTION_HTTPS_MEM_TRUST, + * #MHD_OPTION_HTTPS_MEM_DHPARAMS, #MHD_OPTION_HTTPS_CRED_TYPE, + * #MHD_OPTION_HTTPS_PRIORITIES can be used. + */ + MHD_FEATURE_TLS = 2, + + /** + * Get whether option #MHD_OPTION_HTTPS_CERT_CALLBACK is + * supported. + */ + MHD_FEATURE_HTTPS_CERT_CALLBACK = 3, + + /** + * Get whether IPv6 is supported. If supported then flag + * #MHD_USE_IPv6 can be used. + */ + MHD_FEATURE_IPv6 = 4, + + /** + * Get whether IPv6 without IPv4 is supported. If not supported + * then IPv4 is always enabled in IPv6 sockets and + * flag #MHD_USE_DUAL_STACK if always used when #MHD_USE_IPv6 is + * specified. + */ + MHD_FEATURE_IPv6_ONLY = 5, + + /** + * Get whether `poll()` is supported. If supported then flag + * #MHD_USE_POLL can be used. + */ + MHD_FEATURE_POLL = 6, + + /** + * Get whether `epoll()` is supported. If supported then Flags + * #MHD_USE_EPOLL and + * #MHD_USE_EPOLL_INTERNAL_THREAD can be used. + */ + MHD_FEATURE_EPOLL = 7, + + /** + * Get whether shutdown on listen socket to signal other + * threads is supported. If not supported flag + * #MHD_USE_ITC is automatically forced. + */ + MHD_FEATURE_SHUTDOWN_LISTEN_SOCKET = 8, + + /** + * Get whether socketpair is used internally instead of pipe to + * signal other threads. + */ + MHD_FEATURE_SOCKETPAIR = 9, + + /** + * Get whether TCP Fast Open is supported. If supported then + * flag #MHD_USE_TCP_FASTOPEN and option + * #MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE can be used. + */ + MHD_FEATURE_TCP_FASTOPEN = 10, + + /** + * Get whether HTTP Basic authorization is supported. If supported + * then functions #MHD_basic_auth_get_username_password and + * #MHD_queue_basic_auth_fail_response can be used. + */ + MHD_FEATURE_BASIC_AUTH = 11, + + /** + * Get whether HTTP Digest authorization is supported. If + * supported then options #MHD_OPTION_DIGEST_AUTH_RANDOM, + * #MHD_OPTION_NONCE_NC_SIZE and + * #MHD_digest_auth_check() can be used. + */ + MHD_FEATURE_DIGEST_AUTH = 12, + + /** + * Get whether postprocessor is supported. If supported then + * functions #MHD_create_post_processor(), #MHD_post_process() and + * #MHD_destroy_post_processor() can + * be used. + */ + MHD_FEATURE_POSTPROCESSOR = 13, + + /** + * Get whether password encrypted private key for HTTPS daemon is + * supported. If supported then option + * ::MHD_OPTION_HTTPS_KEY_PASSWORD can be used. + */ + MHD_FEATURE_HTTPS_KEY_PASSWORD = 14, + + /** + * Get whether reading files beyond 2 GiB boundary is supported. + * If supported then #MHD_create_response_from_fd(), + * #MHD_create_response_from_fd64 #MHD_create_response_from_fd_at_offset() + * and #MHD_create_response_from_fd_at_offset64() can be used with sizes and + * offsets larger than 2 GiB. If not supported value of size+offset is + * limited to 2 GiB. + */ + MHD_FEATURE_LARGE_FILE = 15, + + /** + * Get whether MHD set names on generated threads. + */ + MHD_FEATURE_THREAD_NAMES = 16, + + /** + * Get whether HTTP "Upgrade" is supported. + * If supported then #MHD_ALLOW_UPGRADE, #MHD_upgrade_action() and + * #MHD_create_response_for_upgrade() can be used. + */ + MHD_FEATURE_UPGRADE = 17, + + /** + * Get whether it's safe to use same FD for multiple calls of + * #MHD_create_response_from_fd() and whether it's safe to use single + * response generated by #MHD_create_response_from_fd() with multiple + * connections at same time. + * If #MHD_is_feature_supported() return #MHD_NO for this feature then + * usage of responses with same file FD in multiple parallel threads may + * results in incorrect data sent to remote client. + * It's always safe to use same file FD in multiple responses if MHD + * is run in any single thread mode. + */ + MHD_FEATURE_RESPONSES_SHARED_FD = 18, + + /** + * Get whether MHD support automatic detection of bind port number. + * @sa #MHD_DAEMON_INFO_BIND_PORT + */ + MHD_FEATURE_AUTODETECT_BIND_PORT = 19, + + /** + * Get whether MHD support SIGPIPE suppression. + * If SIGPIPE suppression is not supported, application must handle + * SIGPIPE signal by itself. + */ + MHD_FEATURE_AUTOSUPPRESS_SIGPIPE = 20, + + /** + * Get whether MHD use system's sendfile() function to send + * file-FD based responses over non-TLS connections. + * @note Since v0.9.56 + */ + MHD_FEATURE_SENDFILE = 21 +}; + + +/** + * Get information about supported MHD features. + * Indicate that MHD was compiled with or without support for + * particular feature. Some features require additional support + * by kernel. Kernel support is not checked by this function. + * + * @param feature type of requested information + * @return #MHD_YES if feature is supported by MHD, #MHD_NO if + * feature is not supported or feature is unknown. + * @ingroup specialized + */ +_MHD_EXTERN enum MHD_Bool +MHD_is_feature_supported (enum MHD_Feature feature); + + #endif diff --git a/src/include/microhttpd_tls.h b/src/include/microhttpd_tls.h @@ -87,7 +87,7 @@ struct MHD_TLS_Plugin * @return NULL on errors (in particular, invalid cipher suite) */ typedef struct MHD_TLS_Plugin * -MHD_TLS_PluginInit (const char *ciphers); +(*MHD_TLS_PluginInit) (const char *ciphers); /** diff --git a/src/lib/action_continue.c b/src/lib/action_continue.c @@ -31,13 +31,15 @@ * * @param cls NULL * @param request the request to apply the action to + * @return #MHD_SC_OK on success */ -static void +static enum MHD_StatusCode cont_action (void *cls, struct MHD_Request *request) { /* not sure yet, but this function body may just legitimately stay empty... */ + return MHD_SC_OK; } @@ -49,7 +51,7 @@ cont_action (void *cls, struct MHD_Action * MHD_action_continue (void) { - static MHD_Action acont = { + static struct MHD_Action acont = { .action = &cont_action, .action_cls = NULL }; diff --git a/src/lib/action_from_response.c b/src/lib/action_from_response.c @@ -31,27 +31,30 @@ * * @param cls the `struct MHD_Response` * @param request the request we are processing + * @return #MHD_SC_OK on success */ -static void +static enum MHD_StatusCode response_action (void *cls, struct MHD_Request *request) { struct MHD_Response *response = cls; - struct MHD_Daemon *daemon = response->daemon; + struct MHD_Daemon *daemon = request->daemon; + /* If daemon was shut down in parallel, + * response will be aborted now or on later stage. */ if (daemon->shutdown) - return MHD_YES; /* If daemon was shut down in parallel, - * response will be aborted now or on later stage. */ + return MHD_SC_DAEMON_ALREADY_SHUTDOWN; #ifdef UPGRADE_SUPPORT if ( (NULL != response->upgrade_handler) && - (0 == (daemon->options & MHD_ALLOW_UPGRADE)) ) + daemon->disallow_upgrade ) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, + MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED, _("Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n")); #endif - return MHD_NO; + return MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED; } #endif /* UPGRADE_SUPPORT */ request->response = response; @@ -66,9 +69,7 @@ response_action (void *cls, request->resp_sender = MHD_resp_sender_sendfile; #endif /* _MHD_HAVE_SENDFILE */ - if ( ( (NULL != request->method) && - (MHD_str_equal_caseless_ (request->method, - MHD_HTTP_METHOD_HEAD)) ) || + if ( (MHD_METHOD_HEAD == request->method) || (MHD_HTTP_OK > response->status_code) || (MHD_HTTP_NO_CONTENT == response->status_code) || (MHD_HTTP_NOT_MODIFIED == response->status_code) ) @@ -79,19 +80,17 @@ response_action (void *cls, request->response_write_position = response->total_size; } if ( (MHD_REQUEST_HEADERS_PROCESSED == request->state) && - (NULL != connection->method) && - ( (MHD_str_equal_caseless_ (request->method, - MHD_HTTP_METHOD_POST)) || - (MHD_str_equal_caseless_ (request->method, - MHD_HTTP_METHOD_PUT))) ) + (MHD_METHOD_POST == request->method) || + (MHD_METHOD_PUT == request->method) ) { /* response was queued "early", refuse to read body / footers or further requests! */ - connection->read_closed = true; - request->state = MHD_CONNECTION_FOOTERS_RECEIVED; + request->connection->read_closed = true; + request->state = MHD_REQUEST_FOOTERS_RECEIVED; } if (! request->in_idle) - (void) MHD_connection_handle_idle (connection); + (void) MHD_connection_handle_idle (request->connection); + return MHD_SC_OK; } @@ -114,7 +113,7 @@ response_action (void *cls, */ _MHD_EXTERN struct MHD_Action * MHD_action_from_response (struct MHD_Response *response, - enum MHD_bool destroy_after_use) + enum MHD_Bool destroy_after_use) { response->action.action = &response_action; response->action.action_cls = response; diff --git a/src/lib/action_process_upload.c b/src/lib/action_process_upload.c @@ -51,8 +51,9 @@ struct UploadAction * function we are to call for upload data * @param request the request for which we are to process * upload data + * @return #MHD_SC_OK on success */ -static void +static enum MHD_StatusCode upload_action (void *cls, struct MHD_Request *request) { @@ -60,6 +61,7 @@ upload_action (void *cls, (void) ua; // FIXME: implement! + return -1; } @@ -79,11 +81,11 @@ MHD_action_process_upload (MHD_UploadCallback uc, if (NULL == (ua = malloc (sizeof (struct UploadAction)))) return NULL; - ua->action = &upload_action; - ua->action_cls = ua; + ua->action.action = &upload_action; + ua->action.action_cls = ua; ua->uc = uc; ua->uc_cls = uc_cls; - return ua; + return &ua->action; } diff --git a/src/lib/action_suspend.c b/src/lib/action_suspend.c @@ -31,11 +31,13 @@ * * @param cls NULL * @param request the request to apply the action to + * @return #MHD_SC_OK on success */ -static void +static enum MHD_StatusCode suspend_action (void *cls, struct MHD_Request *request) { + struct MHD_Connection *connection = request->connection; struct MHD_Daemon *daemon = connection->daemon; MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); @@ -44,7 +46,7 @@ suspend_action (void *cls, /* suspending again while we didn't even complete resuming yet */ connection->resuming = false; MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); - return; + return MHD_SC_OK; } if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) { @@ -88,6 +90,7 @@ suspend_action (void *cls, } #endif MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); + return MHD_SC_OK; } diff --git a/src/lib/connection_options.c b/src/lib/connection_options.c @@ -46,6 +46,7 @@ MHD_connection_set_timeout (struct MHD_Connection *connection, connection->connection_timeout = (time_t) timeout_s; return; } + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); if (! connection->suspended) { diff --git a/src/lib/daemon_options.c b/src/lib/daemon_options.c @@ -23,6 +23,7 @@ * @author Christian Grothoff */ #include "internal.h" +#include <dlfcn.h> /** @@ -150,7 +151,7 @@ MHD_daemon_tcp_fastopen (struct MHD_Daemon *daemon, unsigned int queue_length) { daemon->fast_open_method = fom; - daemon->fast_open_queue_length = queue_length; + daemon->fo_queue_length = queue_length; switch (fom) { case MHD_FOM_DISABLE: @@ -204,7 +205,6 @@ 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); @@ -338,37 +338,37 @@ MHD_daemon_set_tls_backend (struct MHD_Daemon *daemon, const char *ciphers) { #ifndef HTTPS_SUPPORT - return MHD_TLS_DISABLED; + return MHD_SC_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); + 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? */ + return MHD_SC_TLS_BACKEND_UNSUPPORTED; /* string too long? */ if (NULL == (daemon->tls_backend_lib = dlopen (filename, RTLD_NOW | RTLD_LOCAL))) - return MHD_BACKEND_UNSUPPORTED; /* plugin not found */ + return MHD_SC_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 */ + return MHD_SC_BACKEND_UNSUPPORTED; /* possibly wrong version installed */ } - if (NULL == (daemon->tls_backend = init (ciphers))) + if (NULL == (daemon->tls_api = init (ciphers))) { dlclose (daemon->tls_backend_lib); daemon->tls_backend_lib = NULL; - return MHD_CIPHERS_INVALID; /* possibly wrong version installed */ + return MHD_SC_CIPHERS_INVALID; /* possibly wrong version installed */ } return MHD_SC_OK; #endif @@ -396,8 +396,8 @@ MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon, { struct MHD_TLS_Plugin *plugin; - if (NULL == (plugin = daemon->tls_backend)) - return MHD_TLS_BACKEND_UNINITIALIZED; + if (NULL == (plugin = daemon->tls_api)) + return MHD_SC_TLS_BACKEND_UNINITIALIZED; return plugin->init_kcp (plugin->cls, mem_key, mem_cert, @@ -420,8 +420,8 @@ MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon, { struct MHD_TLS_Plugin *plugin; - if (NULL == (plugin = daemon->tls_backend)) - return MHD_TLS_BACKEND_UNINITIALIZED; + if (NULL == (plugin = daemon->tls_api)) + return MHD_SC_TLS_BACKEND_UNINITIALIZED; return plugin->init_dhparams (plugin->cls, dh); } @@ -442,8 +442,8 @@ MHD_daemon_tls_mem_trust (struct MHD_Daemon *daemon, { struct MHD_TLS_Plugin *plugin; - if (NULL == (plugin = daemon->tls_backend)) - return MHD_TLS_BACKEND_UNINITIALIZED; + if (NULL == (plugin = daemon->tls_api)) + return MHD_SC_TLS_BACKEND_UNINITIALIZED; return plugin->init_mem_trust (plugin->cls, mem_trust); } @@ -462,9 +462,9 @@ MHD_daemon_gnutls_credentials (struct MHD_Daemon *daemon, { struct MHD_TLS_Plugin *plugin; - if (NULL == (plugin = daemon->tls_backend)) - return MHD_TLS_BACKEND_UNINITIALIZED; - return MHD_TLS_BACKEND_OPERATION_UNSUPPORTED; + if (NULL == (plugin = daemon->tls_api)) + return MHD_SC_TLS_BACKEND_UNINITIALIZED; + return MHD_SC_TLS_BACKEND_OPERATION_UNSUPPORTED; } @@ -483,16 +483,17 @@ MHD_daemon_gnutls_credentials (struct MHD_Daemon *daemon, * * @param daemon daemon to configure callback for * @param cb must be of type `gnutls_certificate_retrieve_function2 *`. + * @return #MHD_SC_OK on success */ -void +enum MHD_StatusCode 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; + if (NULL == (plugin = daemon->tls_api)) + return MHD_SC_TLS_BACKEND_UNINITIALIZED; + return MHD_SC_TLS_BACKEND_OPERATION_UNSUPPORTED; } @@ -544,8 +545,8 @@ 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; + daemon->early_uri_logger = cb; + daemon->early_uri_logger_cls = cb_cls; } @@ -710,7 +711,7 @@ MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, MHD_DLOG (daemon, _("Specified value for NC_SIZE too large\n")); #endif - return MHD_DIGEST_AUTH_NC_LENGTH_TOO_BIG; + return MHD_SC_DIGEST_AUTH_NC_LENGTH_TOO_BIG; } if (0 < nc_length) { @@ -725,13 +726,13 @@ MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, _("Failed to allocate memory for nonce-nc map: %s\n"), MHD_strerror_ (errno)); #endif - return MHD_DIGEST_AUTH_NC_ALLOCATION_FAILURE; + return MHD_SC_DIGEST_AUTH_NC_ALLOCATION_FAILURE; } } daemon->digest_nc_length = nc_length; return MHD_SC_OK; #else - return MHD_DIGEST_AUTH_NOT_SUPPORTED_BY_BUILD; + return MHD_SC_DIGEST_AUTH_NOT_SUPPORTED_BY_BUILD; #endif } diff --git a/src/lib/daemon_start.c b/src/lib/daemon_start.c @@ -643,9 +643,9 @@ setup_thread_pool (struct MHD_Daemon *daemon) /* Coarse-grained count of connections per thread (note error * due to integer division). Also keep track of how many * connections are leftover after an equal split. */ - unsigned int conns_per_thread = daemon->connection_limit + unsigned int conns_per_thread = daemon->global_connection_limit / daemon->threading_model; - unsigned int leftover_conns = daemon->connection_limit + unsigned int leftover_conns = daemon->global_connection_limit % daemon->threading_model; unsigned int i; enum MHD_StatusCode sc; @@ -674,9 +674,9 @@ setup_thread_pool (struct MHD_Daemon *daemon) /* Divide available connections evenly amongst the threads. * Thread indexes in [0, leftover_conns) each get one of the * leftover connections. */ - d->connection_limit = conns_per_thread; + d->global_connection_limit = conns_per_thread; if (i < leftover_conns) - ++d->connection_limit; + ++d->global_connection_limit; if (! daemon->disable_itc) { diff --git a/src/lib/init.c b/src/lib/init.c @@ -97,6 +97,8 @@ volatile int global_init_count = 0; MHD_MUTEX_STATIC_DEFN_INIT_(global_init_mutex_); #endif /* MHD_MUTEX_STATIC_DEFN_INIT_ */ +#endif + /** * Check whether global initialisation was performed diff --git a/src/lib/internal.c b/src/lib/internal.c @@ -92,17 +92,20 @@ MHD_state_to_string (enum MHD_CONNECTION_STATE state) */ void MHD_DLOG (const struct MHD_Daemon *daemon, + enum MHD_StatusCode sc, const char *format, ...) { va_list va; - if (0 == (daemon->options & MHD_USE_ERROR_LOG)) + if (NULL == daemon->logger) return; - va_start (va, format); - daemon->custom_error_log (daemon->custom_error_log_cls, - format, - va); + va_start (va, + format); + daemon->logger (daemon->logger_cls, + sc, + format, + va); va_end (va); } #endif @@ -204,9 +207,9 @@ MHD_parse_arguments_ (struct MHD_Connection *connection, { /* last argument, without '=' */ MHD_unescape_plus (args); - daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - args); + daemon->unescape_cb (daemon->unescape_cb_cls, + connection, + args); if (MHD_YES != cb (connection, args, NULL, @@ -219,13 +222,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection, equals[0] = '\0'; equals++; MHD_unescape_plus (args); - daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - args); + daemon->unescape_cb (daemon->unescape_cb_cls, + connection, + args); MHD_unescape_plus (equals); - daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - equals); + daemon->unescape_cb (daemon->unescape_cb_cls, + connection, + equals); if (MHD_YES != cb (connection, args, equals, @@ -235,16 +238,16 @@ MHD_parse_arguments_ (struct MHD_Connection *connection, break; } /* amper is non-NULL here */ - amper[0] = '\0'; + amper[0] = '\0';d amper++; if ( (NULL == equals) || (equals >= amper) ) { /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */ MHD_unescape_plus (args); - daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - args); + daemon->unescape_cb (daemon->unescape_cb_cls, + connection, + args); if (MHD_YES != cb (connection, args, NULL, @@ -260,13 +263,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection, equals[0] = '\0'; equals++; MHD_unescape_plus (args); - daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - args); + daemon->unescape_cb (daemon->unescape_cb_cls, + connection, + args); MHD_unescape_plus (equals); - daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - equals); + daemon->unescape_cb (daemon->unescape_cb_cls, + connection, + equals); if (MHD_YES != cb (connection, args, equals, diff --git a/src/lib/internal.h b/src/lib/internal.h @@ -32,6 +32,8 @@ #include "microhttpd2.h" #include "microhttpd_tls.h" #include "mhd_assert.h" +#include "mhd_compat.h" +#include "memorypool.h" #ifdef HTTPS_SUPPORT #include <gnutls/gnutls.h> @@ -67,9 +69,23 @@ #include "mhd_threads.h" #include "mhd_locks.h" #include "mhd_sockets.h" +#include "mhd_str.h" #include "mhd_itc_types.h" +#ifdef HAVE_MESSAGES +/** + * fprintf()-like helper function for logging debug + * messages. + */ +void +MHD_DLOG (const struct MHD_Daemon *daemon, + enum MHD_StatusCode sc, + const char *format, + ...); +#endif + + /** * Close FD and abort execution if error is detected. * @param fd the FD to close @@ -345,13 +361,40 @@ struct MHD_HTTP_Header /** + * What is this request waiting for? + */ +enum MHD_RequestEventLoopInfo +{ + /** + * We are waiting to be able to read. + */ + MHD_EVENT_LOOP_INFO_READ = 0, + + /** + * We are waiting to be able to write. + */ + MHD_EVENT_LOOP_INFO_WRITE = 1, + + /** + * We are waiting for the application to provide data. + */ + MHD_EVENT_LOOP_INFO_BLOCK = 2, + + /** + * We are finished and are awaiting cleanup. + */ + MHD_EVENT_LOOP_INFO_CLEANUP = 3 +}; + + +/** * State kept for each HTTP request. */ struct MHD_Request { /** - * Reference to the MHD_Daemon struct. + * Reference to the `struct MHD_Daemon`. */ struct MHD_Daemon *daemon; @@ -361,6 +404,12 @@ struct MHD_Request struct MHD_Connection *connection; /** + * Response to return for this request, set once + * it is available. + */ + struct MHD_Response *response; + + /** * Linked list of parsed headers. */ struct MHD_HTTP_Header *headers_received; @@ -389,9 +438,10 @@ struct MHD_Request void *client_context; /** - * Request method. Should be GET/POST/etc. Allocated in pool. + * Request method as string. Should be GET/POST/etc. Allocated in + * pool. */ - char *method; + char *method_s; /** * Requested URL (everything after "GET" only). Allocated @@ -557,6 +607,11 @@ struct MHD_Request enum MHD_REQUEST_STATE state; /** + * HTTP method, as an enum. + */ + enum MHD_Method method; + + /** * What is this request waiting for? */ enum MHD_RequestEventLoopInfo event_loop_info; @@ -591,6 +646,54 @@ struct MHD_Request }; +#ifdef EPOLL_SUPPORT +/** + * State of the socket with respect to epoll (bitmask). + */ +enum MHD_EpollState +{ + + /** + * The socket is not involved with a defined state in epoll() right + * now. + */ + MHD_EPOLL_STATE_UNREADY = 0, + + /** + * epoll() told us that data was ready for reading, and we did + * not consume all of it yet. + */ + MHD_EPOLL_STATE_READ_READY = 1, + + /** + * epoll() told us that space was available for writing, and we did + * not consume all of it yet. + */ + MHD_EPOLL_STATE_WRITE_READY = 2, + + /** + * Is this connection currently in the 'eready' EDLL? + */ + MHD_EPOLL_STATE_IN_EREADY_EDLL = 4, + + /** + * Is this connection currently in the epoll() set? + */ + MHD_EPOLL_STATE_IN_EPOLL_SET = 8, + + /** + * Is this connection currently suspended? + */ + MHD_EPOLL_STATE_SUSPENDED = 16, + + /** + * Is this connection in some error state? + */ + MHD_EPOLL_STATE_ERROR = 128 +}; +#endif + + /** * State kept per HTTP connection. */ @@ -990,7 +1093,11 @@ struct MHD_Daemon */ bool allow_address_reuse; - + /** + * Are we shutting down? + */ + volatile bool shutdown; + }; @@ -1000,10 +1107,11 @@ struct MHD_Daemon * * @param cls action-specfic closure * @param request the request on which the action is to be performed + * @return #MHD_SC_OK on success, otherwise an error code */ -typedef void +typedef enum MHD_StatusCode (*ActionCallback) (void *cls, - const struct MHD_Request *request); + struct MHD_Request *request); /** @@ -1153,4 +1261,44 @@ struct MHD_Response +/** + * Callback invoked when iterating over @a key / @a value + * argument pairs during parsing. + * + * @param connection context of the iteration + * @param key 0-terminated key string, never NULL + * @param value 0-terminated value string, may be NULL + * @param kind origin of the key-value pair + * @return #MHD_YES on success (continue to iterate) + * #MHD_NO to signal failure (and abort iteration) + */ +typedef int +(*MHD_ArgumentIterator_)(struct MHD_Connection *connection, + const char *key, + const char *value, + enum MHD_ValueKind kind); + + +/** + * Parse and unescape the arguments given by the client + * as part of the HTTP request URI. + * + * @param kind header kind to pass to @a cb + * @param connection connection to add headers to + * @param[in,out] args argument URI string (after "?" in URI), + * clobbered in the process! + * @param cb function to call on each key-value pair found + * @param[out] num_headers set to the number of headers found + * @return #MHD_NO on failure (@a cb returned #MHD_NO), + * #MHD_YES for success (parsing succeeded, @a cb always + * returned #MHD_YES) + */ +int +MHD_parse_arguments_ (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + char *args, + MHD_ArgumentIterator_ cb, + unsigned int *num_headers); + + #endif diff --git a/src/lib/request.c b/src/lib/request.c @@ -24,6 +24,7 @@ * @author Christian Grothoff * @author Karlson2k (Evgeny Grin) */ +#include "internal.h" /** diff --git a/src/lib/response.c b/src/lib/response.c @@ -129,7 +129,7 @@ MHD_response_add_header (struct MHD_Response *response, return add_response_entry (response, MHD_HEADER_KIND, header, - content) ? MHD_TRUE : MHD_FALSE; + content) ? MHD_YES : MHD_NO; } @@ -151,7 +151,7 @@ MHD_response_add_trailer (struct MHD_Response *response, return add_response_entry (response, MHD_FOOTER_KIND, footer, - content) ? MHD_TRUE : MHD_FALSE; + content) ? MHD_YES : MHD_NO; } diff --git a/src/lib/response_from_buffer.c b/src/lib/response_from_buffer.c @@ -46,7 +46,7 @@ MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, struct MHD_Response *response; void *tmp; - mhd_assert ( (NULL != data) || + mhd_assert ( (NULL != buffer) || (0 == size) ); if (NULL == (response = MHD_calloc_ (1, @@ -68,19 +68,19 @@ MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, return NULL; } memcpy (tmp, - data, + buffer, size); - data = tmp; + buffer = tmp; } if (MHD_RESPMEM_PERSISTENT != mode) { response->crfc = &free; - response->crc_cls = data; + response->crc_cls = buffer; } response->status_code = sc; response->reference_count = 1; response->total_size = size; - response->data = data; + response->data = buffer; response->data_size = size; return response; } diff --git a/src/lib/response_from_fd.c b/src/lib/response_from_fd.c @@ -180,7 +180,8 @@ MHD_response_from_fd (enum MHD_HTTP_StatusCode sc, ((int64_t) (size + offset) < 0) ) return NULL; - response = MHD_response_from_callback (size, + response = MHD_response_from_callback (sc, + size, 4 * 1024, &file_reader, NULL, @@ -188,7 +189,6 @@ MHD_response_from_fd (enum MHD_HTTP_StatusCode sc, if (NULL == response) return NULL; response->fd = fd; - response->status_code = sc; response->fd_off = offset; response->crc_cls = response; return response; diff --git a/src/lib/version.c b/src/lib/version.c @@ -65,8 +65,8 @@ MHD_get_version (void) * feature is not supported or feature is unknown. * @ingroup specialized */ -_MHD_EXTERN int -MHD_is_feature_supported(enum MHD_FEATURE feature) +_MHD_EXTERN enum MHD_Bool +MHD_is_feature_supported(enum MHD_Feature feature) { switch(feature) { diff --git a/src/microhttpd/mhd_sockets.h b/src/microhttpd/mhd_sockets.h @@ -751,10 +751,10 @@ MHD_socket_noninheritable_ (MHD_socket sock); /** * Create a listen socket, with noninheritable flag if possible. * - * @param use_ipv6 if set to non-zero IPv6 is used + * @param pf protocol family to use * @return created socket or MHD_INVALID_SOCKET in case of errors */ MHD_socket -MHD_socket_create_listen_ (bool use_ipv6); +MHD_socket_create_listen_ (int pf); #endif /* ! MHD_SOCKETS_H */