libmicrohttpd

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

commit adb4520d7c43d72dc2af0a7bea94d625a2aee65d
parent f665d62bec2ff75f24ad5ae6e47f770cb906c826
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun,  7 Dec 2008 05:29:14 +0000

fixing 1438 and 1432

Diffstat:
MChangeLog | 4++++
Mconfigure.ac | 34++++++++++++++++++++++------------
Mdoc/microhttpd.texi | 36+++++++++++++++++-------------------
Msrc/daemon/connection.c | 2+-
Msrc/daemon/daemon.c | 12++++++++++++
Msrc/daemon/internal.c | 4+++-
Msrc/daemon/internal.h | 723++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/include/microhttpd.h | 24++++++++++++++++++++----
8 files changed, 485 insertions(+), 354 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,7 @@ +Sat Dec 6 18:36:17 MST 2008 + Added configure option to disable checking for CURL support. + Added MHD_OPTION to allow specification of custom logger. -CG + Tue Nov 18 01:19:53 MST 2008 Removed support for untested and/or broken SSL features and (largely useless) options. -CG diff --git a/configure.ac b/configure.ac @@ -175,17 +175,26 @@ AC_CHECK_DECL([TCP_CORK], [], [], [[#include <netinet/tcp.h>]]) # libcurl (required for testing) SAVE_LIBS=$LIBS -LIBCURL_CHECK_CONFIG(,,curl=1,curl=0) -AM_CONDITIONAL(HAVE_CURL, test x$curl = x1) -LIBS=$SAVE_LIBS +AC_MSG_CHECKING(whether to use libcurl for testing) +AC_ARG_ENABLE(curl, + [AS_HELP_STRING([--enable-curl],[support cURL based testcases])], + [enable_curl=$enableval], + [enable_curl="yes"]) + +if test "$enable_curl" = "yes" +then + LIBCURL_CHECK_CONFIG(,,curl=1,curl=0) + AM_CONDITIONAL(HAVE_CURL, test x$curl = x1) # Lib cURL & cURL - OpenSSL versions -MHD_REQ_CURL_VERSION=7.16.4 -MHD_REQ_CURL_OPENSSL_VERSION=0.9.8 -MHD_REQ_CURL_GNUTLS_VERSION=2.2.3 -AC_DEFINE_UNQUOTED([MHD_REQ_CURL_VERSION], "$MHD_REQ_CURL_VERSION", [required cURL version to run tests]) -AC_DEFINE_UNQUOTED([MHD_REQ_CURL_OPENSSL_VERSION], "$MHD_REQ_CURL_OPENSSL_VERSION", [required cURL SSL version to run tests]) -AC_DEFINE_UNQUOTED([MHD_REQ_CURL_GNUTLS_VERSION], "$MHD_REQ_CURL_GNUTLS_VERSION", [gnuTLS lib version - used in conjunction with cURL]) + MHD_REQ_CURL_VERSION=7.16.4 + MHD_REQ_CURL_OPENSSL_VERSION=0.9.8 + MHD_REQ_CURL_GNUTLS_VERSION=2.2.3 + AC_DEFINE_UNQUOTED([MHD_REQ_CURL_VERSION], "$MHD_REQ_CURL_VERSION", [required cURL version to run tests]) + AC_DEFINE_UNQUOTED([MHD_REQ_CURL_OPENSSL_VERSION], "$MHD_REQ_CURL_OPENSSL_VERSION", [required cURL SSL version to run tests]) + AC_DEFINE_UNQUOTED([MHD_REQ_CURL_GNUTLS_VERSION], "$MHD_REQ_CURL_GNUTLS_VERSION", [gnuTLS lib version - used in conjunction with cURL]) +fi +LIBS=$SAVE_LIBS # large file support (> 4 GB) AC_SYS_LARGEFILE @@ -271,9 +280,10 @@ AC_DEFINE([GNULIB_GC_RANDOM],[1],[GNULIB_GC_RANDOM]) # gcov compilation use_gcov=no -AC_ARG_ENABLE([coverage], AS_HELP_STRING([--enable-coverage], - [compile the library with code coverage support (default is NO)]), - [use_gcov=yes], [use_gcov=no]) +AC_ARG_ENABLE([coverage], + AS_HELP_STRING([--enable-coverage], + [compile the library with code coverage support (default is NO)]), + [use_gcov=yes], [use_gcov=no]) AM_CONDITIONAL([USE_COVERAGE], [test "x$use_gcov" = "xyes"]) diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi @@ -343,24 +343,18 @@ terminated (const) array of 'enum MHD_GNUTLS_CipherAlgorithm' representing the cipher priority order to which the HTTPS daemon should adhere. -@item MHD_OPTION_KX_PRIORITY -Memory pointer to a zero (MHD_GNUTLS_KX_UNKNOWN) -terminated (const) array of 'MHD_GNUTLS_KeyExchangeAlgorithm' -representing the key exchange algorithm priority order to which -the HTTPS daemon should adhere. - -@item MHD_OPTION_CERT_TYPE -Indicate which type of certificate this server will use, -followed by a value of type 'enum MHD_GNUTLS_CertificateType'. - -@item MHD_OPTION_MAC_ALGO -Specify the mac algorithm used by server. -The argument should be of type "enum MHD_GNUTLS_MacAlgorithm" - -@item MHD_OPTION_TLS_COMP_ALGO -Compression algorithm used by server. Should be followed by an -option of type 'enum MHD_GNUTLS_CompressionMethod'. - +@item MHD_OPTION_EXTERNAL_LOGGER +Use the given function for logging error messages. +This option must be followed by two arguments; the +first must be a pointer to a function +of type 'void fun(void * arg, const char * fmt, va_list ap)' +and the second a pointer of type 'void*' which will +be passed as the "arg" argument to "fun". + +Note that MHD will not generate any log messages +if it was compiled without the "--enable-messages" +flag being set and the MHD_USE_DEBUG flag being set, +even if this argument is used. @end table @end deftp @@ -934,7 +928,11 @@ responce and we finally destroy it only when the daemon shuts down. @deftypefun int MHD_queue_response (struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response) Queue a response to be transmitted to the client as soon as possible -(increment the reference counter). +but only after MHD_AccessHandlerCallback returns. This function +checks that it is legal to queue a response at this time for the +given connection. It also increments the internal reference +counter for the response object (the counter will be decremented +automatically once the response has been transmitted). @table @var @item connection diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -208,7 +208,7 @@ MHD_lookup_connection_value (struct MHD_Connection *connection, /** * Queue a response to be transmitted to the client (as soon as - * possible). + * possible but after MHD_AccessHandlerCallback returns). * * @param connection the connection identifying the client * @param status_code HTTP status code (i.e. 200 for OK) diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -834,6 +834,10 @@ MHD_start_daemon_va (unsigned int options, retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; retVal->pool_size = MHD_POOL_SIZE_DEFAULT; retVal->connection_timeout = 0; /* no timeout */ +#if HAVE_MESSAGES + retVal->custom_error_log = (void(*)(void*,const char *,va_list)) &vfprintf; + retVal->custom_error_log_cls = stderr; +#endif #if HTTPS_SUPPORT if (options & MHD_USE_SSL) { @@ -892,6 +896,14 @@ MHD_start_daemon_va (unsigned int options, va_arg (ap, const int *)); break; #endif + case MHD_OPTION_EXTERNAL_LOGGER: +#if HAVE_MESSAGES + retVal->custom_error_log = va_arg(ap, void (*)(void*cls, const char *, va_list)); + retVal->custom_error_log_cls = va_arg(ap, void *); +#else + va_arg(ap, void (*)(void*cls, const char *,...)); + va_arg(ap, void *); +#endif default: #if HAVE_MESSAGES if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) && diff --git a/src/daemon/internal.c b/src/daemon/internal.c @@ -102,7 +102,9 @@ MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...) if ((daemon->options & MHD_USE_DEBUG) == 0) return; va_start (va, format); - VFPRINTF (stderr, format, va); + daemon->custom_error_log(daemon->custom_error_log_cls, + format, + va); va_end (va); } #endif diff --git a/src/daemon/internal.h b/src/daemon/internal.h @@ -66,12 +66,26 @@ void MHD_http_unescape (char *val); */ 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; }; @@ -82,68 +96,68 @@ struct MHD_HTTP_Header 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! - */ + /** + * 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. - */ + /** + * Buffer pointing to data that we are supposed + * to send as a response. + */ char *data; - /** - * Closure to give to the content reader - * free callback. - */ + /** + * Closure to give to the content reader + * free callback. + */ void *crc_cls; - /** - * How do we get more data? NULL if we are - * given all of the data up front. - */ + /** + * 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". - */ + /** + * NULL if data must not be freed, otherwise + * either user-specified callback or "&free". + */ MHD_ContentReaderFreeCallback crfc; - /** - * Mutex to synchronize access to data/size and - * reference counts. - */ + /** + * Mutex to synchronize access to data/size and + * reference counts. + */ pthread_mutex_t mutex; - /** - * Reference count for this response. Free - * once the counter hits zero. - */ + /** + * Reference count for this response. Free + * once the counter hits zero. + */ unsigned int reference_count; - /** - * Set to -1 if size is not known. - */ + /** + * Set to -1 if size is not known. + */ size_t total_size; - - /** - * Size of data. - */ + + /** + * Size of data. + */ size_t data_size; - /** - * Size of the data buffer. - */ + /** + * Size of the data buffer. + */ size_t data_buffer_size; - - /** - * At what offset in the stream is the - * beginning of data located? - */ + + /** + * At what offset in the stream is the + * beginning of data located? + */ size_t data_start; }; @@ -164,124 +178,124 @@ struct MHD_Response */ enum MHD_CONNECTION_STATE { - /** - * Connection just started (no headers received). - * Waiting for the line with the request type, URL and version. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 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. - */ + /** + * 18: We have sent the response footer. Shutdown or restart. + */ MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1, - /** - * 19: This connection is closed (no more activity - * allowed). - */ + /** + * 19: This connection is closed (no more activity + * allowed). + */ MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 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_CLOSED + 1, - /* + /** * This state indicates the server has send a 'Hello Request' to * the client & a renegotiation of the handshake is in progress. * @@ -329,341 +343,416 @@ 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 { - /** - * This is a linked list. - */ + /** + * This is a linked list. + */ struct MHD_Connection *next; - - /** - * Reference to the MHD_Daemon struct. - */ + + /** + * Reference to the MHD_Daemon struct. + */ struct MHD_Daemon *daemon; - /** - * Linked list of parsed headers. - */ + /** + * Linked list of parsed headers. + */ struct MHD_HTTP_Header *headers_received; - /** - * Response to transmit (initially NULL). - */ + /** + * 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). - */ + /** + * 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 connection. Here is where we - * store it. (MHD does not know or care what it - * is). - */ + /** + * We allow the main application to associate some + * pointer with the connection. Here is where we + * store it. (MHD does not know or care what it + * is). + */ void *client_context; - /** - * Request method. Should be GET/POST/etc. Allocated - * in pool. - */ + /** + * Request method. Should be GET/POST/etc. Allocated + * in pool. + */ char *method; - /** - * Requested URL (everything after "GET" only). Allocated - * in pool. - */ + /** + * Requested URL (everything after "GET" only). Allocated + * in pool. + */ char *url; - /** - * HTTP version string (i.e. http/1.1). Allocated - * in pool. - */ + /** + * 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 - * read_buffer_size (if non-NULL) to allow for - * 0-termination. - */ + /** + * Buffer for reading requests. Allocated + * in pool. Actually one byte larger than + * read_buffer_size (if non-NULL) to allow for + * 0-termination. + */ char *read_buffer; - /** - * Buffer for writing response (headers only). Allocated - * in pool. - */ + /** + * 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 HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED. - */ + /** + * Last incomplete header line during parsing of headers. + * Allocated in pool. Only valid if state is + * either HEADER_PART_RECEIVED or 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 HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED. - */ + /** + * Position after the colon on the last incomplete header + * line during parsing of headers. + * Allocated in pool. Only valid if state is + * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED. + */ char *colon; - /** - * Foreign address (of length addr_len). MALLOCED (not - * in pool!). - */ + /** + * Foreign address (of length addr_len). MALLOCED (not + * in pool!). + */ struct sockaddr_in *addr; - /** - * Thread for this connection (if we are using - * one thread per connection). - */ + /** + * Thread for this connection (if we are using + * one thread per connection). + */ pthread_t 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 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). - */ + /** + * Position where we currently append data in + * read_buffer (last valid position). + */ size_t read_buffer_offset; - /** - * Size of write_buffer (in bytes). - */ + /** + * Size of write_buffer (in bytes). + */ size_t write_buffer_size; - - /** - * Offset where we are with sending from write_buffer. - */ + + /** + * 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?) - */ + /** + * 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? "-1" for unknown. - */ + /** + * How many more bytes of the body do we expect + * to read? "-1" for unknown. + */ size_t remaining_upload_size; - /** - * Current write position in the actual response - * (excluding headers, content only; should be 0 - * while sending headers). - */ + /** + * Current write position in the actual response + * (excluding headers, content only; should be 0 + * while sending headers). + */ size_t response_write_position; - /** - * Position in the 100 CONTINUE message that - * we need to send when receiving http 1.1 requests. - */ + /** + * 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. - */ + /** + * Length of the foreign address. + */ socklen_t addr_len; - /** - * Last time this connection had any activity - * (reading or writing). - */ + /** + * Last time this connection had any activity + * (reading or writing). + */ time_t last_activity; - /** - * Socket for this connection. Set to -1 if - * this connection has died (daemon should clean - * up in that case). - */ + /** + * Socket for this connection. Set to -1 if + * this connection has died (daemon should clean + * up in that case). + */ int 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). - */ + /** + * 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; - /** - * State in the FSM for this connection. - */ + /** + * State in the FSM for this connection. + */ enum MHD_CONNECTION_STATE state; - /** - * HTTP response code. Only valid if response object - * is already set. - */ + /** + * 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. - */ + /** + * 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 sending with chunked encoding? - */ + /** + * Are we sending with chunked encoding? + */ int have_chunked_response; - /** - * 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). - */ + /** + * 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. - */ + /** + * 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. + */ unsigned int current_chunk_size; - /** - * If we are receiving with chunked encoding, where are we currently - * with respect to the current chunk (at what offset / position)? - */ + /** + * If we are receiving with chunked encoding, where are we currently + * with respect to the current chunk (at what offset / position)? + */ unsigned int current_chunk_offset; - - /* handlers used for processing read, write & idle connection operations */ + + /** + * 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 - /* TODO rename as this might be an SSL connection */ + /** + * State required for HTTPS/SSL/TLS support. + */ MHD_gtls_session_t tls_session; #endif }; +/** + * State kept for each MHD daemon. + */ struct MHD_Daemon { - /** - * Callback function for all requests. - */ + /** + * Callback function for all requests. + */ MHD_AccessHandlerCallback default_handler; - - /** - * Closure argument to default_handler. - */ + + /** + * Closure argument to default_handler. + */ void *default_handler_cls; - /** - * Linked list of our current connections. - */ + /** + * Linked list of our current connections. + */ struct MHD_Connection *connections; + /** + * 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 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. + */ void *(*uri_log_callback) (void *cls, const char *uri); + /** + * Closure argument to uri_log_callback. + */ void *uri_log_callback_cls; - /** - * PID of the select thread (if we have internal select) - */ +#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 + + /** + * PID of the select thread (if we have internal select) + */ pthread_t pid; - /** - * Listen socket. - */ + /** + * Listen socket. + */ int socket_fd; - - /** - * Are we shutting down? - */ + + /** + * Are we shutting down? + */ int shutdown; - /** - * Size of the per-connection memory pools. - */ + /** + * Size of the per-connection memory pools. + */ unsigned int pool_size; - /** - * Limit on the number of parallel connections. - */ + /** + * Limit on the number of parallel connections. + */ unsigned int max_connections; - /** - * After how many seconds of inactivity should - * connections time out? Zero for no timeout. - */ + /** + * 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. - */ + /** + * Maximum number of connections per IP, or 0 for + * unlimited. + */ unsigned int per_ip_connection_limit; - /** - * Daemon's options. - */ + /** + * Daemon's options. + */ enum MHD_OPTION options; - /** - * Listen port. - */ + /** + * Listen port. + */ unsigned short port; #if HTTPS_SUPPORT + /** + * What kind of credentials are we offering + * for SSL/TLS? + */ enum MHD_GNUTLS_CredentialsType cred_type; - /* server x509 credintials */ + /** + * Server x509 credentials + */ MHD_gtls_cert_credentials_t x509_cred; - /* cipher priority cache */ + /** + * Cipher priority cache + */ MHD_gnutls_priority_t priority_cache; - /* Diffie-Hellman parameters */ + /** + * Diffie-Hellman parameters + */ MHD_gtls_dh_params_t dh_params; + /** + * Pointer to our SSL/TLS key (in ASCII) in memory. + */ const char *https_mem_key; + /** + * Pointer to our SSL/TLS certificate (in ASCII) in memory. + */ const char *https_mem_cert; #endif }; diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -411,6 +411,21 @@ enum MHD_OPTION * daemon should adhere. */ MHD_OPTION_CIPHER_ALGORITHM = 12, + + /** + * Use the given function for logging error messages. + * This option must be followed by two arguments; the + * first must be a pointer to a function + * of type "void fun(void * arg, const char * fmt, va_list ap)" + * and the second a pointer "void*" which will + * be passed as the "arg" argument to "fun". + * <p> + * Note that MHD will not generate any log messages + * if it was compiled without the "--enable-messages" + * flag being set. + */ + MHD_OPTION_EXTERNAL_LOGGER = 13, + }; /** @@ -910,13 +925,14 @@ MHD_set_connection_value (struct MHD_Connection *connection, * @param key the header to look for * @return NULL if no such item was found */ -const char *MHD_lookup_connection_value (struct MHD_Connection *connection, - enum MHD_ValueKind kind, - const char *key); +const char * +MHD_lookup_connection_value (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + const char *key); /** * Queue a response to be transmitted to the client (as soon as - * possible). + * possible but after MHD_AccessHandlerCallback returns). * * @param connection the connection identifying the client * @param status_code HTTP status code (i.e. 200 for OK)