/* 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 lib/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" #include "mhd_compat.h" #include "mhd_itc.h" #include "mhd_mono_clock.h" #include "memorypool.h" #ifdef HTTPS_SUPPORT #include #if GNUTLS_VERSION_MAJOR >= 3 #include #endif #endif /* HTTPS_SUPPORT */ #ifdef HAVE_STDBOOL_H #include #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_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 */ #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_ */ /** * Ability to use same connection for next request */ enum MHD_ConnKeepAlive { /** * Connection must be closed after sending response. */ MHD_CONN_MUST_CLOSE = -1, /** * KeelAlive state is not yet determined */ MHD_CONN_KEEPALIVE_UNKOWN = 0, /** * Connection can be used for serving next request */ MHD_CONN_USE_KEEPALIVE = 1 }; /** * Function to receive plaintext data. * * @param conn the connection struct * @param write_to where to write received data * @param max_bytes maximum number of bytes to receive * @return number of bytes written to @a write_to */ typedef ssize_t (*ReceiveCallback) (struct MHD_Connection *conn, void *write_to, size_t max_bytes); /** * Function to transmit plaintext data. * * @param conn the connection struct * @param read_from where to read data to transmit * @param max_bytes maximum number of bytes to transmit * @return number of bytes transmitted */ typedef ssize_t (*TransmitCallback) (struct MHD_Connection *conn, const void *read_from, size_t max_bytes); /** * States in a state machine for a request. * * The main transitions are any-state to #MHD_REQUEST_CLOSED, any * state to state+1, #MHD_REQUEST_FOOTERS_SENT to * #MHD_REQUEST_INIT. #MHD_REQUEST_CLOSED is the terminal state * and #MHD_REQUEST_INIT the initial state. * * Note that transitions for *reading* happen only after the input has * been processed; transitions for *writing* happen after the * respective data has been put into the write buffer (the write does * not have to be completed yet). A transition to * #MHD_REQUEST_CLOSED or #MHD_REQUEST_INIT requires the write * to be complete. */ enum MHD_REQUEST_STATE // FIXME: fix capitalization! { /** * Request just started (no headers received). * Waiting for the line with the request type, URL and version. */ MHD_REQUEST_INIT = 0, /** * 1: We got the URL (and request type and version). Wait for a header line. */ MHD_REQUEST_URL_RECEIVED = MHD_REQUEST_INIT + 1, /** * 2: We got part of a multi-line request header. Wait for the rest. */ MHD_REQUEST_HEADER_PART_RECEIVED = MHD_REQUEST_URL_RECEIVED + 1, /** * 3: We got the request headers. Process them. */ MHD_REQUEST_HEADERS_RECEIVED = MHD_REQUEST_HEADER_PART_RECEIVED + 1, /** * 4: We have processed the request headers. Send 100 continue. */ MHD_REQUEST_HEADERS_PROCESSED = MHD_REQUEST_HEADERS_RECEIVED + 1, /** * 5: We have processed the headers and need to send 100 CONTINUE. */ MHD_REQUEST_CONTINUE_SENDING = MHD_REQUEST_HEADERS_PROCESSED + 1, /** * 6: We have sent 100 CONTINUE (or do not need to). Read the message body. */ MHD_REQUEST_CONTINUE_SENT = MHD_REQUEST_CONTINUE_SENDING + 1, /** * 7: We got the request body. Wait for a line of the footer. */ MHD_REQUEST_BODY_RECEIVED = MHD_REQUEST_CONTINUE_SENT + 1, /** * 8: We got part of a line of the footer. Wait for the * rest. */ MHD_REQUEST_FOOTER_PART_RECEIVED = MHD_REQUEST_BODY_RECEIVED + 1, /** * 9: We received the entire footer. Wait for a response to be queued * and prepare the response headers. */ MHD_REQUEST_FOOTERS_RECEIVED = MHD_REQUEST_FOOTER_PART_RECEIVED + 1, /** * 10: We have prepared the response headers in the writ buffer. * Send the response headers. */ MHD_REQUEST_HEADERS_SENDING = MHD_REQUEST_FOOTERS_RECEIVED + 1, /** * 11: We have sent the response headers. Get ready to send the body. */ MHD_REQUEST_HEADERS_SENT = MHD_REQUEST_HEADERS_SENDING + 1, /** * 12: We are ready to send a part of a non-chunked body. Send it. */ MHD_REQUEST_NORMAL_BODY_READY = MHD_REQUEST_HEADERS_SENT + 1, /** * 13: We are waiting for the client to provide more * data of a non-chunked body. */ MHD_REQUEST_NORMAL_BODY_UNREADY = MHD_REQUEST_NORMAL_BODY_READY + 1, /** * 14: We are ready to send a chunk. */ MHD_REQUEST_CHUNKED_BODY_READY = MHD_REQUEST_NORMAL_BODY_UNREADY + 1, /** * 15: We are waiting for the client to provide a chunk of the body. */ MHD_REQUEST_CHUNKED_BODY_UNREADY = MHD_REQUEST_CHUNKED_BODY_READY + 1, /** * 16: We have sent the response body. Prepare the footers. */ MHD_REQUEST_BODY_SENT = MHD_REQUEST_CHUNKED_BODY_UNREADY + 1, /** * 17: We have prepared the response footer. Send it. */ MHD_REQUEST_FOOTERS_SENDING = MHD_REQUEST_BODY_SENT + 1, /** * 18: We have sent the response footer. Shutdown or restart. */ MHD_REQUEST_FOOTERS_SENT = MHD_REQUEST_FOOTERS_SENDING + 1, /** * 19: This request is to be closed. */ MHD_REQUEST_CLOSED = MHD_REQUEST_FOOTERS_SENT + 1, #ifdef UPGRADE_SUPPORT /** * Request was "upgraded" and socket is now under the * control of the application. */ MHD_REQUEST_UPGRADE #endif /* UPGRADE_SUPPORT */ }; /** * Header or cookie in HTTP request or response. */ struct MHD_HTTP_Header { /** * Headers are kept in a linked list. */ struct MHD_HTTP_Header *next; /** * The name of the header (key), without the colon. */ char *header; /** * The value of the header. */ char *value; /** * Type of the header (where in the HTTP protocol is this header * from). */ enum MHD_ValueKind kind; }; /** * State kept for each HTTP request. */ struct MHD_Request { /** * Reference to the `struct MHD_Daemon`. */ struct MHD_Daemon *daemon; /** * Connection this request is associated with. */ 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; /** * Tail of linked list of parsed headers. */ struct MHD_HTTP_Header *headers_received_tail; /** * We allow the main application to associate some pointer with the * HTTP request, which is passed to each #MHD_AccessHandlerCallback * and some other API calls. Here is where we store it. (MHD does * not know or care what it is). */ void *client_context; /** * Request method as string. Should be GET/POST/etc. Allocated in * pool. */ char *method_s; /** * Requested URL (everything after "GET" only). Allocated * in pool. */ const char *url; /** * HTTP version string (i.e. http/1.1). Allocated * in pool. */ char *version_s; /** * Close connection after sending response? * Functions may change value from "Unknown" or "KeepAlive" to "Must close", * but no functions reset value "Must Close" to any other value. */ enum MHD_ConnKeepAlive keepalive; /** * Buffer for reading requests. Allocated in pool. Actually one * byte larger than @e read_buffer_size (if non-NULL) to allow for * 0-termination. */ char *read_buffer; /** * Buffer for writing response (headers only). Allocated * in pool. */ char *write_buffer; /** * Last incomplete header line during parsing of headers. * Allocated in pool. Only valid if state is * either #MHD_REQUEST_HEADER_PART_RECEIVED or * #MHD_REQUEST_FOOTER_PART_RECEIVED. */ char *last; /** * Position after the colon on the last incomplete header * line during parsing of headers. * Allocated in pool. Only valid if state is * either #MHD_REQUEST_HEADER_PART_RECEIVED or * #MHD_REQUEST_FOOTER_PART_RECEIVED. */ char *colon; #ifdef UPGRADE_SUPPORT /** * If this connection was upgraded, this points to * the upgrade response details such that the * #thread_main_connection_upgrade()-logic can perform the * bi-directional forwarding. */ struct MHD_UpgradeResponseHandle *urh; #endif /* UPGRADE_SUPPORT */ /** * Size of @e read_buffer (in bytes). This value indicates * how many bytes we're willing to read into the buffer; * the real buffer is one byte longer to allow for * adding zero-termination (when needed). */ size_t read_buffer_size; /** * Position where we currently append data in * @e read_buffer (last valid position). */ size_t read_buffer_offset; /** * Size of @e write_buffer (in bytes). */ size_t write_buffer_size; /** * Offset where we are with sending from @e write_buffer. */ size_t write_buffer_send_offset; /** * Last valid location in write_buffer (where do we * append and up to where is it safe to send?) */ size_t write_buffer_append_offset; /** * Number of bytes we had in the HTTP header, set once we * pass #MHD_REQUEST_HEADERS_RECEIVED. */ size_t header_size; /** * How many more bytes of the body do we expect * to read? #MHD_SIZE_UNKNOWN for unknown. */ uint64_t remaining_upload_size; /** * If we are receiving with chunked encoding, where are we right * now? Set to 0 if we are waiting to receive the chunk size; * otherwise, this is the size of the current chunk. A value of * zero is also used when we're at the end of the chunks. */ uint64_t current_chunk_size; /** * If we are receiving with chunked encoding, where are we currently * with respect to the current chunk (at what offset / position)? */ uint64_t current_chunk_offset; /** * Current write position in the actual response * (excluding headers, content only; should be 0 * while sending headers). */ uint64_t response_write_position; #if defined(_MHD_HAVE_SENDFILE) // FIXME: document, fix capitalization! enum MHD_resp_sender_ { MHD_resp_sender_std = 0, MHD_resp_sender_sendfile } resp_sender; #endif /* _MHD_HAVE_SENDFILE */ /** * Position in the 100 CONTINUE message that * we need to send when receiving http 1.1 requests. */ size_t continue_message_write_offset; /** * State in the FSM for this 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; /** * Are we currently inside the "idle" handler (to avoid recursively * invoking it). */ bool in_idle; /** * Are we currently inside the "idle" handler (to avoid recursively * invoking it). */ bool in_cleanup; /** * Are we receiving with chunked encoding? This will be set to * #MHD_YES after we parse the headers and are processing the body * with chunks. After we are done with the body and we are * processing the footers; once the footers are also done, this will * be set to #MHD_NO again (before the final call to the handler). */ bool have_chunked_upload; }; /** * 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 }; /** * State kept per HTTP connection. */ struct MHD_Connection { #ifdef EPOLL_SUPPORT /** * Next pointer for the EDLL listing connections that are epoll-ready. */ struct MHD_Connection *nextE; /** * Previous pointer for the EDLL listing connections that are epoll-ready. */ struct MHD_Connection *prevE; #endif /** * Next pointer for the DLL describing our IO state. */ struct MHD_Connection *next; /** * Previous pointer for the DLL describing our IO state. */ struct MHD_Connection *prev; /** * Next pointer for the XDLL organizing connections by timeout. * This DLL can be either the * 'manual_timeout_head/manual_timeout_tail' or the * 'normal_timeout_head/normal_timeout_tail', depending on whether a * custom timeout is set for the connection. */ struct MHD_Connection *nextX; /** * Previous pointer for the XDLL organizing connections by timeout. */ struct MHD_Connection *prevX; /** * Reference to the MHD_Daemon struct. */ struct MHD_Daemon *daemon; /** * The memory pool is created whenever we first read from the TCP * stream and destroyed at the end of each request (and re-created * for the next request). In the meantime, this pointer is NULL. * The pool is used for all request-related data except for the * response (which maybe shared between requests) and the IP * address (which persists across individual requests). */ struct MemoryPool *pool; /** * We allow the main application to associate some pointer with the * TCP connection (which may span multiple HTTP requests). Here is * where we store it. (MHD does not know or care what it is). * The location is given to the #MHD_NotifyConnectionCallback and * also accessible via #MHD_CONNECTION_INFO_SOCKET_CONTEXT. */ void *socket_context; #ifdef HTTPS_SUPPORT /** * State kept per TLS connection. Plugin-specific. */ struct MHD_TLS_ConnectionState *tls_cs; #endif /** * Function used for reading HTTP request stream. */ ReceiveCallback recv_cls; /** * Function used for writing HTTP response stream. */ TransmitCallback send_cls; /** * Information about the current request we are processing * on this connection. */ struct MHD_Request request; /** * Thread handle for this connection (if we are using * one thread per connection). */ MHD_thread_handle_ID_ pid; /** * Foreign address (of length @e addr_len). */ struct sockaddr_storage addr; /** * Length of the foreign address. */ socklen_t addr_len; /** * Last time this connection had any activity * (reading or writing). */ time_t last_activity; /** * After how many seconds of inactivity should * this connection time out? Zero for no timeout. */ time_t connection_timeout; /** * Socket for this connection. Set to #MHD_INVALID_SOCKET if * this connection has died (daemon should clean * up in that case). */ MHD_socket socket_fd; #ifdef EPOLL_SUPPORT /** * What is the state of this socket in relation to epoll? */ enum MHD_EpollState epoll_state; #endif /** * Is the connection suspended? */ bool suspended; /** * Are we ready to read from TLS for this connection? */ bool tls_read_ready; /** * Is the connection wanting to resume? */ bool resuming; /** * Set to `true` if the thread has been joined. */ bool thread_joined; /** * true if #socket_fd is non-blocking, false otherwise. */ bool sk_nonblck; /** * Has this socket been closed for reading (i.e. other side closed * the connection)? If so, we must completely close the connection * once we are done sending our response (and stop trying to read * from this socket). */ bool read_closed; }; #ifdef UPGRADE_SUPPORT /** * Buffer we use for upgrade response handling in the unlikely * case where the memory pool was so small it had no buffer * capacity left. Note that we don't expect to _ever_ use this * buffer, so it's mostly wasted memory (except that it allows * us to handle a tricky error condition nicely). So no need to * make this one big. Applications that want to perform well * should just pick an adequate size for the memory pools. */ #define RESERVE_EBUF_SIZE 8 /** * Context we pass to epoll() for each of the two sockets * of a `struct MHD_UpgradeResponseHandle`. We need to do * this so we can distinguish the two sockets when epoll() * gives us event notifications. */ struct UpgradeEpollHandle { /** * Reference to the overall response handle this struct is * included within. */ struct MHD_UpgradeResponseHandle *urh; /** * The socket this event is kind-of about. Note that this is NOT * necessarily the socket we are polling on, as for when we read * from TLS, we epoll() on the connection's socket * (`urh->connection->socket_fd`), while this then the application's * socket (where the application will read from). Nevertheless, for * the application to read, we need to first read from TLS, hence * the two are related. * * Similarly, for writing to TLS, this epoll() will be on the * connection's `socket_fd`, and this will merely be the FD which * the applicatio would write to. Hence this struct must always be * interpreted based on which field in `struct * MHD_UpgradeResponseHandle` it is (`app` or `mhd`). */ MHD_socket socket; /** * IO-state of the @e socket (or the connection's `socket_fd`). */ enum MHD_EpollState celi; }; /** * Handle given to the application to manage special * actions relating to MHD responses that "upgrade" * the HTTP protocol (i.e. to WebSockets). */ struct MHD_UpgradeResponseHandle { /** * The connection for which this is an upgrade handle. Note that * because a response may be shared over many connections, this may * not be the only upgrade handle for the response of this connection. */ struct MHD_Connection *connection; #ifdef HTTPS_SUPPORT /** * Kept in a DLL per daemon. */ struct MHD_UpgradeResponseHandle *next; /** * Kept in a DLL per daemon. */ struct MHD_UpgradeResponseHandle *prev; #ifdef EPOLL_SUPPORT /** * Next pointer for the EDLL listing urhs that are epoll-ready. */ struct MHD_UpgradeResponseHandle *nextE; /** * Previous pointer for the EDLL listing urhs that are epoll-ready. */ struct MHD_UpgradeResponseHandle *prevE; /** * Specifies whether urh already in EDLL list of ready connections. */ bool in_eready_list; #endif /** * The buffer for receiving data from TLS to * be passed to the application. Contains @e in_buffer_size * bytes (unless @e in_buffer_size is zero). Do not free! */ char *in_buffer; /** * The buffer for receiving data from the application to * be passed to TLS. Contains @e out_buffer_size * bytes (unless @e out_buffer_size is zero). Do not free! */ char *out_buffer; /** * Size of the @e in_buffer. * Set to 0 if the TLS connection went down for reading or socketpair * went down for writing. */ size_t in_buffer_size; /** * Size of the @e out_buffer. * Set to 0 if the TLS connection went down for writing or socketpair * went down for reading. */ size_t out_buffer_size; /** * Number of bytes actually in use in the @e in_buffer. Can be larger * than @e in_buffer_size if and only if @a in_buffer_size is zero and * we still have bytes that can be forwarded. * Reset to zero if all data was forwarded to socketpair or * if socketpair went down for writing. */ size_t in_buffer_used; /** * Number of bytes actually in use in the @e out_buffer. Can be larger * than @e out_buffer_size if and only if @a out_buffer_size is zero and * we still have bytes that can be forwarded. * Reset to zero if all data was forwarded to TLS connection or * if TLS connection went down for writing. */ size_t out_buffer_used; /** * The socket we gave to the application (r/w). */ struct UpgradeEpollHandle app; /** * If @a app_sock was a socketpair, our end of it, otherwise * #MHD_INVALID_SOCKET; (r/w). */ struct UpgradeEpollHandle mhd; /** * Emergency IO buffer we use in case the memory pool has literally * nothing left. */ char e_buf[RESERVE_EBUF_SIZE]; #endif /* HTTPS_SUPPORT */ /** * Set to true after the application finished with the socket * by #MHD_UPGRADE_ACTION_CLOSE. * * When BOTH @e was_closed (changed by command from application) * AND @e clean_ready (changed internally by MHD) are set to * #MHD_YES, function #MHD_resume_connection() will move this * connection to cleanup list. * @remark This flag could be changed from any thread. */ volatile bool was_closed; /** * Set to true if connection is ready for cleanup. * * In TLS mode functions #MHD_connection_finish_forward_() must * be called before setting this flag to true. * * In thread-per-connection mode, true in this flag means * that connection's thread exited or about to exit and will * not use MHD_Connection::urh data anymore. * * In any mode true in this flag also means that * MHD_Connection::urh data will not be used for socketpair * forwarding and forwarding itself is finished. * * When BOTH @e was_closed (changed by command from application) * AND @e clean_ready (changed internally by MHD) are set to * true, function #MHD_resume_connection() will move this * connection to cleanup list. * @remark This flag could be changed from thread that process * connection's recv(), send() and response. */ bool clean_ready; }; #endif /* UPGRADE_SUPPORT */ /** * 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_cb_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; /** * Pointer to master daemon (NULL if this is the master) */ struct MHD_Daemon *master; /** * Worker daemons (one per thread) */ struct MHD_Daemon *worker_pool; #if HTTPS_SUPPORT #ifdef UPGRADE_SUPPORT /** * Head of DLL of upgrade response handles we are processing. * Used for upgraded TLS connections when thread-per-connection * is not used. */ struct MHD_UpgradeResponseHandle *urh_head; /** * Tail of DLL of upgrade response handles we are processing. * Used for upgraded TLS connections when thread-per-connection * is not used. */ struct MHD_UpgradeResponseHandle *urh_tail; #endif /* UPGRADE_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 /** * Head of the XDLL of ALL connections with a default ('normal') * timeout, sorted by timeout (earliest at the tail, most recently * used connection at the head). MHD can just look at the tail of * this list to determine the timeout for all of its elements; * whenever there is an event of a connection, the connection is * moved back to the tail of the list. * * All connections by default start in this list; if a custom * timeout that does not match @e connection_timeout is set, they * are moved to the @e manual_timeout_head-XDLL. * Not used in MHD_USE_THREAD_PER_CONNECTION mode as each thread * needs only one connection-specific timeout. */ struct MHD_Connection *normal_timeout_head; /** * Tail of the XDLL of ALL connections with a default timeout, * sorted by timeout (earliest timeout at the tail). * Not used in MHD_USE_THREAD_PER_CONNECTION mode. */ struct MHD_Connection *normal_timeout_tail; /** * Head of the XDLL of ALL connections with a non-default/custom * timeout, unsorted. MHD will do a O(n) scan over this list to * determine the current timeout. * Not used in MHD_USE_THREAD_PER_CONNECTION mode. */ struct MHD_Connection *manual_timeout_head; /** * Tail of the XDLL of ALL connections with a non-default/custom * timeout, unsorted. * Not used in MHD_USE_THREAD_PER_CONNECTION mode. */ struct MHD_Connection *manual_timeout_tail; /** * Head of doubly-linked list of our current, active connections. */ struct MHD_Connection *connections_head; /** * Tail of doubly-linked list of our current, active connections. */ struct MHD_Connection *connections_tail; /** * Head of doubly-linked list of our current but suspended * connections. */ struct MHD_Connection *suspended_connections_head; /** * Tail of doubly-linked list of our current but suspended * connections. */ struct MHD_Connection *suspended_connections_tail; /** * Head of doubly-linked list of connections to clean up. */ struct MHD_Connection *cleanup_head; /** * Tail of doubly-linked list of connections to clean up. */ struct MHD_Connection *cleanup_tail; /** * Table storing number of connections per IP */ void *per_ip_connection_count; #ifdef EPOLL_SUPPORT /** * Head of EDLL of connections ready for processing (in epoll mode). */ struct MHD_Connection *eready_head; /** * Tail of EDLL of connections ready for processing (in epoll mode) */ struct MHD_Connection *eready_tail; /** * Pointer to marker used to indicate ITC slot in epoll sets. */ const char *epoll_itc_marker; #ifdef UPGRADE_SUPPORT /** * Head of EDLL of upgraded connections ready for processing (in epoll mode). */ struct MHD_UpgradeResponseHandle *eready_urh_head; /** * Tail of EDLL of upgraded connections ready for processing (in epoll mode) */ struct MHD_UpgradeResponseHandle *eready_urh_tail; #endif /* UPGRADE_SUPPORT */ #endif /* EPOLL_SUPPORT */ #ifdef DAUTH_SUPPORT /** * Character array of random values. */ const char *digest_auth_random; /** * An array that contains the map nonce-nc. */ struct MHD_NonceNc *nnc; /** * A rw-lock for synchronizing access to @e nnc. */ MHD_mutex_ nnc_lock; /** * Size of `digest_auth_random. */ size_t digest_auth_rand_size; /** * Size of the nonce-nc array. */ unsigned int nonce_nc_size; #endif /** * The select thread handle (if we have internal select) */ MHD_thread_handle_ID_ pid; /** * Socket address to bind to for the listen socket. */ struct sockaddr_storage listen_sa; /** * Mutex for per-IP connection counts. */ MHD_mutex_ per_ip_connection_mutex; /** * Mutex for (modifying) access to the "cleanup", "normal_timeout" and * "manual_timeout" DLLs. */ MHD_mutex_ cleanup_connection_mutex; /** * Number of (valid) bytes in @e listen_sa. Zero * if @e listen_sa is not initialized. */ size_t listen_sa_len; /** * Default size of the per-connection memory pool. */ #define POOL_SIZE_DEFAULT (32 * 1024) /** * Buffer size to use for each connection. Default * is #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; /** * Number of active parallel connections. */ unsigned int connections; /** * Number of worker daemons */ unsigned int worker_pool_size; /** * Default timeout in seconds for idle connections. */ time_t connection_default_timeout; /** * Listen socket we should use, MHD_INVALID_SOCKET means * we are to initialize the socket from the other options given. */ MHD_socket listen_socket; #ifdef EPOLL_SUPPORT /** * File descriptor associated with our epoll loop. */ int epoll_fd; /** * true if the listen socket is in the 'epoll' set, * false if not. */ bool listen_socket_in_epoll; #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) /** * File descriptor associated with the #run_epoll_for_upgrade() loop. * Only available if #MHD_USE_HTTPS_EPOLL_UPGRADE is set. */ int epoll_upgrade_fd; /** * true if @e epoll_upgrade_fd is in the 'epoll' set, * false if not. */ bool upgrade_fd_in_epoll; #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ #endif /** * Inter-thread communication channel. */ struct MHD_itc_ itc; /** * Which threading mode do we use? Postive * numbers indicate the number of worker threads to be used. * Values larger than 1 imply a thread pool. */ enum MHD_ThreadingMode threading_mode; /** * 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_NONE (do not listen). */ 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 to bind to random free port. */ 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; /** * Did we hit some system or process-wide resource limit while * trying to accept() the last time? If so, we don't accept new * connections until we close an existing one. This effectively * temporarily lowers the "connection_limit" to the current * number of connections. */ bool at_limit; /** * 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; /** * 'True' if some data is already waiting to be processed. If set * to 'true' - zero timeout for select()/poll*() is used. Should be * reset each time before processing connections and raised by any * connection which require additional immediately processing * (application does not provide data for response, data waiting in * TLS buffers etc.) */ bool data_already_pending; /** * MHD_daemon_quiesce() was run against this daemon. */ bool was_quiesced; /** * Is some connection wanting to resume? */ bool resuming; /** * Allow reusing the address:port combination when binding. * See #MHD_daemon_listen_allow_address_reuse(). */ bool allow_address_reuse; /** * MHD should speak SHOUTcast instead of HTTP. */ bool enable_shoutcast; /** * Are we shutting down? */ volatile bool shutdown; }; /** * Action function implementing some action to be * performed on a request. * * @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 enum MHD_StatusCode (*ActionCallback) (void *cls, struct MHD_Request *request); /** * Actions are returned by the application to drive the request * handling of MHD. */ struct MHD_Action { /** * Function to call for the action. */ ActionCallback action; /** * Closure for @a action */ void *action_cls; }; /** * Representation of an HTTP response. */ struct MHD_Response { /** * A response *is* an action. See also * #MHD_action_from_response(). Hence this field * must be the first field in a response! */ struct MHD_Action action; /** * Headers to send for the response. Initially * the linked list is created in inverse order; * the order should be inverted before sending! */ struct MHD_HTTP_Header *first_header; /** * Buffer pointing to data that we are supposed * to send as a response. */ char *data; /** * Closure to give to the content reader @e crc * and content reader free callback @e crfc. */ void *crc_cls; /** * How do we get more data? NULL if we are * given all of the data up front. */ MHD_ContentReaderCallback crc; /** * NULL if data must not be freed, otherwise * either user-specified callback or "&free". */ MHD_ContentReaderFreeCallback crfc; /** * Function to call once MHD is finished with * the request, may be NULL. */ MHD_RequestTerminationCallback termination_cb; /** * Closure for @e termination_cb. */ void *termination_cb_cls; #ifdef UPGRADE_SUPPORT /** * Application function to call once we are done sending the headers * of the response; NULL unless this is a response created with * #MHD_create_response_for_upgrade(). */ MHD_UpgradeHandler upgrade_handler; /** * Closure for @e uh. */ void *upgrade_handler_cls; #endif /* UPGRADE_SUPPORT */ /** * Mutex to synchronize access to @e data, @e size and * @e reference_count. */ MHD_mutex_ mutex; /** * Set to #MHD_SIZE_UNKNOWN if size is not known. */ uint64_t total_size; /** * At what offset in the stream is the * beginning of @e data located? */ uint64_t data_start; /** * Offset to start reading from when using @e fd. */ uint64_t fd_off; /** * Number of bytes ready in @e data (buffer may be larger * than what is filled with payload). */ size_t data_size; /** * Size of the data buffer @e data. */ size_t data_buffer_size; /** * HTTP status code of the response. */ enum MHD_HTTP_StatusCode status_code; /** * Reference count for this response. Free once the counter hits * zero. */ unsigned int reference_count; /** * File-descriptor if this response is FD-backed. */ int fd; /** * Only respond in HTTP 1.0 mode. */ bool v10_only; /** * Use ShoutCAST format. */ bool icy; }; /** * Callback invoked when iterating over @a key / @a value * argument pairs during parsing. * * @param request 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 true on success (continue to iterate) * false to signal failure (and abort iteration) */ typedef bool (*MHD_ArgumentIterator_)(struct MHD_Request *request, 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 request request to add headers to * @param kind header kind to pass to @a cb * @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 false on failure (@a cb returned false), * true for success (parsing succeeded, @a cb always * returned true) */ bool MHD_parse_arguments_ (struct MHD_Request *request, enum MHD_ValueKind kind, char *args, MHD_ArgumentIterator_ cb, unsigned int *num_headers); /** * Insert an element at the head of a DLL. Assumes that head, tail and * element are structs with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to insert */ #define DLL_insert(head,tail,element) do { \ mhd_assert (NULL == (element)->next); \ mhd_assert (NULL == (element)->prev); \ (element)->next = (head); \ (element)->prev = NULL; \ if ((tail) == NULL) \ (tail) = element; \ else \ (head)->prev = element; \ (head) = (element); } while (0) /** * Remove an element from a DLL. Assumes that head, tail and element * are structs with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to remove */ #define DLL_remove(head,tail,element) do { \ mhd_assert ( (NULL != (element)->next) || ((element) == (tail))); \ mhd_assert ( (NULL != (element)->prev) || ((element) == (head))); \ if ((element)->prev == NULL) \ (head) = (element)->next; \ else \ (element)->prev->next = (element)->next; \ if ((element)->next == NULL) \ (tail) = (element)->prev; \ else \ (element)->next->prev = (element)->prev; \ (element)->next = NULL; \ (element)->prev = NULL; } while (0) /** * Insert an element at the head of a XDLL. Assumes that head, tail and * element are structs with prevX and nextX fields. * * @param head pointer to the head of the XDLL * @param tail pointer to the tail of the XDLL * @param element element to insert */ #define XDLL_insert(head,tail,element) do { \ mhd_assert (NULL == (element)->nextX); \ mhd_assert (NULL == (element)->prevX); \ (element)->nextX = (head); \ (element)->prevX = NULL; \ if (NULL == (tail)) \ (tail) = element; \ else \ (head)->prevX = element; \ (head) = (element); } while (0) /** * Remove an element from a XDLL. Assumes that head, tail and element * are structs with prevX and nextX fields. * * @param head pointer to the head of the XDLL * @param tail pointer to the tail of the XDLL * @param element element to remove */ #define XDLL_remove(head,tail,element) do { \ mhd_assert ( (NULL != (element)->nextX) || ((element) == (tail))); \ mhd_assert ( (NULL != (element)->prevX) || ((element) == (head))); \ if (NULL == (element)->prevX) \ (head) = (element)->nextX; \ else \ (element)->prevX->nextX = (element)->nextX; \ if (NULL == (element)->nextX) \ (tail) = (element)->prevX; \ else \ (element)->nextX->prevX = (element)->prevX; \ (element)->nextX = NULL; \ (element)->prevX = NULL; } while (0) /** * Insert an element at the head of a EDLL. Assumes that head, tail and * element are structs with prevE and nextE fields. * * @param head pointer to the head of the EDLL * @param tail pointer to the tail of the EDLL * @param element element to insert */ #define EDLL_insert(head,tail,element) do { \ (element)->nextE = (head); \ (element)->prevE = NULL; \ if ((tail) == NULL) \ (tail) = element; \ else \ (head)->prevE = element; \ (head) = (element); } while (0) /** * Remove an element from a EDLL. Assumes that head, tail and element * are structs with prevE and nextE fields. * * @param head pointer to the head of the EDLL * @param tail pointer to the tail of the EDLL * @param element element to remove */ #define EDLL_remove(head,tail,element) do { \ if ((element)->prevE == NULL) \ (head) = (element)->nextE; \ else \ (element)->prevE->nextE = (element)->nextE; \ if ((element)->nextE == NULL) \ (tail) = (element)->prevE; \ else \ (element)->nextE->prevE = (element)->prevE; \ (element)->nextE = NULL; \ (element)->prevE = NULL; } while (0) /** * Error code similar to EGAIN or EINTR */ #define MHD_ERR_AGAIN_ (-3073) /** * Connection was hard-closed by remote peer. */ #define MHD_ERR_CONNRESET_ (-3074) /** * Connection is not connected anymore due to * network error or any other reason. */ #define MHD_ERR_NOTCONN_ (-3075) /** * "Not enough memory" error code */ #define MHD_ERR_NOMEM_ (-3076) /** * "Bad FD" error code */ #define MHD_ERR_BADF_ (-3077) /** * Error code similar to EINVAL */ #define MHD_ERR_INVAL_ (-3078) #endif