| /* |
| 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 <gnutls/gnutls.h> |
| #if GNUTLS_VERSION_MAJOR >= 3 |
| #include <gnutls/abstract.h> |
| #endif |
| #endif /* HTTPS_SUPPORT */ |
| |
| #ifdef HAVE_STDBOOL_H |
| #include <stdbool.h> |
| #endif |
| #ifdef MHD_PANIC |
| /* Override any defined MHD_PANIC macro with proper one */ |
| #undef MHD_PANIC |
| #endif /* MHD_PANIC */ |
| |
| #ifdef HAVE_MESSAGES |
| /** |
| * Trigger 'panic' action based on fatal errors. |
| * |
| * @param msg error message (const char *) |
| */ |
| #define MHD_PANIC(msg) do { mhd_panic (mhd_panic_cls, __FILE__, __LINE__, msg); \ |
| BUILTIN_NOT_REACHED; } while (0) |
| #else |
| /** |
| * Trigger 'panic' action based on fatal errors. |
| * |
| * @param msg error message (const char *) |
| */ |
| #define MHD_PANIC(msg) do { mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); \ |
| BUILTIN_NOT_REACHED; } while (0) |
| #endif |
| |
| #include "mhd_threads.h" |
| #include "mhd_locks.h" |
| #include "mhd_sockets.h" |
| #include "mhd_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 application 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? Positive |
| * 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 |