From ed7d85d6a835bc3528cb66a324dac93af1d3e8bc Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 17 Feb 2018 05:35:04 +0100 Subject: work towards idle handler rewrite' --- src/include/microhttpd2.h | 156 ++++---- src/include/microhttpd_tls.h | 4 + src/lib/connection_call_handlers.c | 715 +++++++++++++++++++++++++++---------- 3 files changed, 630 insertions(+), 245 deletions(-) diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h index 8d89a807..f54d16b2 100644 --- a/src/include/microhttpd2.h +++ b/src/include/microhttpd2.h @@ -333,37 +333,51 @@ struct MHD_Connection; enum MHD_StatusCode { + /* 00000-level status codes indicate return values + the application must act on. */ + /** * Successful operation (not used for logging). */ MHD_SC_OK = 0, /** - * Informational event, MHD started. + * We were asked to return a timeout, but, there is no timeout. */ - MHD_SC_DAEMON_STARTED = 10000, + MHD_SC_NO_TIMEOUT = 1, + + /* 10000-level status codes indicate intermediate + results of some kind. */ + /** - * Informational event, there is no timeout. + * Informational event, MHD started. */ - MHD_SC_NO_TIMEOUT = 10001, + MHD_SC_DAEMON_STARTED = 10000, /** * Informational event, we accepted a connection. */ - MHD_SC_CONNECTION_ACCEPTED = 10002, + MHD_SC_CONNECTION_ACCEPTED = 10001, /** * Informational event, thread processing connection termiantes. */ - MHD_SC_THREAD_TERMINATING = 10003, + MHD_SC_THREAD_TERMINATING = 10002, /** * Informational event, state machine status for a connection. */ - MHD_SC_STATE_MACHINE_STATUS_REPORT = 10004, + MHD_SC_STATE_MACHINE_STATUS_REPORT = 10003, + + /** + * accept() returned transient error. + */ + MHD_SC_ACCEPT_FAILED_EAGAIN = 10004, + /* 20000-level status codes indicate success of some kind. */ + /** * MHD is closing a connection after the client closed it * (perfectly normal end). @@ -375,6 +389,11 @@ enum MHD_StatusCode * logic to generate the response data completed. */ MHD_SC_APPLICATION_DATA_GENERATION_FINISHED = 20001, + + + /* 30000-level status codes indicate transient failures + that might go away if the client tries again. */ + /** * Resource limit in terms of number of parallel connections @@ -382,130 +401,104 @@ enum MHD_StatusCode */ MHD_SC_LIMIT_CONNECTIONS_REACHED = 30000, - /** - * accept() returned transient error. - */ - MHD_SC_ACCEPT_FAILED_EAGAIN = 30001, - /** * We failed to allocate memory for poll() syscall. * (May be transient.) */ - MHD_SC_POLL_MALLOC_FAILURE = 30002, + MHD_SC_POLL_MALLOC_FAILURE = 30001, /** * The operation failed because the respective * daemon is already too deep inside of the shutdown * activity. */ - MHD_SC_DAEMON_ALREADY_SHUTDOWN = 30003, + MHD_SC_DAEMON_ALREADY_SHUTDOWN = 30002, /** * We failed to start a thread. */ - MHD_SC_THREAD_LAUNCH_FAILURE = 30004, + MHD_SC_THREAD_LAUNCH_FAILURE = 30003, /** * The operation failed because we either have no * listen socket or were already quiesced. */ - MHD_SC_DAEMON_ALREADY_QUIESCED = 30005, + MHD_SC_DAEMON_ALREADY_QUIESCED = 30004, /** * The operation failed because client disconnected * faster than we could accept(). */ - MHD_SC_ACCEPT_FAST_DISCONNECT = 30006, + MHD_SC_ACCEPT_FAST_DISCONNECT = 30005, /** * Operating resource limits hit on accept(). */ - MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED = 30007, + MHD_SC_ACCEPT_SYSTEM_LIMIT_REACHED = 30006, /** * Connection was refused by accept policy callback. */ - MHD_SC_ACCEPT_POLICY_REJECTED = 30008, + MHD_SC_ACCEPT_POLICY_REJECTED = 30007, /** * We failed to allocate memory for the connection. * (May be transient.) */ - MHD_SC_CONNECTION_MALLOC_FAILURE = 30009, + MHD_SC_CONNECTION_MALLOC_FAILURE = 30008, /** * We failed to allocate memory for the connection's memory pool. * (May be transient.) */ - MHD_SC_POOL_MALLOC_FAILURE = 30010, + MHD_SC_POOL_MALLOC_FAILURE = 30009, /** * We failed to forward data from a Web socket to the * application to the remote side due to the socket * being closed prematurely. (May be transient.) */ - MHD_SC_UPGRADE_FORWARD_INCOMPLETE = 30011, - - /** - * MHD is closing a connection because it was reset. - */ - MHD_SC_CONNECTION_RESET_CLOSED = 30012, - - /** - * MHD is closing a connection because reading the - * request failed. - */ - MHD_SC_CONNECTION_READ_FAIL_CLOSED = 30013, - - /** - * MHD is closing a connection because writing the response failed. - */ - MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 30014, - - /** - * MHD is closing a connection because the application - * logic to generate the response data failed. - */ - MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED = 30015, + MHD_SC_UPGRADE_FORWARD_INCOMPLETE = 30010, /** * We failed to allocate memory for generatig the response from our * memory pool. Likely the request header was too large to leave * enough room. */ - MHD_SC_CONNECTION_POOL_MALLOC_FAILURE = 30016, + MHD_SC_CONNECTION_POOL_MALLOC_FAILURE = 30011, + /* 40000-level errors are caused by the HTTP client + (or the network) */ /** - * MHD does not support the requested combination of - * EPOLL with thread-per-connection mode. - */ - MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID = 40000, - - /** - * MHD does not support quiescing if ITC was disabled - * and threads are used. + * MHD is closing a connection because parsing the + * request failed. */ - MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 40001, + MHD_SC_CONNECTION_PARSE_FAIL_CLOSED = 40000, /** - * We failed to bind the listen socket. + * MHD is closing a connection because it was reset. */ - MHD_SC_LISTEN_SOCKET_BIND_FAILED = 40002, + MHD_SC_CONNECTION_RESET_CLOSED = 40001, /** - * The application requested an unsupported TLS backend to be used. + * MHD is closing a connection because reading the + * request failed. */ - MHD_SC_TLS_BACKEND_UNSUPPORTED = 40003, + MHD_SC_CONNECTION_READ_FAIL_CLOSED = 40002, /** - * The application requested a TLS cipher suite which is not - * supported by the selected backend. + * MHD is closing a connection because writing the response failed. */ - MHD_SC_TLS_CIPHERS_INVALID = 40004, + MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 40003, + + /* 50000-level errors are because of an error internal + to the MHD logic, possibly including our interaction + with the operating system (but not the application) */ + /** * This build of MHD does not support TLS, but the application * requested TLS. @@ -788,7 +781,46 @@ enum MHD_StatusCode * state machine, we closed the connection. */ MHD_SC_STATEMACHINE_FAILURE_CONNECTION_CLOSED = 50054, - + + + /* 60000-level errors are because the application + logic did something wrong or generated an error. */ + + /** + * MHD does not support the requested combination of + * EPOLL with thread-per-connection mode. + */ + MHD_SC_SYSCALL_THREAD_COMBINATION_INVALID = 60000, + + /** + * MHD does not support quiescing if ITC was disabled + * and threads are used. + */ + MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001, + + /** + * We failed to bind the listen socket. + */ + MHD_SC_LISTEN_SOCKET_BIND_FAILED = 60002, + + /** + * The application requested an unsupported TLS backend to be used. + */ + MHD_SC_TLS_BACKEND_UNSUPPORTED = 60003, + + /** + * The application requested a TLS cipher suite which is not + * supported by the selected backend. + */ + MHD_SC_TLS_CIPHERS_INVALID = 60004, + + /** + * MHD is closing a connection because the application + * logic to generate the response data failed. + */ + MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED = 60005, + + }; diff --git a/src/include/microhttpd_tls.h b/src/include/microhttpd_tls.h index c0a5c66b..85862a45 100644 --- a/src/include/microhttpd_tls.h +++ b/src/include/microhttpd_tls.h @@ -96,6 +96,10 @@ struct MHD_TLS_Plugin (*handshake)(void *cls, struct MHD_TLS_ConnectionState *cs); + + enum MHD_Bool + (*idle_ready)(void *cls, + struct MHD_TLS_ConnectionState *cs); ssize_t (*send)(void *cls, diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c index 1eac9c10..346089a2 100644 --- a/src/lib/connection_call_handlers.c +++ b/src/lib/connection_call_handlers.c @@ -935,48 +935,405 @@ MHD_request_handle_write_ (struct MHD_Request *request) } -#if COMMENTED_OUT_FOR_REWRITE +/** + * Convert @a method to the respective enum value. + * + * @param method the method string to look up enum value for + * @return resulting enum, or generic value for "unknown" + */ +static enum MHD_Method +method_string_to_enum (const char *method) +{ + static const struct { + const char *key; + enum MHD_Method value; + } methods[] = { + { "OPTIONS", MHD_METHOD_OPTIONS }, + { "GET", MHD_METHOD_GET }, + { "HEAD", MHD_METHOD_HEAD }, + { "POST", MHD_METHOD_POST }, + { "PUT", MHD_METHOD_PUT }, + { "DELETE", MHD_METHOD_DELETE }, + { "TRACE", MHD_METHOD_TRACE }, + { "CONNECT", MHD_METHOD_CONNECT }, + { "ACL", MHD_METHOD_ACL }, + { "BASELINE_CONTROL", MHD_METHOD_BASELINE_CONTROL }, + { "BIND", MHD_METHOD_BIND }, + { "CHECKIN", MHD_METHOD_CHECKIN }, + { "CHECKOUT", MHD_METHOD_CHECKOUT }, + { "COPY", MHD_METHOD_COPY }, + { "LABEL", MHD_METHOD_LABEL }, + { "LINK", MHD_METHOD_LINK }, + { "LOCK", MHD_METHOD_LOCK }, + { "MERGE", MHD_METHOD_MERGE }, + { "MKACTIVITY", MHD_METHOD_MKACTIVITY }, + { "MKCOL", MHD_METHOD_MKCOL }, + { "MKREDIRECTREF", MHD_METHOD_MKREDIRECTREF }, + { "MKWORKSPACE", MHD_METHOD_MKWORKSPACE }, + { "MOVE", MHD_METHOD_MOVE }, + { "ORDERPATCH", MHD_METHOD_ORDERPATCH }, + { "PRI", MHD_METHOD_PRI }, + { "PROPFIND", MHD_METHOD_PROPFIND }, + { "PROPPATCH", MHD_METHOD_PROPPATCH }, + { "REBIND", MHD_METHOD_REBIND }, + { "REPORT", MHD_METHOD_REPORT }, + { "SEARCH", MHD_METHOD_SEARCH }, + { "UNBIND", MHD_METHOD_UNBIND }, + { "UNCHECKOUT", MHD_METHOD_UNCHECKOUT }, + { "UNLINK", MHD_METHOD_UNLINK }, + { "UNLOCK", MHD_METHOD_UNLOCK }, + { "UPDATE", MHD_METHOD_UPDATE }, + { "UPDATEDIRECTREF", MHD_METHOD_UPDATEDIRECTREF }, + { "VERSION-CONTROL", MHD_METHOD_VERSION_CONTROL }, + { NULL, MHD_METHOD_UNKNOWN } /* must be last! */ + }; + unsigned int i; + + for (i=0;NULL != methods[i].key;i++) + if (0 == + MHD_str_equal_caseless_ (method, + methods[i].key)) + return methods[i].value; + return MHD_METHOD_UNKNOWN; +} + + +/** + * Parse the first line of the HTTP HEADER. + * + * @param connection the connection (updated) + * @param line the first line, not 0-terminated + * @param line_len length of the first @a line + * @return true if the line is ok, false if it is malformed + */ +static bool +parse_initial_message_line (struct MHD_Request *request, + char *line, + size_t line_len) +{ + struct MHD_Connection *connection = request->connection; + struct MHD_Daemon *daemon = request->daemon; + const char *curi; + char *uri; + char *http_version; + char *args; + unsigned int unused_num_headers; + + if (NULL == (uri = memchr (line, + ' ', + line_len))) + return false; /* serious error */ + uri[0] = '\0'; + request->method_s = line; + request->method = method_string_to_enum (line); + uri++; + /* Skip any spaces. Not required by standard but allow + to be more tolerant. */ + while ( (' ' == uri[0]) && + ( (size_t)(uri - line) < line_len) ) + uri++; + if ((size_t)(uri - line) == line_len) + { + curi = ""; + uri = NULL; + request->version = ""; + args = NULL; + } + else + { + curi = uri; + /* Search from back to accept misformed URI with space */ + http_version = line + line_len - 1; + /* Skip any trailing spaces */ + while ( (' ' == http_version[0]) && + (http_version > uri) ) + http_version--; + /* Find first space in reverse direction */ + while ( (' ' != http_version[0]) && + (http_version > uri) ) + http_version--; + if (http_version > uri) + { + http_version[0] = '\0'; + request->version = http_version + 1; + args = memchr (uri, + '?', + http_version - uri); + } + else + { + request->version = ""; + args = memchr (uri, + '?', + line_len - (uri - line)); + } + } + if (NULL != daemon->uri_log_callback) + { + request->client_aware = true; + request->client_context + = daemon->early_uri_logger_cb (daemon->early_uri_logger_cb_cls, + curi, + request); + } + if (NULL != args) + { + args[0] = '\0'; + args++; + /* note that this call clobbers 'args' */ + MHD_parse_arguments_ (connection, + MHD_GET_ARGUMENT_KIND, + args, + &connection_add_header, + &unused_num_headers); + } + if (NULL != uri) + daemon->unescape_cb (daemon->unescape_cb_cls, + request, + uri); + request->url = curi; + return MHD_YES; +} + + +/** + * Add an entry to the HTTP headers of a request. If this fails, + * transmit an error response (request too big). + * + * @param request the request for which a value should be set + * @param kind kind of the value + * @param key key for the value + * @param value the value itself + * @return false on failure (out of memory), true for success + */ +static bool +connection_add_header (struct MHD_Request *request, + const char *key, + const char *value, + enum MHD_ValueKind kind) +{ + if (MHD_NO == + MHD_request_set_value (request, + kind, + key, + value)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (request->daemon, + _("Not enough memory in pool to allocate header record!\n")); +#endif + transmit_error_response (request->connection, + MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, + REQUEST_TOO_BIG); + return false; + } + return true; +} + + +/** + * We have received (possibly the beginning of) a line in the + * header (or footer). Validate (check for ":") and prepare + * to process. + * + * @param request the request we're processing + * @param line line from the header to process + * @return true on success, false on error (malformed @a line) + */ +static bool +process_header_line (struct MHD_Request *request, + char *line) +{ + struct MHD_Connection *connection = request->connection; + char *colon; + + /* line should be normal header line, find colon */ + colon = strchr (line, ':'); + if (NULL == colon) + { + /* error in header line, die hard */ + CONNECTION_CLOSE_ERROR (connection, + MHD_SC_CONNECTION_PARSE_FAIL_CLOSED, + _("Received malformed line (no colon). Closing connection.\n")); + return false; + } + if (-1 >= request->daemon->strict_for_client) + { + /* check for whitespace before colon, which is not allowed + by RFC 7230 section 3.2.4; we count space ' ' and + tab '\t', but not '\r\n' as those would have ended the line. */ + const char *white; + + white = strchr (line, + (unsigned char) ' '); + if ( (NULL != white) && + (white < colon) ) + { + CONNECTION_CLOSE_ERROR (connection, + MHD_SC_CONNECTION_PARSE_FAIL_CLOSED, + _("Whitespace before colon forbidden by RFC 7230. Closing connection.\n")); + return false; + } + white = strchr (line, + (unsigned char) '\t'); + if ( (NULL != white) && + (white < colon) ) + { + CONNECTION_CLOSE_ERROR (connection, + MHD_SC_CONNECTION_PARSE_FAIL_CLOSED, + _("Tab before colon forbidden by RFC 7230. Closing connection.\n")); + return false; + } + } + /* zero-terminate header */ + colon[0] = '\0'; + colon++; /* advance to value */ + while ( ('\0' != colon[0]) && + ( (' ' == colon[0]) || + ('\t' == colon[0]) ) ) + colon++; + /* we do the actual adding of the connection + header at the beginning of the while + loop since we need to be able to inspect + the *next* header line (in case it starts + with a space...) */ + request->last = line; + request->colon = colon; + return true; +} /** - * This function was created to handle per-connection processing that + * Process a header value that spans multiple lines. + * The previous line(s) are in connection->last. + * + * @param request the request we're processing + * @param line the current input line + * @param kind if the line is complete, add a header + * of the given kind + * @return true if the line was processed successfully + */ +static bool +process_broken_line (struct MHD_Request *request, + char *line, + enum MHD_ValueKind kind) +{ + struct MHD_Connection *connection = request->connection; + char *last; + char *tmp; + size_t last_len; + size_t tmp_len; + + last = request->last; + if ( (' ' == line[0]) || + ('\t' == line[0]) ) + { + /* value was continued on the next line, see + http://www.jmarshall.com/easy/http/ */ + last_len = strlen (last); + /* skip whitespace at start of 2nd line */ + tmp = line; + while ( (' ' == tmp[0]) || + ('\t' == tmp[0]) ) + tmp++; + tmp_len = strlen (tmp); + /* FIXME: we might be able to do this better (faster!), as most + likely 'last' and 'line' should already be adjacent in + memory; however, doing this right gets tricky if we have a + value continued over multiple lines (in which case we need to + record how often we have done this so we can check for + adjacency); also, in the case where these are not adjacent + (not sure how it can happen!), we would want to allocate from + the end of the pool, so as to not destroy the read-buffer's + ability to grow nicely. */ + last = MHD_pool_reallocate (connection->pool, + last, + last_len + 1, + last_len + tmp_len + 1); + if (NULL == last) + { + transmit_error_response (connection, + MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } + memcpy (&last[last_len], + tmp, + tmp_len + 1); + request->last = last; + return MHD_YES; /* possibly more than 2 lines... */ + } + mhd_assert ( (NULL != last) && + (NULL != request->colon) ); + if (! request_add_header (request, + last, + request->colon, + kind)) + { + transmit_error_response (connection, + MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, + REQUEST_TOO_BIG); + return false; + } + /* we still have the current line to deal with... */ + if ('\0' != line[0]) + { + if (! process_header_line (request, + line)) + { + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, + REQUEST_MALFORMED); + return false; + } + } + return true; +} + + +#ifdef REWRITE_IN_PROGRESS + +/** + * This function was created to handle per-request processing that * has to happen even if the socket cannot be read or written to. - * @remark To be called only from thread that process connection's + * @remark To be called only from thread that process request's * recv(), send() and response. * - * @param connection connection to handle - * @return #MHD_YES if we should continue to process the - * connection (not dead yet), #MHD_NO if it died + * @param request the request to handle + * @return true if we should continue to process the + * request (not dead yet), false if it died */ -int -MHD_connection_handle_idle (struct MHD_Connection *connection) +bool +MHD_request_handle_idle (struct MHD_Request *request) { - struct MHD_Daemon *daemon = connection->daemon; + struct MHD_Daemon *daemon = request->daemon; + struct MHD_Connection *connection = request->connection; char *line; size_t line_len; int ret; - connection->in_idle = true; + request->in_idle = true; while (! connection->suspended) { #ifdef HTTPS_SUPPORT - if (MHD_TLS_CONN_NO_TLS != connection->tls_state) - { /* HTTPS connection. */ - if ((MHD_TLS_CONN_INIT <= connection->tls_state) && - (MHD_TLS_CONN_CONNECTED > connection->tls_state)) - break; - } + struct MHD_TLS_Plugin *tls; + + if ( (NULL != (tls = daemon->tls_api)) && + (! tls->idle_ready (tls->cls, + connection->tls_cs)) ) + break; #endif /* HTTPS_SUPPORT */ #if DEBUG_STATES MHD_DLOG (daemon, + MHD_SC_STATE_MACHINE_STATUS_REPORT, _("In function %s handling connection at state: %s\n"), __FUNCTION__, - MHD_state_to_string (connection->state)); + MHD_state_to_string (request->state)); #endif - switch (connection->state) + switch (request->state) { - case MHD_CONNECTION_INIT: - line = get_next_header_line (connection, + case MHD_REQUEST_INIT: + line = get_next_header_line (request, &line_len); /* Check for empty string, as we might want to tolerate 'spurious' empty lines; also @@ -985,34 +1342,37 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) if ( (NULL == line) || (0 == line[0]) ) { - if (MHD_CONNECTION_INIT != connection->state) + if (MHD_REQUEST_INIT != request->state) continue; if (connection->read_closed) { CONNECTION_CLOSE_ERROR (connection, + MHD_SC_CONNECTION_READ_FAIL_CLOSED, NULL); continue; } break; } - if (MHD_NO == parse_initial_message_line (connection, - line, - line_len)) + if (MHD_NO == + parse_initial_message_line (request, + line, + line_len)) CONNECTION_CLOSE_ERROR (connection, NULL); else - connection->state = MHD_CONNECTION_URL_RECEIVED; + request->state = MHD_REQUEST_URL_RECEIVED; continue; - case MHD_CONNECTION_URL_RECEIVED: - line = get_next_header_line (connection, + case MHD_REQUEST_URL_RECEIVED: + line = get_next_header_line (request, NULL); if (NULL == line) { - if (MHD_CONNECTION_URL_RECEIVED != connection->state) + if (MHD_REQUEST_URL_RECEIVED != request->state) continue; if (connection->read_closed) { CONNECTION_CLOSE_ERROR (connection, + MHD_SC_CONNECTION_READ_FAIL_CLOSED, NULL); continue; } @@ -1020,126 +1380,126 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } if (0 == line[0]) { - connection->state = MHD_CONNECTION_HEADERS_RECEIVED; - connection->header_size = (size_t) (line - connection->read_buffer); + request->state = MHD_REQUEST_HEADERS_RECEIVED; + request->header_size = (size_t) (line - request->read_buffer); continue; } - if (MHD_NO == process_header_line (connection, - line)) + if (! process_header_line (request, + line)) { transmit_error_response (connection, MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED); break; } - connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; + request->state = MHD_REQUEST_HEADER_PART_RECEIVED; continue; - case MHD_CONNECTION_HEADER_PART_RECEIVED: - line = get_next_header_line (connection, + case MHD_REQUEST_HEADER_PART_RECEIVED: + line = get_next_header_line (request, NULL); if (NULL == line) { - if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) + if (request->state != MHD_REQUEST_HEADER_PART_RECEIVED) continue; if (connection->read_closed) { CONNECTION_CLOSE_ERROR (connection, + MHD_SC_CONNECTION_READ_FAIL_CLOSED, NULL); continue; } break; } if (MHD_NO == - process_broken_line (connection, + process_broken_line (request, line, MHD_HEADER_KIND)) continue; if (0 == line[0]) { - connection->state = MHD_CONNECTION_HEADERS_RECEIVED; - connection->header_size = (size_t) (line - connection->read_buffer); + request->state = MHD_REQUEST_HEADERS_RECEIVED; + request->header_size = (size_t) (line - request->read_buffer); continue; } continue; - case MHD_CONNECTION_HEADERS_RECEIVED: - parse_connection_headers (connection); - if (MHD_CONNECTION_CLOSED == connection->state) + case MHD_REQUEST_HEADERS_RECEIVED: + parse_request_headers (request); + if (MHD_REQUEST_CLOSED == request->state) continue; - connection->state = MHD_CONNECTION_HEADERS_PROCESSED; + request->state = MHD_REQUEST_HEADERS_PROCESSED; if (connection->suspended) break; continue; - case MHD_CONNECTION_HEADERS_PROCESSED: - call_connection_handler (connection); /* first call */ - if (MHD_CONNECTION_CLOSED == connection->state) + case MHD_REQUEST_HEADERS_PROCESSED: + call_request_handler (request); /* first call */ + if (MHD_REQUEST_CLOSED == request->state) continue; - if (need_100_continue (connection)) + if (need_100_continue (request)) { - connection->state = MHD_CONNECTION_CONTINUE_SENDING; - if (MHD_NO != socket_flush_possible (connection)) + request->state = MHD_REQUEST_CONTINUE_SENDING; + if (socket_flush_possible (connection)) socket_start_extra_buffering (connection); else socket_start_no_buffering (connection); - break; } - if ( (NULL != connection->response) && - ( (MHD_str_equal_caseless_ (connection->method, + if ( (NULL != request->response) && + ( (MHD_str_equal_caseless_ (request->method, MHD_HTTP_METHOD_POST)) || - (MHD_str_equal_caseless_ (connection->method, + (MHD_str_equal_caseless_ (request->method, MHD_HTTP_METHOD_PUT))) ) { /* we refused (no upload allowed!) */ - connection->remaining_upload_size = 0; + request->remaining_upload_size = 0; /* force close, in case client still tries to upload... */ connection->read_closed = true; } - connection->state = (0 == connection->remaining_upload_size) - ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; + request->state = (0 == request->remaining_upload_size) + ? MHD_REQUEST_FOOTERS_RECEIVED : MHD_REQUEST_CONTINUE_SENT; if (connection->suspended) break; continue; - case MHD_CONNECTION_CONTINUE_SENDING: - if (connection->continue_message_write_offset == + case MHD_REQUEST_CONTINUE_SENDING: + if (request->continue_message_write_offset == MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) { - connection->state = MHD_CONNECTION_CONTINUE_SENT; - if (MHD_NO != socket_flush_possible (connection)) - socket_start_no_buffering_flush (connection); + request->state = MHD_REQUEST_CONTINUE_SENT; + if (MHD_NO != socket_flush_possible (request)) + socket_start_no_buffering_flush (request); else - socket_start_normal_buffering (connection); + socket_start_normal_buffering (request); continue; } break; - case MHD_CONNECTION_CONTINUE_SENT: - if (0 != connection->read_buffer_offset) + case MHD_REQUEST_CONTINUE_SENT: + if (0 != request->read_buffer_offset) { - process_request_body (connection); /* loop call */ - if (MHD_CONNECTION_CLOSED == connection->state) + process_request_body (request); /* loop call */ + if (MHD_REQUEST_CLOSED == request->state) continue; } - if ( (0 == connection->remaining_upload_size) || - ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) && - (0 == connection->read_buffer_offset) && - (connection->read_closed) ) ) + if ( (0 == request->remaining_upload_size) || + ( (MHD_SIZE_UNKNOWN == request->remaining_upload_size) && + (0 == request->read_buffer_offset) && + (request->read_closed) ) ) { - if ( (connection->have_chunked_upload) && - (! connection->read_closed) ) - connection->state = MHD_CONNECTION_BODY_RECEIVED; + if ( (request->have_chunked_upload) && + (! request->read_closed) ) + request->state = MHD_REQUEST_BODY_RECEIVED; else - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + request->state = MHD_REQUEST_FOOTERS_RECEIVED; if (connection->suspended) break; continue; } break; - case MHD_CONNECTION_BODY_RECEIVED: - line = get_next_header_line (connection, + case MHD_REQUEST_BODY_RECEIVED: + line = get_next_header_line (request, NULL); if (NULL == line) { - if (connection->state != MHD_CONNECTION_BODY_RECEIVED) + if (request->state != MHD_REQUEST_BODY_RECEIVED) continue; if (connection->read_closed) { @@ -1151,12 +1511,12 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } if (0 == line[0]) { - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + request->state = MHD_REQUEST_FOOTERS_RECEIVED; if (connection->suspended) break; continue; } - if (MHD_NO == process_header_line (connection, + if (MHD_NO == process_header_line (request, line)) { transmit_error_response (connection, @@ -1164,14 +1524,14 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) REQUEST_MALFORMED); break; } - connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; + request->state = MHD_REQUEST_FOOTER_PART_RECEIVED; continue; - case MHD_CONNECTION_FOOTER_PART_RECEIVED: - line = get_next_header_line (connection, + case MHD_REQUEST_FOOTER_PART_RECEIVED: + line = get_next_header_line (request, NULL); if (NULL == line) { - if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) + if (request->state != MHD_REQUEST_FOOTER_PART_RECEIVED) continue; if (connection->read_closed) { @@ -1182,66 +1542,66 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) break; } if (MHD_NO == - process_broken_line (connection, + process_broken_line (request, line, MHD_FOOTER_KIND)) continue; if (0 == line[0]) { - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + request->state = MHD_REQUEST_FOOTERS_RECEIVED; if (connection->suspended) break; continue; } continue; - case MHD_CONNECTION_FOOTERS_RECEIVED: - call_connection_handler (connection); /* "final" call */ - if (connection->state == MHD_CONNECTION_CLOSED) + case MHD_REQUEST_FOOTERS_RECEIVED: + call_request_handler (request); /* "final" call */ + if (request->state == MHD_REQUEST_CLOSED) continue; - if (NULL == connection->response) + if (NULL == request->response) break; /* try again next time */ - if (MHD_NO == build_header_response (connection)) + if (MHD_NO == build_header_response (request)) { /* oops - close! */ CONNECTION_CLOSE_ERROR (connection, _("Closing connection (failed to create response header)\n")); continue; } - connection->state = MHD_CONNECTION_HEADERS_SENDING; + request->state = MHD_REQUEST_HEADERS_SENDING; if (MHD_NO != socket_flush_possible (connection)) socket_start_extra_buffering (connection); else socket_start_no_buffering (connection); break; - case MHD_CONNECTION_HEADERS_SENDING: + case MHD_REQUEST_HEADERS_SENDING: /* no default action */ break; - case MHD_CONNECTION_HEADERS_SENT: + case MHD_REQUEST_HEADERS_SENT: /* Some clients may take some actions right after header receive */ if (MHD_NO != socket_flush_possible (connection)) socket_start_no_buffering_flush (connection); #ifdef UPGRADE_SUPPORT - if (NULL != connection->response->upgrade_handler) + if (NULL != request->response->upgrade_handler) { socket_start_normal_buffering (connection); - connection->state = MHD_CONNECTION_UPGRADE; - /* This connection is "upgraded". Pass socket to application. */ + request->state = MHD_REQUEST_UPGRADE; + /* This request is "upgraded". Pass socket to application. */ if (MHD_YES != - MHD_response_execute_upgrade_ (connection->response, - connection)) + MHD_response_execute_upgrade_ (request->response, + request)) { /* upgrade failed, fail hard */ CONNECTION_CLOSE_ERROR (connection, NULL); continue; } - /* Response is not required anymore for this connection. */ - if (NULL != connection->response) + /* Response is not required anymore for this request. */ + if (NULL != request->response) { - struct MHD_Response * const resp = connection->response; - connection->response = NULL; + struct MHD_Response * const resp = request->response; + request->response = NULL; MHD_destroy_response (resp); } continue; @@ -1252,29 +1612,29 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) else socket_start_normal_buffering (connection); - if (connection->have_chunked_upload) - connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; + if (request->have_chunked_upload) + request->state = MHD_REQUEST_CHUNKED_BODY_UNREADY; else - connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; + request->state = MHD_REQUEST_NORMAL_BODY_UNREADY; continue; - case MHD_CONNECTION_NORMAL_BODY_READY: + case MHD_REQUEST_NORMAL_BODY_READY: /* nothing to do here */ break; - case MHD_CONNECTION_NORMAL_BODY_UNREADY: - if (NULL != connection->response->crc) - MHD_mutex_lock_chk_ (&connection->response->mutex); - if (0 == connection->response->total_size) + case MHD_REQUEST_NORMAL_BODY_UNREADY: + if (NULL != request->response->crc) + MHD_mutex_lock_chk_ (&request->response->mutex); + if (0 == request->response->total_size) { - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); - connection->state = MHD_CONNECTION_BODY_SENT; + if (NULL != request->response->crc) + MHD_mutex_unlock_chk_ (&request->response->mutex); + request->state = MHD_REQUEST_BODY_SENT; continue; } - if (try_ready_normal_body (connection)) + if (try_ready_normal_body (request)) { - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); - connection->state = MHD_CONNECTION_NORMAL_BODY_READY; + if (NULL != request->response->crc) + MHD_mutex_unlock_chk_ (&request->response->mutex); + request->state = MHD_REQUEST_NORMAL_BODY_READY; /* Buffering for flushable socket was already enabled*/ if (MHD_NO == socket_flush_possible (connection)) socket_start_no_buffering (connection); @@ -1283,26 +1643,26 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) /* mutex was already unlocked by "try_ready_normal_body */ /* not ready, no socket action */ break; - case MHD_CONNECTION_CHUNKED_BODY_READY: + case MHD_REQUEST_CHUNKED_BODY_READY: /* nothing to do here */ break; - case MHD_CONNECTION_CHUNKED_BODY_UNREADY: - if (NULL != connection->response->crc) - MHD_mutex_lock_chk_ (&connection->response->mutex); - if ( (0 == connection->response->total_size) || - (connection->response_write_position == - connection->response->total_size) ) + case MHD_REQUEST_CHUNKED_BODY_UNREADY: + if (NULL != request->response->crc) + MHD_mutex_lock_chk_ (&request->response->mutex); + if ( (0 == request->response->total_size) || + (request->response_write_position == + request->response->total_size) ) { - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); - connection->state = MHD_CONNECTION_BODY_SENT; + if (NULL != request->response->crc) + MHD_mutex_unlock_chk_ (&request->response->mutex); + request->state = MHD_REQUEST_BODY_SENT; continue; } - if (try_ready_chunked_body (connection)) + if (try_ready_chunked_body (request)) { - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); - connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; + if (NULL != request->response->crc) + MHD_mutex_unlock_chk_ (&request->response->mutex); + request->state = MHD_REQUEST_CHUNKED_BODY_READY; /* Buffering for flushable socket was already enabled */ if (MHD_NO == socket_flush_possible (connection)) socket_start_no_buffering (connection); @@ -1310,31 +1670,31 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) } /* mutex was already unlocked by try_ready_chunked_body */ break; - case MHD_CONNECTION_BODY_SENT: - if (MHD_NO == build_header_response (connection)) + case MHD_REQUEST_BODY_SENT: + if (MHD_NO == build_header_response (request)) { /* oops - close! */ CONNECTION_CLOSE_ERROR (connection, _("Closing connection (failed to create response header)\n")); continue; } - if ( (! connection->have_chunked_upload) || - (connection->write_buffer_send_offset == - connection->write_buffer_append_offset) ) - connection->state = MHD_CONNECTION_FOOTERS_SENT; + if ( (! request->have_chunked_upload) || + (request->write_buffer_send_offset == + request->write_buffer_append_offset) ) + request->state = MHD_REQUEST_FOOTERS_SENT; else - connection->state = MHD_CONNECTION_FOOTERS_SENDING; + request->state = MHD_REQUEST_FOOTERS_SENDING; continue; - case MHD_CONNECTION_FOOTERS_SENDING: + case MHD_REQUEST_FOOTERS_SENDING: /* no default action */ break; - case MHD_CONNECTION_FOOTERS_SENT: - if (MHD_HTTP_PROCESSING == connection->responseCode) + case MHD_REQUEST_FOOTERS_SENT: + if (MHD_HTTP_PROCESSING == request->responseCode) { /* After this type of response, we allow sending another! */ - connection->state = MHD_CONNECTION_HEADERS_PROCESSED; - MHD_destroy_response (connection->response); - connection->response = NULL; + request->state = MHD_REQUEST_HEADERS_PROCESSED; + MHD_destroy_response (request->response); + request->response = NULL; /* FIXME: maybe partially reset memory pool? */ continue; } @@ -1343,7 +1703,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) else socket_start_normal_buffering (connection); - MHD_destroy_response (connection->response); + MHD_destroy_response (request->response); connection->response = NULL; if ( (NULL != daemon->notify_completed) && (connection->client_aware) ) @@ -1354,7 +1714,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) &connection->client_context, MHD_REQUEST_TERMINATED_COMPLETED_OK); } - if ( (MHD_CONN_USE_KEEPALIVE != connection->keepalive) || + if ( (MHD_CONN_USE_KEEPALIVE != request->keepalive) || (connection->read_closed) ) { /* have to close for some reason */ @@ -1362,55 +1722,44 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) MHD_REQUEST_TERMINATED_COMPLETED_OK); MHD_pool_destroy (connection->pool); connection->pool = NULL; - connection->read_buffer = NULL; - connection->read_buffer_size = 0; - connection->read_buffer_offset = 0; + request->read_buffer = NULL; + request->read_buffer_size = 0; + request->read_buffer_offset = 0; } else { /* can try to keep-alive */ if (MHD_NO != socket_flush_possible (connection)) socket_start_normal_buffering (connection); - connection->version = NULL; - connection->state = MHD_CONNECTION_INIT; - connection->last = NULL; - connection->colon = NULL; - connection->header_size = 0; - connection->keepalive = MHD_CONN_KEEPALIVE_UNKOWN; + request->version = NULL; + request->state = MHD_REQUEST_INIT; + request->last = NULL; + request->colon = NULL; + request->header_size = 0; + request->keepalive = MHD_CONN_KEEPALIVE_UNKOWN; /* Reset the read buffer to the starting size, preserving the bytes we have already read. */ - connection->read_buffer + request->read_buffer = MHD_pool_reset (connection->pool, - connection->read_buffer, - connection->read_buffer_offset, - connection->daemon->pool_size / 2); - connection->read_buffer_size - = connection->daemon->pool_size / 2; + request->read_buffer, + request->read_buffer_offset, + daemon->pool_size / 2); + request->read_buffer_size + = daemon->pool_size / 2; } - connection->client_aware = false; - connection->client_context = NULL; - connection->continue_message_write_offset = 0; - connection->responseCode = 0; - connection->headers_received = NULL; - connection->headers_received_tail = NULL; - connection->response_write_position = 0; - connection->have_chunked_upload = false; - connection->current_chunk_size = 0; - connection->current_chunk_offset = 0; - connection->method = NULL; - connection->url = NULL; - connection->write_buffer = NULL; - connection->write_buffer_size = 0; - connection->write_buffer_send_offset = 0; - connection->write_buffer_append_offset = 0; + memset (&request, + 0, + sizeof (struct MHD_Request)); + request->daemon = daemon; + request->connection = connection; continue; - case MHD_CONNECTION_CLOSED: + case MHD_REQUEST_CLOSED: cleanup_connection (connection); - connection->in_idle = false; + request->in_idle = false; return MHD_NO; #ifdef UPGRADE_SUPPORT - case MHD_CONNECTION_UPGRADE: - connection->in_idle = false; + case MHD_REQUEST_UPGRADE: + request->in_idle = false; return MHD_YES; /* keep open */ #endif /* UPGRADE_SUPPORT */ default: @@ -1428,7 +1777,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) { MHD_connection_close_ (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); - connection->in_idle = false; + request->in_idle = false; return MHD_YES; } } @@ -1441,7 +1790,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) ret = MHD_connection_epoll_update_ (connection); } #endif /* EPOLL_SUPPORT */ - connection->in_idle = false; + request->in_idle = false; return ret; } -- cgit v1.2.3