| /* |
| This file is part of libmicrohttpd |
| Copyright (C) 2007-2015 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 "platform.h" |
| #include "microhttpd.h" |
| #include "platform_interface.h" |
| #if HTTPS_SUPPORT |
| #include <openssl/ssl.h> |
| #endif |
| #if EPOLL_SUPPORT |
| #include <sys/epoll.h> |
| #endif |
| #if HAVE_NETINET_TCP_H |
| /* for TCP_FASTOPEN */ |
| #include <netinet/tcp.h> |
| #endif |
| |
| |
| /** |
| * 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() |
| #else |
| #define BUILTIN_NOT_REACHED |
| #endif |
| |
| |
| #if 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 |
| |
| |
| /** |
| * 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 |
| }; |
| |
| |
| /** |
| * What is this connection waiting for? |
| */ |
| enum MHD_ConnectionEventLoopInfo |
| { |
| /** |
| * 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 |
| }; |
| |
| |
| /** |
| * Maximum length of a nonce in digest authentication. 32(MD5 Hex) + |
| * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera |
| * (already) takes more (see Mantis #1633), so we've increased the |
| * value to support something longer... |
| */ |
| #define MAX_NONCE_LENGTH 129 |
| |
| |
| /** |
| * A structure representing the internal holder of the |
| * nonce-nc map. |
| */ |
| struct MHD_NonceNc |
| { |
| |
| /** |
| * Nonce counter, a value that increases for each subsequent |
| * request for the same nonce. |
| */ |
| unsigned long int nc; |
| |
| /** |
| * Nonce value: |
| */ |
| char nonce[MAX_NONCE_LENGTH]; |
| |
| }; |
| |
| #if HAVE_MESSAGES |
| /** |
| * fprintf-like helper function for logging debug |
| * messages. |
| */ |
| void |
| MHD_DLOG (const struct MHD_Daemon *daemon, |
| const char *format, ...); |
| #endif |
| |
| |
| /** |
| * 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; |
| |
| }; |
| |
| |
| /** |
| * Representation of a response. |
| */ |
| struct MHD_Response |
| { |
| |
| /** |
| * 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; |
| |
| /** |
| * 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. |
| */ |
| off_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; |
| |
| /** |
| * 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; |
| |
| /** |
| * Flags set for the MHD response. |
| */ |
| enum MHD_ResponseFlags flags; |
| |
| }; |
| |
| |
| /** |
| * States in a state machine for a connection. |
| * |
| * Transitions are any-state to CLOSED, any state to state+1, |
| * FOOTERS_SENT to INIT. CLOSED is the terminal state and |
| * 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 CLOSED or INIT |
| * requires the write to be complete. |
| */ |
| enum MHD_CONNECTION_STATE |
| { |
| /** |
| * Connection just started (no headers received). |
| * Waiting for the line with the request type, URL and version. |
| */ |
| MHD_CONNECTION_INIT = 0, |
| |
| /** |
| * 1: We got the URL (and request type and version). Wait for a header line. |
| */ |
| MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1, |
| |
| /** |
| * 2: We got part of a multi-line request header. Wait for the rest. |
| */ |
| MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1, |
| |
| /** |
| * 3: We got the request headers. Process them. |
| */ |
| MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1, |
| |
| /** |
| * 4: We have processed the request headers. Send 100 continue. |
| */ |
| MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1, |
| |
| /** |
| * 5: We have processed the headers and need to send 100 CONTINUE. |
| */ |
| MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1, |
| |
| /** |
| * 6: We have sent 100 CONTINUE (or do not need to). Read the message body. |
| */ |
| MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1, |
| |
| /** |
| * 7: We got the request body. Wait for a line of the footer. |
| */ |
| MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1, |
| |
| /** |
| * 8: We got part of a line of the footer. Wait for the |
| * rest. |
| */ |
| MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1, |
| |
| /** |
| * 9: We received the entire footer. Wait for a response to be queued |
| * and prepare the response headers. |
| */ |
| MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1, |
| |
| /** |
| * 10: We have prepared the response headers in the writ buffer. |
| * Send the response headers. |
| */ |
| MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1, |
| |
| /** |
| * 11: We have sent the response headers. Get ready to send the body. |
| */ |
| MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1, |
| |
| /** |
| * 12: We are ready to send a part of a non-chunked body. Send it. |
| */ |
| MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1, |
| |
| /** |
| * 13: We are waiting for the client to provide more |
| * data of a non-chunked body. |
| */ |
| MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1, |
| |
| /** |
| * 14: We are ready to send a chunk. |
| */ |
| MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1, |
| |
| /** |
| * 15: We are waiting for the client to provide a chunk of the body. |
| */ |
| MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1, |
| |
| /** |
| * 16: We have sent the response body. Prepare the footers. |
| */ |
| MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1, |
| |
| /** |
| * 17: We have prepared the response footer. Send it. |
| */ |
| MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1, |
| |
| /** |
| * 18: We have sent the response footer. Shutdown or restart. |
| */ |
| MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1, |
| |
| /** |
| * 19: This connection is to be closed. |
| */ |
| MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1, |
| |
| /** |
| * 20: This connection is finished (only to be freed) |
| */ |
| MHD_CONNECTION_IN_CLEANUP = MHD_CONNECTION_CLOSED + 1, |
| |
| /* |
| * SSL/TLS connection states |
| */ |
| |
| /** |
| * The initial connection state for all secure connectoins |
| * Handshake messages will be processed in this state & while |
| * in the 'MHD_TLS_HELLO_REQUEST' state |
| */ |
| MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_IN_CLEANUP + 1 |
| |
| }; |
| |
| /** |
| * Should all state transitions be printed to stderr? |
| */ |
| #define DEBUG_STATES MHD_NO |
| |
| |
| #if HAVE_MESSAGES |
| #if DEBUG_STATES |
| const char * |
| MHD_state_to_string (enum MHD_CONNECTION_STATE state); |
| #endif |
| #endif |
| |
| /** |
| * 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 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 *write_to, |
| size_t max_bytes); |
| |
| |
| /** |
| * State kept for each HTTP request. |
| */ |
| struct MHD_Connection |
| { |
| |
| #if 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; |
| |
| /** |
| * 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; |
| |
| /** |
| * Response to transmit (initially NULL). |
| */ |
| struct MHD_Response *response; |
| |
| /** |
| * 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 connection-related data |
| * except for the response (which maybe shared between |
| * connections) and the IP address (which persists |
| * across individual requests). |
| */ |
| struct MemoryPool *pool; |
| |
| /** |
| * 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; |
| |
| /** |
| * 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; |
| |
| /** |
| * Request method. Should be GET/POST/etc. Allocated |
| * in pool. |
| */ |
| char *method; |
| |
| /** |
| * Requested URL (everything after "GET" only). Allocated |
| * in pool. |
| */ |
| char *url; |
| |
| /** |
| * HTTP version string (i.e. http/1.1). Allocated |
| * in pool. |
| */ |
| char *version; |
| |
| /** |
| * 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_CONNECTION_HEADER_PART_RECEIVED or |
| * #MHD_CONNECTION_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_CONNECTION_HEADER_PART_RECEIVED or |
| * #MHD_CONNECTION_FOOTER_PART_RECEIVED. |
| */ |
| char *colon; |
| |
| /** |
| * Foreign address (of length @e addr_len). MALLOCED (not |
| * in pool!). |
| */ |
| struct sockaddr *addr; |
| |
| /** |
| * Thread handle for this connection (if we are using |
| * one thread per connection). |
| */ |
| MHD_thread_handle_ pid; |
| |
| /** |
| * Size of 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 |
| * read_buffer (last valid position). |
| */ |
| size_t read_buffer_offset; |
| |
| /** |
| * Size of write_buffer (in bytes). |
| */ |
| size_t write_buffer_size; |
| |
| /** |
| * Offset where we are with sending from 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; |
| |
| /** |
| * How many more bytes of the body do we expect |
| * to read? #MHD_SIZE_UNKNOWN for unknown. |
| */ |
| uint64_t remaining_upload_size; |
| |
| /** |
| * Current write position in the actual response |
| * (excluding headers, content only; should be 0 |
| * while sending headers). |
| */ |
| uint64_t response_write_position; |
| |
| /** |
| * Position in the 100 CONTINUE message that |
| * we need to send when receiving http 1.1 requests. |
| */ |
| size_t continue_message_write_offset; |
| |
| /** |
| * 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. |
| */ |
| unsigned int connection_timeout; |
| |
| /** |
| * Did we ever call the "default_handler" on this connection? |
| * (this flag will determine if we call the 'notify_completed' |
| * handler when the connection closes down). |
| */ |
| int client_aware; |
| |
| /** |
| * 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; |
| |
| /** |
| * 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). |
| */ |
| int read_closed; |
| |
| /** |
| * Set to #MHD_YES if the thread has been joined. |
| */ |
| int thread_joined; |
| |
| /** |
| * Are we currently inside the "idle" handler (to avoid recursively invoking it). |
| */ |
| int in_idle; |
| |
| #if EPOLL_SUPPORT |
| /** |
| * What is the state of this socket in relation to epoll? |
| */ |
| enum MHD_EpollState epoll_state; |
| #endif |
| |
| /** |
| * State in the FSM for this connection. |
| */ |
| enum MHD_CONNECTION_STATE state; |
| |
| /** |
| * What is this connection waiting for? |
| */ |
| enum MHD_ConnectionEventLoopInfo event_loop_info; |
| |
| /** |
| * HTTP response code. Only valid if response object |
| * is already set. |
| */ |
| unsigned int responseCode; |
| |
| /** |
| * Set to MHD_YES if the response's content reader |
| * callback failed to provide data the last time |
| * we tried to read from it. In that case, the |
| * write socket should be marked as unready until |
| * the CRC call succeeds. |
| */ |
| int response_unready; |
| |
| /** |
| * 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). |
| */ |
| int have_chunked_upload; |
| |
| /** |
| * 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. |
| */ |
| size_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)? |
| */ |
| size_t current_chunk_offset; |
| |
| /** |
| * Handler used for processing read connection operations |
| */ |
| int (*read_handler) (struct MHD_Connection *connection); |
| |
| /** |
| * Handler used for processing write connection operations |
| */ |
| int (*write_handler) (struct MHD_Connection *connection); |
| |
| /** |
| * Handler used for processing idle connection operations |
| */ |
| int (*idle_handler) (struct MHD_Connection *connection); |
| |
| /** |
| * Function used for reading HTTP request stream. |
| */ |
| ReceiveCallback recv_cls; |
| |
| /** |
| * Function used for writing HTTP response stream. |
| */ |
| TransmitCallback send_cls; |
| |
| #if HTTPS_SUPPORT |
| /** |
| * State required for HTTPS/SSL/TLS support. |
| */ |
| SSL* tls_session; |
| |
| /** |
| * Memory location to return for protocol session info. |
| */ |
| const char* protocol; |
| |
| /** |
| * Memory location to return for protocol session info. |
| */ |
| const char* cipher; |
| |
| /** |
| * Could it be that we are ready to read due to TLS buffers |
| * even though the socket is not? |
| */ |
| int tls_read_ready; |
| #endif |
| |
| /** |
| * Is the connection suspended? |
| */ |
| int suspended; |
| |
| /** |
| * Is the connection wanting to resume? |
| */ |
| int resuming; |
| }; |
| |
| /** |
| * Signature of function called to log URI accesses. |
| * |
| * @param cls closure |
| * @param uri uri being accessed |
| * @param con connection handle |
| * @return new closure |
| */ |
| typedef void * |
| (*LogCallback)(void * cls, |
| const char * uri, |
| struct MHD_Connection *con); |
| |
| /** |
| * Signature of function called to unescape URIs. See also |
| * #MHD_http_unescape(). |
| * |
| * @param cls closure |
| * @param conn connection handle |
| * @param uri 0-terminated string to unescape (should be updated) |
| * @return length of the resulting string |
| */ |
| typedef size_t |
| (*UnescapeCallback)(void *cls, |
| struct MHD_Connection *conn, |
| char *uri); |
| |
| |
| /** |
| * 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 |
| { |
| |
| /** |
| * Callback function for all requests. |
| */ |
| MHD_AccessHandlerCallback default_handler; |
| |
| /** |
| * Closure argument to default_handler. |
| */ |
| void *default_handler_cls; |
| |
| /** |
| * 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; |
| |
| #if 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; |
| #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 'connection_timeout' is set, they |
| * are moved to the 'manual_timeout_head'-XDLL. |
| */ |
| 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). |
| */ |
| 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. |
| */ |
| struct MHD_Connection *manual_timeout_head; |
| |
| /** |
| * Tail of the XDLL of ALL connections with a non-default/custom |
| * timeout, unsorted. |
| */ |
| struct MHD_Connection *manual_timeout_tail; |
| |
| /** |
| * Function to call to check if we should accept or reject an |
| * incoming request. May be NULL. |
| */ |
| MHD_AcceptPolicyCallback apc; |
| |
| /** |
| * Closure argument to apc. |
| */ |
| void *apc_cls; |
| |
| /** |
| * Function to call when we are done processing |
| * a particular request. May be NULL. |
| */ |
| MHD_RequestCompletedCallback notify_completed; |
| |
| /** |
| * Closure argument to notify_completed. |
| */ |
| void *notify_completed_cls; |
| |
| /** |
| * Function to call when we are starting/stopping |
| * a connection. May be NULL. |
| */ |
| MHD_NotifyConnectionCallback notify_connection; |
| |
| /** |
| * Closure argument to notify_connection. |
| */ |
| void *notify_connection_cls; |
| |
| /** |
| * Function to call with the full URI at the |
| * beginning of request processing. May be NULL. |
| * <p> |
| * Returns the initial pointer to internal state |
| * kept by the client for the request. |
| */ |
| LogCallback uri_log_callback; |
| |
| /** |
| * Closure argument to @e uri_log_callback. |
| */ |
| void *uri_log_callback_cls; |
| |
| /** |
| * Function to call when we unescape escape sequences. |
| */ |
| UnescapeCallback unescape_callback; |
| |
| /** |
| * Closure for @e unescape_callback. |
| */ |
| void *unescape_callback_cls; |
| |
| #if HAVE_MESSAGES |
| /** |
| * Function for logging error messages (if we |
| * support error reporting). |
| */ |
| void (*custom_error_log) (void *cls, const char *fmt, va_list va); |
| |
| /** |
| * Closure argument to custom_error_log. |
| */ |
| void *custom_error_log_cls; |
| #endif |
| |
| /** |
| * Pointer to master daemon (NULL if this is the master) |
| */ |
| struct MHD_Daemon *master; |
| |
| /** |
| * Worker daemons (one per thread) |
| */ |
| struct MHD_Daemon *worker_pool; |
| |
| /** |
| * Table storing number of connections per IP |
| */ |
| void *per_ip_connection_count; |
| |
| /** |
| * Size of the per-connection memory pools. |
| */ |
| size_t pool_size; |
| |
| /** |
| * Increment for growth of the per-connection memory pools. |
| */ |
| size_t pool_increment; |
| |
| /** |
| * Size of threads created by MHD. |
| */ |
| size_t thread_stack_size; |
| |
| /** |
| * Number of worker daemons |
| */ |
| unsigned int worker_pool_size; |
| |
| /** |
| * The select thread handle (if we have internal select) |
| */ |
| MHD_thread_handle_ pid; |
| |
| /** |
| * Mutex for per-IP connection counts. |
| */ |
| MHD_mutex_ per_ip_connection_mutex; |
| |
| /** |
| * Mutex for (modifying) access to the "cleanup" connection DLL. |
| */ |
| MHD_mutex_ cleanup_connection_mutex; |
| |
| /** |
| * Listen socket. |
| */ |
| MHD_socket socket_fd; |
| |
| /** |
| * Whether to allow/disallow/ignore reuse of listening address. |
| * The semantics is the following: |
| * 0: ignore (user did not ask for neither allow/disallow, use SO_REUSEADDR) |
| * >0: allow (use SO_REUSEPORT on most platforms, SO_REUSEADDR on Windows) |
| * <0: disallow (mostly no action, SO_EXCLUSIVEADDRUSE on Windows) |
| */ |
| int listening_address_reuse; |
| |
| #if EPOLL_SUPPORT |
| /** |
| * File descriptor associated with our epoll loop. |
| */ |
| int epoll_fd; |
| |
| /** |
| * MHD_YES if the listen socket is in the 'epoll' set, |
| * MHD_NO if not. |
| */ |
| int listen_socket_in_epoll; |
| #endif |
| |
| /** |
| * Pipe we use to signal shutdown, unless |
| * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen |
| * socket (which we can then 'shutdown' to stop listening). |
| * MHD can be build with usage of socketpair instead of |
| * pipe (forced on W32). |
| */ |
| MHD_pipe wpipe[2]; |
| |
| /** |
| * Are we shutting down? |
| */ |
| int shutdown; |
| |
| /* |
| * Do we need to process resuming connections? |
| */ |
| int resuming; |
| |
| /** |
| * Number of active parallel connections. |
| */ |
| unsigned int connections; |
| |
| /** |
| * Limit on the number of parallel connections. |
| */ |
| unsigned int connection_limit; |
| |
| /** |
| * After how many seconds of inactivity should |
| * connections time out? Zero for no timeout. |
| */ |
| unsigned int connection_timeout; |
| |
| /** |
| * Maximum number of connections per IP, or 0 for |
| * unlimited. |
| */ |
| unsigned int per_ip_connection_limit; |
| |
| /** |
| * Daemon's flags (bitfield). |
| */ |
| enum MHD_FLAG options; |
| |
| /** |
| * Listen port. |
| */ |
| uint16_t port; |
| |
| #if HTTPS_SUPPORT |
| SSL_CTX* tls_context; |
| /** |
| * Pointer to our SSL/TLS key (in PEM) in memory. |
| */ |
| const char *https_mem_key; |
| |
| /** |
| * Pointer to our SSL/TLS certificate (in PEM) in memory. |
| */ |
| const char *https_mem_cert; |
| |
| /** |
| * Pointer to 0-terminated HTTPS passphrase in memory. |
| */ |
| const char *https_key_password; |
| |
| /** |
| * Pointer to our SSL/TLS certificate authority (in PEM) in memory. |
| */ |
| const char *https_mem_trust; |
| |
| /** |
| * Our Diffie-Hellman parameters (in PEM) in memory. |
| */ |
| const char *https_mem_dhparams; |
| |
| /** |
| * Pointer to SSL/TLS cipher string in memory. |
| */ |
| const char *https_mem_cipher; |
| |
| /** |
| * For how many connections do we have 'tls_read_ready' set to MHD_YES? |
| * Used to avoid O(n) traversal over all connections when determining |
| * event-loop timeout (as it needs to be zero if there is any connection |
| * which might have ready data within TLS). |
| */ |
| unsigned int num_tls_read_ready; |
| |
| #endif |
| |
| #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 `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 |
| |
| #ifdef TCP_FASTOPEN |
| /** |
| * The queue size for incoming SYN + DATA packets. |
| */ |
| unsigned int fastopen_queue_size; |
| #endif |
| }; |
| |
| |
| #if EXTRA_CHECKS |
| #define EXTRA_CHECK(a) do { if (!(a)) abort(); } while (0) |
| #else |
| #define EXTRA_CHECK(a) |
| #endif |
| |
| |
| /** |
| * 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 { \ |
| EXTRA_CHECK (NULL == (element)->next); \ |
| EXTRA_CHECK (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 { \ |
| EXTRA_CHECK ( (NULL != (element)->next) || ((element) == (tail))); \ |
| EXTRA_CHECK ( (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 { \ |
| EXTRA_CHECK (NULL == (element)->nextX); \ |
| EXTRA_CHECK (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 { \ |
| EXTRA_CHECK ( (NULL != (element)->nextX) || ((element) == (tail))); \ |
| EXTRA_CHECK ( (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) |
| |
| |
| /** |
| * Equivalent to `time(NULL)` but tries to use some sort of monotonic |
| * clock that isn't affected by someone setting the system real time |
| * clock. |
| * |
| * @return 'current' time |
| */ |
| time_t |
| MHD_monotonic_time(void); |
| |
| |
| /** |
| * Convert all occurences of '+' to ' '. |
| * |
| * @param arg string that is modified (in place), must be 0-terminated |
| */ |
| void |
| MHD_unescape_plus (char *arg); |
| |
| |
| #endif |