libmicrohttpd

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

commit 2133a6d6b4c35b11a485404b84fcd946dcc96a19
parent d44a18700cc184027d4a283dc212982c6c112679
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 15 Sep 2019 12:52:14 +0200

fix-warnings

Diffstat:
Msrc/microhttpd/connection.c | 4283++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 2161 insertions(+), 2122 deletions(-)

diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -68,7 +68,8 @@ * minimal. */ #ifdef HAVE_MESSAGES -#define REQUEST_TOO_BIG "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>" +#define REQUEST_TOO_BIG \ + "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>" #else #define REQUEST_TOO_BIG "" #endif @@ -81,7 +82,8 @@ * minimal. */ #ifdef HAVE_MESSAGES -#define REQUEST_LACKS_HOST "<html><head><title>&quot;Host:&quot; header required</title></head><body>In HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 request lacked such a header.</body></html>" +#define REQUEST_LACKS_HOST \ + "<html><head><title>&quot;Host:&quot; header required</title></head><body>In HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 request lacked such a header.</body></html>" #else #define REQUEST_LACKS_HOST "" #endif @@ -94,7 +96,8 @@ * minimal. */ #ifdef HAVE_MESSAGES -#define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" +#define REQUEST_MALFORMED \ + "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" #else #define REQUEST_MALFORMED "" #endif @@ -106,7 +109,8 @@ * minimal. */ #ifdef HAVE_MESSAGES -#define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Please ask the developer of this Web server to carefully read the GNU libmicrohttpd documentation about connection management and blocking.</body></html>" +#define INTERNAL_ERROR \ + "<html><head><title>Internal server error</title></head><body>Please ask the developer of this Web server to carefully read the GNU libmicrohttpd documentation about connection management and blocking.</body></html>" #else #define INTERNAL_ERROR "" #endif @@ -157,17 +161,18 @@ MHD_conn_init_static_ (void) #ifdef SF_FLAGS long sys_page_size = sysconf (_SC_PAGESIZE); if (0 > sys_page_size) - { /* Failed to get page size. */ - freebsd_sendfile_flags_ = SF_NODISKIO; - freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO; - } + { /* Failed to get page size. */ + freebsd_sendfile_flags_ = SF_NODISKIO; + freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO; + } else - { - freebsd_sendfile_flags_ = - SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO); - freebsd_sendfile_flags_thd_p_c_ = - SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size), SF_NODISKIO); - } + { + freebsd_sendfile_flags_ = + SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_ / sys_page_size), SF_NODISKIO); + freebsd_sendfile_flags_thd_p_c_ = + SF_FLAGS ((uint16_t) (MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size), + SF_NODISKIO); + } #endif /* SF_FLAGS */ } #endif /* HAVE_FREEBSD_SENDFILE */ @@ -189,9 +194,9 @@ recv_param_adapter (struct MHD_Connection *connection, if ( (MHD_INVALID_SOCKET == connection->socket_fd) || (MHD_CONNECTION_CLOSED == connection->state) ) - { - return MHD_ERR_NOTCONN_; - } + { + return MHD_ERR_NOTCONN_; + } if (i > MHD_SCKT_SEND_MAX_SIZE_) i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ @@ -199,25 +204,25 @@ recv_param_adapter (struct MHD_Connection *connection, other, i); if (0 > ret) + { + const int err = MHD_socket_get_error_ (); + if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) { - const int err = MHD_socket_get_error_ (); - if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) - { #ifdef EPOLL_SUPPORT - /* Got EAGAIN --- no longer read-ready */ - connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; + /* Got EAGAIN --- no longer read-ready */ + connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; #endif /* EPOLL_SUPPORT */ - return MHD_ERR_AGAIN_; - } - if (MHD_SCKT_ERR_IS_EINTR_ (err)) - return MHD_ERR_AGAIN_; - if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) - return MHD_ERR_CONNRESET_; - /* Treat any other error as hard error. */ - return MHD_ERR_NOTCONN_; + return MHD_ERR_AGAIN_; } + if (MHD_SCKT_ERR_IS_EINTR_ (err)) + return MHD_ERR_AGAIN_; + if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) + return MHD_ERR_CONNRESET_; + /* Treat any other error as hard error. */ + return MHD_ERR_NOTCONN_; + } #ifdef EPOLL_SUPPORT - else if (i > (size_t)ret) + else if (i > (size_t) ret) connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; #endif /* EPOLL_SUPPORT */ return ret; @@ -242,9 +247,9 @@ send_param_adapter (struct MHD_Connection *connection, if ( (MHD_INVALID_SOCKET == connection->socket_fd) || (MHD_CONNECTION_CLOSED == connection->state) ) - { - return MHD_ERR_NOTCONN_; - } + { + return MHD_ERR_NOTCONN_; + } if (i > MHD_SCKT_SEND_MAX_SIZE_) i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */ @@ -252,26 +257,26 @@ send_param_adapter (struct MHD_Connection *connection, other, i); if (0 > ret) - { - const int err = MHD_socket_get_error_(); + { + const int err = MHD_socket_get_error_ (); - if (MHD_SCKT_ERR_IS_EAGAIN_(err)) - { + if (MHD_SCKT_ERR_IS_EAGAIN_ (err)) + { #ifdef EPOLL_SUPPORT - /* EAGAIN --- no longer write-ready */ - connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; + /* EAGAIN --- no longer write-ready */ + connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; #endif /* EPOLL_SUPPORT */ - return MHD_ERR_AGAIN_; - } - if (MHD_SCKT_ERR_IS_EINTR_ (err)) - return MHD_ERR_AGAIN_; - if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) - return MHD_ERR_CONNRESET_; - /* Treat any other error as hard error. */ - return MHD_ERR_NOTCONN_; + return MHD_ERR_AGAIN_; } + if (MHD_SCKT_ERR_IS_EINTR_ (err)) + return MHD_ERR_AGAIN_; + if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) + return MHD_ERR_CONNRESET_; + /* Treat any other error as hard error. */ + return MHD_ERR_NOTCONN_; + } #ifdef EPOLL_SUPPORT - else if (i > (size_t)ret) + else if (i > (size_t) ret) connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; #endif /* EPOLL_SUPPORT */ return ret; @@ -298,9 +303,9 @@ send_param_adapter (struct MHD_Connection *connection, * @return true if force push is possible, false otherwise */ _MHD_static_inline bool -socket_flush_possible(struct MHD_Connection *connection) +socket_flush_possible (struct MHD_Connection *connection) { - (void)connection; /* Mute compiler warning. */ + (void) connection; /* Mute compiler warning. */ #if defined(TCP_CORK) || defined(TCP_PUSH) return true; #else /* !TCP_CORK && !TCP_PUSH */ @@ -310,20 +315,6 @@ socket_flush_possible(struct MHD_Connection *connection) /** - * Activate extra buffering mode on connection socket to prevent - * sending of partial packets. - * - * @param connection connection to be processed - * @return true on success, false otherwise - */ -_MHD_static_inline bool -socket_start_extra_buffering (struct MHD_Connection *connection) -{ - mhd_assert(NULL != connection); -} - - -/** * Activate no buffering mode (no delay sending) on connection socket * and push to client data pending in socket buffer. * @@ -333,20 +324,20 @@ socket_start_extra_buffering (struct MHD_Connection *connection) _MHD_static_inline bool socket_start_no_buffering_flush (struct MHD_Connection *connection) { - bool res; -#if defined(TCP_NOPUSH) && !defined(TCP_CORK) + bool res = false; +#if defined(TCP_NOPUSH) && ! defined(TCP_CORK) const int dummy = 0; #endif /* !TCP_CORK */ -#if defined(__FreeBSD__) && __FreeBSD__+0 >= 9 +#if defined(__FreeBSD__) && __FreeBSD__ + 0 >= 9 /* FreeBSD do not need zero-send for flushing starting from version 9 */ -#elif defined(TCP_NOPUSH) && !defined(TCP_CORK) +#elif defined(TCP_NOPUSH) && ! defined(TCP_CORK) /* Force flush data with zero send otherwise Darwin and some BSD systems will add 5 seconds delay. Not required with TCP_CORK as switching off TCP_CORK always flushes socket buffer. */ res = (0 <= MHD_send_ (connection->socket_fd, - &dummy, - 0)) && res; + &dummy, + 0)) && res; #endif /* TCP_NOPUSH && !TCP_CORK*/ return res; } @@ -378,15 +369,15 @@ MHD_get_connection_values (struct MHD_Connection *connection, ret = 0; for (pos = connection->headers_received; NULL != pos; pos = pos->next) if (0 != (pos->kind & kind)) - { - ret++; - if ( (NULL != iterator) && - (MHD_YES != iterator (iterator_cls, - pos->kind, - pos->header, - pos->value)) ) - return ret; - } + { + ret++; + if ( (NULL != iterator) && + (MHD_YES != iterator (iterator_cls, + pos->kind, + pos->header, + pos->value)) ) + return ret; + } return ret; } @@ -418,23 +409,23 @@ MHD_get_connection_values_n (struct MHD_Connection *connection, if (NULL == iterator) for (pos = connection->headers_received; NULL != pos; pos = pos->next) - { - if (kind == pos->kind) - ret++; - } + { + if (kind == pos->kind) + ret++; + } else for (pos = connection->headers_received; NULL != pos; pos = pos->next) if (kind == pos->kind) - { - ret++; - if (MHD_NO == iterator (iterator_cls, - pos->kind, - pos->header, - pos->header_size, - pos->value, - pos->value_size)) - return ret; - } + { + ret++; + if (MHD_NO == iterator (iterator_cls, + pos->kind, + pos->header, + pos->header_size, + pos->value, + pos->value_size)) + return ret; + } return ret; } @@ -479,15 +470,15 @@ MHD_set_connection_value_n_nocheck_ (struct MHD_Connection *connection, pos->next = NULL; /* append 'pos' to the linked list of headers */ if (NULL == connection->headers_received_tail) - { - connection->headers_received = pos; - connection->headers_received_tail = pos; - } + { + connection->headers_received = pos; + connection->headers_received_tail = pos; + } else - { - connection->headers_received_tail->next = pos; - connection->headers_received_tail = pos; - } + { + connection->headers_received_tail->next = pos; + connection->headers_received_tail = pos; + } return MHD_YES; } @@ -526,8 +517,8 @@ MHD_set_connection_value_n (struct MHD_Connection *connection, size_t value_size) { if ( (MHD_GET_ARGUMENT_KIND != kind) && - ( ((key ? strlen(key) : 0) != key_size) || - ((value ? strlen(value) : 0) != value_size) ) ) + ( ((key ? strlen (key) : 0) != key_size) || + ((value ? strlen (value) : 0) != value_size) ) ) return MHD_NO; /* binary zero is allowed only in GET arguments */ return MHD_set_connection_value_n_nocheck_ (connection, @@ -604,7 +595,7 @@ MHD_lookup_connection_value (struct MHD_Connection *connection, (void) MHD_lookup_connection_value_n (connection, kind, key, - (NULL == key) ? 0 : strlen(key), + (NULL == key) ? 0 : strlen (key), &value, NULL); return value; @@ -644,27 +635,27 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection, return MHD_NO; if (NULL == key) + { + for (pos = connection->headers_received; NULL != pos; pos = pos->next) { - for (pos = connection->headers_received; NULL != pos; pos = pos->next) - { - if ( (0 != (kind & pos->kind)) && - (NULL == pos->header) ) - break; - } + if ( (0 != (kind & pos->kind)) && + (NULL == pos->header) ) + break; } + } else + { + for (pos = connection->headers_received; NULL != pos; pos = pos->next) { - for (pos = connection->headers_received; NULL != pos; pos = pos->next) - { - if ( (0 != (kind & pos->kind)) && - (key_size == pos->header_size) && - ( (key == pos->header) || - (MHD_str_equal_caseless_bin_n_ (key, - pos->header, - key_size) ) ) ) - break; - } + if ( (0 != (kind & pos->kind)) && + (key_size == pos->header_size) && + ( (key == pos->header) || + (MHD_str_equal_caseless_bin_n_ (key, + pos->header, + key_size) ) ) ) + break; } + } if (NULL == pos) return MHD_NO; @@ -696,27 +687,30 @@ MHD_lookup_connection_value_n (struct MHD_Connection *connection, */ static bool MHD_lookup_header_token_ci (const struct MHD_Connection *connection, - const char *header, - size_t header_len, - const char *token, - size_t token_len) + const char *header, + size_t header_len, + const char *token, + size_t token_len) { struct MHD_HTTP_Header *pos; - if (NULL == connection || NULL == header || 0 == header[0] || NULL == token || 0 == token[0]) + if ((NULL == connection)||(NULL == header)||(0 == header[0])||(NULL == + token) ||(0 == + token + [0]) ) return false; for (pos = connection->headers_received; NULL != pos; pos = pos->next) - { - if ((0 != (pos->kind & MHD_HEADER_KIND)) && - (header_len == pos->header_size) && - ( (header == pos->header) || - (MHD_str_equal_caseless_bin_n_(header, - pos->header, - header_len)) ) && - (MHD_str_has_token_caseless_ (pos->value, token, token_len))) - return true; - } + { + if ((0 != (pos->kind & MHD_HEADER_KIND)) && + (header_len == pos->header_size) && + ( (header == pos->header) || + (MHD_str_equal_caseless_bin_n_ (header, + pos->header, + header_len)) ) && + (MHD_str_has_token_caseless_ (pos->value, token, token_len))) + return true; + } return false; } @@ -733,8 +727,8 @@ MHD_lookup_header_token_ci (const struct MHD_Connection *connection, * false otherwise */ #define MHD_lookup_header_s_token_ci(c,h,tkn) \ - MHD_lookup_header_token_ci((c),(h),MHD_STATICSTR_LEN_(h),\ - (tkn),MHD_STATICSTR_LEN_(tkn)) + MHD_lookup_header_token_ci ((c),(h),MHD_STATICSTR_LEN_ (h), \ + (tkn),MHD_STATICSTR_LEN_ (tkn)) /** @@ -750,19 +744,20 @@ need_100_continue (struct MHD_Connection *connection) const char *expect; return ( (NULL == connection->response) && - (NULL != connection->version) && - (MHD_str_equal_caseless_(connection->version, - MHD_HTTP_VERSION_1_1)) && + (NULL != connection->version) && + (MHD_str_equal_caseless_ (connection->version, + MHD_HTTP_VERSION_1_1)) && (MHD_NO != MHD_lookup_connection_value_n (connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_EXPECT, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_EXPECT), + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_EXPECT), &expect, NULL)) && - (MHD_str_equal_caseless_(expect, - "100-continue")) && - (connection->continue_message_write_offset < - MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) ); + (MHD_str_equal_caseless_ (expect, + "100-continue")) && + (connection->continue_message_write_offset < + MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) ); } @@ -780,24 +775,24 @@ MHD_connection_mark_closed_ (struct MHD_Connection *connection) connection->state = MHD_CONNECTION_CLOSED; connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; if (0 == (daemon->options & MHD_USE_TURBO)) - { + { #ifdef HTTPS_SUPPORT - /* For TLS connection use shutdown of TLS layer - * and do not shutdown TCP socket. This give more - * chances to send TLS closure data to remote side. - * Closure of TLS layer will be interpreted by - * remote side as end of transmission. */ - if (0 != (daemon->options & MHD_USE_TLS)) - { - if (! MHD_tls_connection_shutdown(connection)) - shutdown (connection->socket_fd, - SHUT_WR); - } - else /* Combined with next 'shutdown()'. */ -#endif /* HTTPS_SUPPORT */ - shutdown (connection->socket_fd, - SHUT_WR); + /* For TLS connection use shutdown of TLS layer + * and do not shutdown TCP socket. This give more + * chances to send TLS closure data to remote side. + * Closure of TLS layer will be interpreted by + * remote side as end of transmission. */ + if (0 != (daemon->options & MHD_USE_TLS)) + { + if (! MHD_tls_connection_shutdown (connection)) + shutdown (connection->socket_fd, + SHUT_WR); } + else /* Combined with next 'shutdown()'. */ +#endif /* HTTPS_SUPPORT */ + shutdown (connection->socket_fd, + SHUT_WR); + } } @@ -819,16 +814,16 @@ MHD_connection_close_ (struct MHD_Connection *connection, MHD_connection_mark_closed_ (connection); if (NULL != resp) - { - connection->response = NULL; - MHD_destroy_response (resp); - } + { + connection->response = NULL; + MHD_destroy_response (resp); + } if ( (NULL != daemon->notify_completed) && (connection->client_aware) ) daemon->notify_completed (daemon->notify_completed_cls, - connection, - &connection->client_context, - termination_code); + connection, + &connection->client_context, + termination_code); connection->client_aware = false; } @@ -863,33 +858,33 @@ MHD_connection_finish_forward_ (struct MHD_Connection *connection) EPOLL_CTL_DEL, connection->socket_fd, NULL)) ) - { - MHD_PANIC (_("Failed to remove FD from epoll set\n")); - } + { + MHD_PANIC (_ ("Failed to remove FD from epoll set\n")); + } if (urh->in_eready_list) - { - EDLL_remove (daemon->eready_urh_head, - daemon->eready_urh_tail, - urh); - urh->in_eready_list = false; - } + { + EDLL_remove (daemon->eready_urh_head, + daemon->eready_urh_tail, + urh); + urh->in_eready_list = false; + } #endif /* EPOLL_SUPPORT */ if (MHD_INVALID_SOCKET != urh->mhd.socket) - { + { #if EPOLL_SUPPORT - if ( (0 != (daemon->options & MHD_USE_EPOLL)) && - (0 != epoll_ctl (daemon->epoll_upgrade_fd, - EPOLL_CTL_DEL, - urh->mhd.socket, - NULL)) ) - { - MHD_PANIC (_("Failed to remove FD from epoll set\n")); - } -#endif /* EPOLL_SUPPORT */ - /* Reflect remote disconnect to application by breaking - * socketpair connection. */ - shutdown (urh->mhd.socket, SHUT_RDWR); + if ( (0 != (daemon->options & MHD_USE_EPOLL)) && + (0 != epoll_ctl (daemon->epoll_upgrade_fd, + EPOLL_CTL_DEL, + urh->mhd.socket, + NULL)) ) + { + MHD_PANIC (_ ("Failed to remove FD from epoll set\n")); } +#endif /* EPOLL_SUPPORT */ + /* Reflect remote disconnect to application by breaking + * socketpair connection. */ + shutdown (urh->mhd.socket, SHUT_RDWR); + } /* Socketpair sockets will remain open as they will be * used with MHD_UPGRADE_ACTION_CLOSE. They will be * closed by MHD_cleanup_upgraded_connection_() during @@ -908,14 +903,14 @@ MHD_connection_finish_forward_ (struct MHD_Connection *connection) */ static void connection_close_error (struct MHD_Connection *connection, - const char *emsg) + const char *emsg) { #ifdef HAVE_MESSAGES if (NULL != emsg) MHD_DLOG (connection->daemon, emsg); #else /* ! HAVE_MESSAGES */ - (void)emsg; /* Mute compiler warning. */ + (void) emsg; /* Mute compiler warning. */ #endif /* ! HAVE_MESSAGES */ MHD_connection_close_ (connection, MHD_REQUEST_TERMINATED_WITH_ERROR); @@ -958,50 +953,51 @@ try_ready_normal_body (struct MHD_Connection *connection) (connection->response_write_position == response->total_size) ) return MHD_YES; /* 0-byte response is always ready */ if ( (response->data_start <= - connection->response_write_position) && + connection->response_write_position) && (response->data_size + response->data_start > - connection->response_write_position) ) + connection->response_write_position) ) return MHD_YES; /* response already ready */ #if defined(_MHD_HAVE_SENDFILE) if (MHD_resp_sender_sendfile == connection->resp_sender) - { - /* will use sendfile, no need to bother response crc */ - return MHD_YES; - } + { + /* will use sendfile, no need to bother response crc */ + return MHD_YES; + } #endif /* _MHD_HAVE_SENDFILE */ ret = response->crc (response->crc_cls, connection->response_write_position, response->data, - (size_t) MHD_MIN ((uint64_t)response->data_buffer_size, - response->total_size - - connection->response_write_position)); + (size_t) MHD_MIN ((uint64_t) response->data_buffer_size, + response->total_size + - connection->response_write_position)); if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || (((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) ) - { - /* either error or http 1.0 transfer, close socket! */ - response->total_size = connection->response_write_position; + { + /* either error or http 1.0 transfer, close socket! */ + response->total_size = connection->response_write_position; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_ (&response->mutex); + MHD_mutex_unlock_chk_ (&response->mutex); #endif - if ( ((ssize_t)MHD_CONTENT_READER_END_OF_STREAM) == ret) - MHD_connection_close_ (connection, - MHD_REQUEST_TERMINATED_COMPLETED_OK); - else - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (application reported error generating data)\n")); - return MHD_NO; - } + if ( ((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) + MHD_connection_close_ (connection, + MHD_REQUEST_TERMINATED_COMPLETED_OK); + else + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (application reported error generating data)\n")); + return MHD_NO; + } response->data_start = connection->response_write_position; response->data_size = ret; if (0 == ret) - { - connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; + { + connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_ (&response->mutex); + MHD_mutex_unlock_chk_ (&response->mutex); #endif - return MHD_NO; - } + return MHD_NO; + } return MHD_YES; } @@ -1027,95 +1023,96 @@ try_ready_chunked_body (struct MHD_Connection *connection) if (NULL == response->crc) return MHD_YES; if (0 == connection->write_buffer_size) - { - size_t size; + { + size_t size; - size = MHD_pool_get_free (connection->pool); - if (size < 128) - { + size = MHD_pool_get_free (connection->pool); + if (size < 128) + { #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_ (&response->mutex); + MHD_mutex_unlock_chk_ (&response->mutex); #endif - /* not enough memory */ - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (out of memory)\n")); - return MHD_NO; - } - if ( (2 * (0xFFFFFF + sizeof(cbuf) + 2)) < size) - size = 2 * (0xFFFFFF + sizeof(cbuf) + 2); - connection->write_buffer = MHD_pool_allocate (connection->pool, - size, - false); - mhd_assert (NULL != connection->write_buffer); - connection->write_buffer_size = size; + /* not enough memory */ + CONNECTION_CLOSE_ERROR (connection, + _ ("Closing connection (out of memory)\n")); + return MHD_NO; } + if ( (2 * (0xFFFFFF + sizeof(cbuf) + 2)) < size) + size = 2 * (0xFFFFFF + sizeof(cbuf) + 2); + connection->write_buffer = MHD_pool_allocate (connection->pool, + size, + false); + mhd_assert (NULL != connection->write_buffer); + connection->write_buffer_size = size; + } if (0 == response->total_size) ret = 0; /* response must be empty, don't bother calling crc */ else if ( (response->data_start <= - connection->response_write_position) && - (response->data_start + response->data_size > - connection->response_write_position) ) - { - /* difference between response_write_position and data_start is less - than data_size which is size_t type, no need to check for overflow */ - const size_t data_write_offset - = (size_t)(connection->response_write_position - response->data_start); - /* buffer already ready, use what is there for the chunk */ - ret = response->data_size - data_write_offset; - if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2 ) - ret = connection->write_buffer_size - sizeof (cbuf) - 2; - memcpy (&connection->write_buffer[sizeof (cbuf)], - &response->data[data_write_offset], - ret); - } + connection->response_write_position) && + (response->data_start + response->data_size > + connection->response_write_position) ) + { + /* difference between response_write_position and data_start is less + than data_size which is size_t type, no need to check for overflow */ + const size_t data_write_offset + = (size_t) (connection->response_write_position - response->data_start); + /* buffer already ready, use what is there for the chunk */ + ret = response->data_size - data_write_offset; + if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2 ) + ret = connection->write_buffer_size - sizeof (cbuf) - 2; + memcpy (&connection->write_buffer[sizeof (cbuf)], + &response->data[data_write_offset], + ret); + } else - { - /* buffer not in range, try to fill it */ - ret = response->crc (response->crc_cls, - connection->response_write_position, - &connection->write_buffer[sizeof (cbuf)], - connection->write_buffer_size - sizeof (cbuf) - 2); - } + { + /* buffer not in range, try to fill it */ + ret = response->crc (response->crc_cls, + connection->response_write_position, + &connection->write_buffer[sizeof (cbuf)], + connection->write_buffer_size - sizeof (cbuf) - 2); + } if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret) - { - /* error, close socket! */ - response->total_size = connection->response_write_position; + { + /* error, close socket! */ + response->total_size = connection->response_write_position; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_ (&response->mutex); + MHD_mutex_unlock_chk_ (&response->mutex); #endif - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (application error generating response)\n")); - return MHD_NO; - } + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (application error generating response)\n")); + return MHD_NO; + } if ( (((ssize_t) MHD_CONTENT_READER_END_OF_STREAM) == ret) || (0 == response->total_size) ) - { - /* end of message, signal other side! */ - memcpy (connection->write_buffer, - "0\r\n", - 3); - connection->write_buffer_append_offset = 3; - connection->write_buffer_send_offset = 0; - response->total_size = connection->response_write_position; - return MHD_YES; - } + { + /* end of message, signal other side! */ + memcpy (connection->write_buffer, + "0\r\n", + 3); + connection->write_buffer_append_offset = 3; + connection->write_buffer_send_offset = 0; + response->total_size = connection->response_write_position; + return MHD_YES; + } if (0 == ret) - { - connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; + { + connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_ (&response->mutex); + MHD_mutex_unlock_chk_ (&response->mutex); #endif - return MHD_NO; - } + return MHD_NO; + } if (ret > 0xFFFFFF) ret = 0xFFFFFF; - cblen = MHD_snprintf_(cbuf, - sizeof (cbuf), - "%X\r\n", - (unsigned int) ret); - mhd_assert(cblen > 0); - mhd_assert((size_t)cblen < sizeof(cbuf)); + cblen = MHD_snprintf_ (cbuf, + sizeof (cbuf), + "%X\r\n", + (unsigned int) ret); + mhd_assert (cblen > 0); + mhd_assert ((size_t) cblen < sizeof(cbuf)); memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen); @@ -1156,33 +1153,34 @@ keepalive_possible (struct MHD_Connection *connection) (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) return MHD_NO; - if (MHD_str_equal_caseless_(connection->version, - MHD_HTTP_VERSION_1_1) && + if (MHD_str_equal_caseless_ (connection->version, + MHD_HTTP_VERSION_1_1) && ( (NULL == connection->response) || - (0 == (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_RESPONSE) ) ) ) - { - if (MHD_lookup_header_s_token_ci (connection, - MHD_HTTP_HEADER_CONNECTION, - "upgrade")) - return MHD_NO; + (0 == (connection->response->flags + & MHD_RF_HTTP_VERSION_1_0_RESPONSE) ) ) ) + { + if (MHD_lookup_header_s_token_ci (connection, + MHD_HTTP_HEADER_CONNECTION, + "upgrade")) + return MHD_NO; - if (MHD_lookup_header_s_token_ci (connection, - MHD_HTTP_HEADER_CONNECTION, - "close")) - return MHD_NO; + if (MHD_lookup_header_s_token_ci (connection, + MHD_HTTP_HEADER_CONNECTION, + "close")) + return MHD_NO; + return MHD_YES; + } + if (MHD_str_equal_caseless_ (connection->version, + MHD_HTTP_VERSION_1_0)) + { + if (MHD_lookup_header_s_token_ci (connection, + MHD_HTTP_HEADER_CONNECTION, + "Keep-Alive")) return MHD_YES; - } - if (MHD_str_equal_caseless_(connection->version, - MHD_HTTP_VERSION_1_0)) - { - if (MHD_lookup_header_s_token_ci (connection, - MHD_HTTP_HEADER_CONNECTION, - "Keep-Alive")) - return MHD_YES; - return MHD_NO; - } + return MHD_NO; + } return MHD_NO; } @@ -1196,7 +1194,7 @@ keepalive_possible (struct MHD_Connection *connection) */ static void get_date_string (char *date, - size_t date_len) + size_t date_len) { static const char *const days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" @@ -1207,8 +1205,9 @@ get_date_string (char *date, }; struct tm now; time_t t; -#if !defined(HAVE_C11_GMTIME_S) && !defined(HAVE_W32_GMTIME_S) && !defined(HAVE_GMTIME_R) - struct tm* pNow; +#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \ + ! defined(HAVE_GMTIME_R) + struct tm*pNow; #endif date[0] = 0; @@ -1222,25 +1221,25 @@ get_date_string (char *date, &t)) return; #elif defined(HAVE_GMTIME_R) - if (NULL == gmtime_r(&t, - &now)) + if (NULL == gmtime_r (&t, + &now)) return; #else - pNow = gmtime(&t); + pNow = gmtime (&t); if (NULL == pNow) return; now = *pNow; #endif MHD_snprintf_ (date, - date_len, - "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", - days[now.tm_wday % 7], - (unsigned int) now.tm_mday, - mons[now.tm_mon % 12], - (unsigned int) (1900 + now.tm_year), - (unsigned int) now.tm_hour, - (unsigned int) now.tm_min, - (unsigned int) now.tm_sec); + date_len, + "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", + days[now.tm_wday % 7], + (unsigned int) now.tm_mday, + mons[now.tm_mon % 12], + (unsigned int) (1900 + now.tm_year), + (unsigned int) now.tm_hour, + (unsigned int) now.tm_min, + (unsigned int) now.tm_sec); } @@ -1269,26 +1268,26 @@ try_grow_read_buffer (struct MHD_Connection *connection, if (0 == connection->read_buffer_size) new_size = avail_size / 2; /* Use half of available buffer for reading */ else - { - size_t grow_size; + { + size_t grow_size; - grow_size = avail_size / 8; - if (MHD_BUF_INC_SIZE > grow_size) - { /* Shortage of space */ - if (!required) - return false; /* Grow is not mandatory, leave some space in pool */ - else - { - /* Shortage of space, but grow is mandatory */ - static const size_t small_inc = MHD_BUF_INC_SIZE / 8; - if (small_inc < avail_size) - grow_size = small_inc; - else - grow_size = avail_size; - } - } - new_size = connection->read_buffer_size + grow_size; + grow_size = avail_size / 8; + if (MHD_BUF_INC_SIZE > grow_size) + { /* Shortage of space */ + if (! required) + return false; /* Grow is not mandatory, leave some space in pool */ + else + { + /* Shortage of space, but grow is mandatory */ + static const size_t small_inc = MHD_BUF_INC_SIZE / 8; + if (small_inc < avail_size) + grow_size = small_inc; + else + grow_size = avail_size; + } } + new_size = connection->read_buffer_size + grow_size; + } /* we can actually grow the buffer, do it! */ connection->read_buffer = MHD_pool_reallocate (connection->pool, connection->read_buffer, @@ -1337,53 +1336,55 @@ build_header_response (struct MHD_Connection *connection) mhd_assert (NULL != connection->version); if (0 == connection->version[0]) - { - data = MHD_pool_allocate (connection->pool, - 0, - true); - connection->write_buffer = data; - connection->write_buffer_append_offset = 0; - connection->write_buffer_send_offset = 0; - connection->write_buffer_size = 0; - return MHD_YES; - } + { + data = MHD_pool_allocate (connection->pool, + 0, + true); + connection->write_buffer = data; + connection->write_buffer_append_offset = 0; + connection->write_buffer_send_offset = 0; + connection->write_buffer_size = 0; + return MHD_YES; + } rc = connection->responseCode & (~MHD_ICY_FLAG); if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) - { - reason_phrase = MHD_get_reason_phrase_for (rc); - off = MHD_snprintf_ (code, - sizeof (code), - "%s %u %s\r\n", - (0 != (connection->responseCode & MHD_ICY_FLAG)) - ? "ICY" - : ( (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_0, - connection->version) || - (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_RESPONSE)) ) - ? MHD_HTTP_VERSION_1_0 - : MHD_HTTP_VERSION_1_1), - rc, - reason_phrase); - /* estimate size */ - size = off + 2; /* +2 for extra "\r\n" at the end */ - kind = MHD_HEADER_KIND; - if ( (0 == (connection->daemon->options & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) && - (NULL == MHD_get_response_header (response, - MHD_HTTP_HEADER_DATE)) ) - get_date_string (date, - sizeof (date)); - else - date[0] = '\0'; - datelen = strlen (date); - size += datelen; - } + { + reason_phrase = MHD_get_reason_phrase_for (rc); + off = MHD_snprintf_ (code, + sizeof (code), + "%s %u %s\r\n", + (0 != (connection->responseCode & MHD_ICY_FLAG)) + ? "ICY" + : ( (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_0, + connection->version) || + (0 != (connection->response->flags + & MHD_RF_HTTP_VERSION_1_0_RESPONSE)) ) + ? MHD_HTTP_VERSION_1_0 + : MHD_HTTP_VERSION_1_1), + rc, + reason_phrase); + /* estimate size */ + size = off + 2; /* +2 for extra "\r\n" at the end */ + kind = MHD_HEADER_KIND; + if ( (0 == (connection->daemon->options + & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) && + (NULL == MHD_get_response_header (response, + MHD_HTTP_HEADER_DATE)) ) + get_date_string (date, + sizeof (date)); + else + date[0] = '\0'; + datelen = strlen (date); + size += datelen; + } else - { - /* 2 bytes for final CRLF of a Chunked-Body */ - size = 2; - kind = MHD_FOOTER_KIND; - off = 0; - datelen = 0; - } + { + /* 2 bytes for final CRLF of a Chunked-Body */ + size = 2; + kind = MHD_FOOTER_KIND; + off = 0; + datelen = 0; + } /* calculate extra headers we need to add, such as 'Connection: close', first see what was explicitly requested by the application */ @@ -1393,160 +1394,161 @@ build_header_response (struct MHD_Connection *connection) must_add_content_length = MHD_NO; response_has_close = false; switch (connection->state) - { - case MHD_CONNECTION_FOOTERS_RECEIVED: - response_has_close = MHD_check_response_header_s_token_ci (response, - MHD_HTTP_HEADER_CONNECTION, - "close"); - response_has_keepalive = MHD_check_response_header_s_token_ci (response, - MHD_HTTP_HEADER_CONNECTION, - "Keep-Alive"); - client_requested_close = MHD_lookup_header_s_token_ci (connection, - MHD_HTTP_HEADER_CONNECTION, - "close"); - - if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY)) - connection->keepalive = MHD_CONN_MUST_CLOSE; + { + case MHD_CONNECTION_FOOTERS_RECEIVED: + response_has_close = MHD_check_response_header_s_token_ci (response, + MHD_HTTP_HEADER_CONNECTION, + "close"); + response_has_keepalive = MHD_check_response_header_s_token_ci (response, + MHD_HTTP_HEADER_CONNECTION, + "Keep-Alive"); + client_requested_close = MHD_lookup_header_s_token_ci (connection, + MHD_HTTP_HEADER_CONNECTION, + "close"); + + if (0 != (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY)) + connection->keepalive = MHD_CONN_MUST_CLOSE; #ifdef UPGRADE_SUPPORT - else if (NULL != response->upgrade_handler) - /* If this connection will not be "upgraded", it must be closed. */ - connection->keepalive = MHD_CONN_MUST_CLOSE; + else if (NULL != response->upgrade_handler) + /* If this connection will not be "upgraded", it must be closed. */ + connection->keepalive = MHD_CONN_MUST_CLOSE; #endif /* UPGRADE_SUPPORT */ - /* now analyze chunked encoding situation */ - connection->have_chunked_upload = false; - have_encoding = MHD_get_response_header (response, - MHD_HTTP_HEADER_TRANSFER_ENCODING); - if (NULL == have_encoding) - may_add_content_length = MHD_YES; - else - may_add_content_length = MHD_NO; /* RFC 7230, Section 3.3.2 forbids header */ - if ( (MHD_SIZE_UNKNOWN == response->total_size) && + /* now analyze chunked encoding situation */ + connection->have_chunked_upload = false; + have_encoding = MHD_get_response_header (response, + MHD_HTTP_HEADER_TRANSFER_ENCODING); + if (NULL == have_encoding) + may_add_content_length = MHD_YES; + else + may_add_content_length = MHD_NO; /* RFC 7230, Section 3.3.2 forbids header */ + if ( (MHD_SIZE_UNKNOWN == response->total_size) && #ifdef UPGRADE_SUPPORT - (NULL == response->upgrade_handler) && + (NULL == response->upgrade_handler) && #endif /* UPGRADE_SUPPORT */ - (! response_has_close) && - (! client_requested_close) ) + (! response_has_close) && + (! client_requested_close) ) + { + /* size is unknown, and close was not explicitly requested; + need to either to HTTP 1.1 chunked encoding or + close the connection */ + /* 'close' header doesn't exist yet, see if we need to add one; + if the client asked for a close, no need to start chunk'ing */ + if ( (MHD_YES == keepalive_possible (connection)) && + (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, + connection->version) ) ) + { + if (NULL == have_encoding) + { + must_add_chunked_encoding = MHD_YES; + connection->have_chunked_upload = true; + } + else { - /* size is unknown, and close was not explicitly requested; - need to either to HTTP 1.1 chunked encoding or - close the connection */ - /* 'close' header doesn't exist yet, see if we need to add one; - if the client asked for a close, no need to start chunk'ing */ - if ( (MHD_YES == keepalive_possible (connection)) && - (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, - connection->version) ) ) - { - if (NULL == have_encoding) - { - must_add_chunked_encoding = MHD_YES; - connection->have_chunked_upload = true; - } - else - { - if (MHD_str_equal_caseless_ (have_encoding, - "identity")) - { - /* application forced identity encoding, can't do 'chunked' */ - must_add_close = MHD_YES; - } - else - { - connection->have_chunked_upload = true; - } - } - } + if (MHD_str_equal_caseless_ (have_encoding, + "identity")) + { + /* application forced identity encoding, can't do 'chunked' */ + must_add_close = MHD_YES; + } else - { - /* Keep alive or chunking not possible - => set close header if not present */ - if (! response_has_close) - must_add_close = MHD_YES; - } + { + connection->have_chunked_upload = true; + } } + } + else + { + /* Keep alive or chunking not possible + => set close header if not present */ + if (! response_has_close) + must_add_close = MHD_YES; + } + } - /* check for other reasons to add 'close' header */ - if ( ( (client_requested_close) || - (connection->read_closed) || - (MHD_CONN_MUST_CLOSE == connection->keepalive)) && - (! response_has_close) && + /* check for other reasons to add 'close' header */ + if ( ( (client_requested_close) || + (connection->read_closed) || + (MHD_CONN_MUST_CLOSE == connection->keepalive)) && + (! response_has_close) && #ifdef UPGRADE_SUPPORT - (NULL == response->upgrade_handler) && + (NULL == response->upgrade_handler) && #endif /* UPGRADE_SUPPORT */ - (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) - must_add_close = MHD_YES; - - /* check if we must add 'close' header because we cannot add content-length - because it is forbidden AND we don't have a 'chunked' encoding */ - if ( (! may_add_content_length) && - (! connection->have_chunked_upload) && - (! response_has_close) ) - must_add_close = MHD_YES; - /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status - codes SHOULD NOT have a Content-Length according to spec; - also chunked encoding / unknown length or CONNECT... */ - if ( (MHD_SIZE_UNKNOWN != response->total_size) && - (MHD_HTTP_NO_CONTENT != rc) && - (MHD_HTTP_NOT_MODIFIED != rc) && - (MHD_HTTP_OK <= rc) && - (NULL == /* this should always succeed due to check in + (0 == (response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) ) + must_add_close = MHD_YES; + + /* check if we must add 'close' header because we cannot add content-length + because it is forbidden AND we don't have a 'chunked' encoding */ + if ( (! may_add_content_length) && + (! connection->have_chunked_upload) && + (! response_has_close) ) + must_add_close = MHD_YES; + /* #MHD_HTTP_NO_CONTENT, #MHD_HTTP_NOT_MODIFIED and 1xx-status + codes SHOULD NOT have a Content-Length according to spec; + also chunked encoding / unknown length or CONNECT... */ + if ( (MHD_SIZE_UNKNOWN != response->total_size) && + (MHD_HTTP_NO_CONTENT != rc) && + (MHD_HTTP_NOT_MODIFIED != rc) && + (MHD_HTTP_OK <= rc) && + (NULL == /* this should always succeed due to check in MHD_add_response_header() */ - MHD_get_response_header (response, - MHD_HTTP_HEADER_CONTENT_LENGTH)) && - (may_add_content_length) && - ( (NULL == connection->method) || - (! MHD_str_equal_caseless_ (connection->method, - MHD_HTTP_METHOD_CONNECT)) ) ) - { - /* - Here we add a content-length if one is missing; however, - for 'connect' methods, the responses MUST NOT include a - content-length header *if* the response code is 2xx (in - which case we expect there to be no body). Still, - as we don't know the response code here in some cases, we - simply only force adding a content-length header if this - is not a 'connect' or if the response is not empty - (which is kind of more sane, because if some crazy - application did return content with a 2xx status code, - then having a content-length might again be a good idea). - - Note that the change from 'SHOULD NOT' to 'MUST NOT' is - a recent development of the HTTP 1.1 specification. - */ - content_length_len - = MHD_snprintf_ (content_length_buf, - sizeof (content_length_buf), - MHD_HTTP_HEADER_CONTENT_LENGTH ": " MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n", - (MHD_UNSIGNED_LONG_LONG) response->total_size); - must_add_content_length = MHD_YES; - } + MHD_get_response_header (response, + MHD_HTTP_HEADER_CONTENT_LENGTH)) && + (may_add_content_length) && + ( (NULL == connection->method) || + (! MHD_str_equal_caseless_ (connection->method, + MHD_HTTP_METHOD_CONNECT)) ) ) + { + /* + Here we add a content-length if one is missing; however, + for 'connect' methods, the responses MUST NOT include a + content-length header *if* the response code is 2xx (in + which case we expect there to be no body). Still, + as we don't know the response code here in some cases, we + simply only force adding a content-length header if this + is not a 'connect' or if the response is not empty + (which is kind of more sane, because if some crazy + application did return content with a 2xx status code, + then having a content-length might again be a good idea). + + Note that the change from 'SHOULD NOT' to 'MUST NOT' is + a recent development of the HTTP 1.1 specification. + */ + content_length_len + = MHD_snprintf_ (content_length_buf, + sizeof (content_length_buf), + MHD_HTTP_HEADER_CONTENT_LENGTH ": " + MHD_UNSIGNED_LONG_LONG_PRINTF "\r\n", + (MHD_UNSIGNED_LONG_LONG) response->total_size); + must_add_content_length = MHD_YES; + } - /* check for adding keep alive */ - if ( (! response_has_keepalive) && - (! response_has_close) && - (MHD_NO == must_add_close) && - (MHD_CONN_MUST_CLOSE != connection->keepalive) && + /* check for adding keep alive */ + if ( (! response_has_keepalive) && + (! response_has_close) && + (MHD_NO == must_add_close) && + (MHD_CONN_MUST_CLOSE != connection->keepalive) && #ifdef UPGRADE_SUPPORT - (NULL == response->upgrade_handler) && + (NULL == response->upgrade_handler) && #endif /* UPGRADE_SUPPORT */ - (MHD_YES == keepalive_possible (connection)) ) - must_add_keep_alive = MHD_YES; - break; - case MHD_CONNECTION_BODY_SENT: - response_has_keepalive = false; - break; - default: - mhd_assert (0); - return MHD_NO; - } + (MHD_YES == keepalive_possible (connection)) ) + must_add_keep_alive = MHD_YES; + break; + case MHD_CONNECTION_BODY_SENT: + response_has_keepalive = false; + break; + default: + mhd_assert (0); + return MHD_NO; + } if (MHD_CONN_MUST_CLOSE != connection->keepalive) - { - if ( (must_add_close) || (response_has_close) ) - connection->keepalive = MHD_CONN_MUST_CLOSE; - else if ( (must_add_keep_alive) || (response_has_keepalive) ) - connection->keepalive = MHD_CONN_USE_KEEPALIVE; - } + { + if ( (must_add_close) || (response_has_close) ) + connection->keepalive = MHD_CONN_MUST_CLOSE; + else if ( (must_add_keep_alive) || (response_has_keepalive) ) + connection->keepalive = MHD_CONN_USE_KEEPALIVE; + } if (must_add_close) size += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); @@ -1560,94 +1562,98 @@ build_header_response (struct MHD_Connection *connection) mhd_assert (! (must_add_chunked_encoding && must_add_content_length) ); for (pos = response->first_header; NULL != pos; pos = pos->next) - { - /* TODO: add proper support for excluding "Keep-Alive" token. */ - if ( (pos->kind == kind) && - (! ( (MHD_YES == must_add_close) && - (response_has_keepalive) && - (pos->header_size == MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION)) && - (MHD_str_equal_caseless_bin_n_(pos->header, - MHD_HTTP_HEADER_CONNECTION, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION))) && - (MHD_str_equal_caseless_(pos->value, - "Keep-Alive")) ) ) ) - size += pos->header_size + pos->value_size + 4; /* colon, space, linefeeds */ - } + { + /* TODO: add proper support for excluding "Keep-Alive" token. */ + if ( (pos->kind == kind) && + (! ( (MHD_YES == must_add_close) && + (response_has_keepalive) && + (pos->header_size == MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_CONNECTION)) && + (MHD_str_equal_caseless_bin_n_ (pos->header, + MHD_HTTP_HEADER_CONNECTION, + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_CONNECTION))) && + (MHD_str_equal_caseless_ (pos->value, + "Keep-Alive")) ) ) ) + size += pos->header_size + pos->value_size + 4; /* colon, space, linefeeds */ + } /* produce data */ data = MHD_pool_allocate (connection->pool, size + 1, false); if (NULL == data) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Not enough memory for write!\n"); + MHD_DLOG (connection->daemon, + "Not enough memory for write!\n"); #endif - return MHD_NO; - } + return MHD_NO; + } if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) - { - memcpy (data, - code, - off); - } + { + memcpy (data, + code, + off); + } if (must_add_close) - { - /* we must add the 'Connection: close' header */ - memcpy (&data[off], - "Connection: close\r\n", - MHD_STATICSTR_LEN_ ("Connection: close\r\n")); - off += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); - } + { + /* we must add the 'Connection: close' header */ + memcpy (&data[off], + "Connection: close\r\n", + MHD_STATICSTR_LEN_ ("Connection: close\r\n")); + off += MHD_STATICSTR_LEN_ ("Connection: close\r\n"); + } if (must_add_keep_alive) - { - /* we must add the 'Connection: Keep-Alive' header */ - memcpy (&data[off], - "Connection: Keep-Alive\r\n", - MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n")); - off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"); - } + { + /* we must add the 'Connection: Keep-Alive' header */ + memcpy (&data[off], + "Connection: Keep-Alive\r\n", + MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n")); + off += MHD_STATICSTR_LEN_ ("Connection: Keep-Alive\r\n"); + } if (must_add_chunked_encoding) - { - /* we must add the 'Transfer-Encoding: chunked' header */ - memcpy (&data[off], - "Transfer-Encoding: chunked\r\n", - MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n")); - off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"); - } + { + /* we must add the 'Transfer-Encoding: chunked' header */ + memcpy (&data[off], + "Transfer-Encoding: chunked\r\n", + MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n")); + off += MHD_STATICSTR_LEN_ ("Transfer-Encoding: chunked\r\n"); + } if (must_add_content_length) - { - /* we must add the 'Content-Length' header */ - memcpy (&data[off], - content_length_buf, - content_length_len); - off += content_length_len; - } + { + /* we must add the 'Content-Length' header */ + memcpy (&data[off], + content_length_buf, + content_length_len); + off += content_length_len; + } for (pos = response->first_header; NULL != pos; pos = pos->next) - { - /* TODO: add proper support for excluding "Keep-Alive" token. */ - if ( (pos->kind == kind) && - (! ( (MHD_YES == must_add_close) && - (response_has_keepalive) && - (pos->header_size == MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION)) && - (MHD_str_equal_caseless_bin_n_(pos->header, - MHD_HTTP_HEADER_CONNECTION, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONNECTION))) && - (MHD_str_equal_caseless_(pos->value, - "Keep-Alive")) ) ) ) - off += MHD_snprintf_ (&data[off], - size - off, - "%s: %s\r\n", - pos->header, - pos->value); - } + { + /* TODO: add proper support for excluding "Keep-Alive" token. */ + if ( (pos->kind == kind) && + (! ( (MHD_YES == must_add_close) && + (response_has_keepalive) && + (pos->header_size == MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_CONNECTION)) && + (MHD_str_equal_caseless_bin_n_ (pos->header, + MHD_HTTP_HEADER_CONNECTION, + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_CONNECTION))) && + (MHD_str_equal_caseless_ (pos->value, + "Keep-Alive")) ) ) ) + off += MHD_snprintf_ (&data[off], + size - off, + "%s: %s\r\n", + pos->header, + pos->value); + } if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) - { - memcpy (&data[off], - date, - datelen); - off += datelen; - } + { + memcpy (&data[off], + date, + datelen); + off += datelen; + } memcpy (&data[off], "\r\n", 2); @@ -1678,73 +1684,76 @@ build_header_response (struct MHD_Connection *connection) static void transmit_error_response (struct MHD_Connection *connection, unsigned int status_code, - const char *message) + const char *message) { struct MHD_Response *response; int iret; if (NULL == connection->version) - { - /* we were unable to process the full header line, so we don't - really know what version the client speaks; assume 1.0 */ - connection->version = MHD_HTTP_VERSION_1_0; - } + { + /* we were unable to process the full header line, so we don't + really know what version the client speaks; assume 1.0 */ + connection->version = MHD_HTTP_VERSION_1_0; + } connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; connection->read_closed = true; if (0 != connection->read_buffer_size) - { - /* Read buffer is not needed anymore, discard it - * to free some space for error response. */ - connection->read_buffer = MHD_pool_reallocate(connection->pool, - connection->read_buffer, - connection->read_buffer_size, - 0); - connection->read_buffer_size = 0; - } + { + /* Read buffer is not needed anymore, discard it + * to free some space for error response. */ + connection->read_buffer = MHD_pool_reallocate (connection->pool, + connection->read_buffer, + connection->read_buffer_size, + 0); + connection->read_buffer_size = 0; + } #ifdef HAVE_MESSAGES MHD_DLOG (connection->daemon, - _("Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"), + _ ( + "Error processing request (HTTP response code is %u (`%s')). Closing connection.\n"), status_code, message); #endif if (NULL != connection->response) - { - MHD_destroy_response (connection->response); - connection->response = NULL; - } + { + MHD_destroy_response (connection->response); + connection->response = NULL; + } response = MHD_create_response_from_buffer (strlen (message), - (void *) message, - MHD_RESPMEM_PERSISTENT); + (void *) message, + MHD_RESPMEM_PERSISTENT); if (NULL == response) - { - /* can't even send a reply, at least close the connection */ - connection->state = MHD_CONNECTION_CLOSED; - return; - } + { + /* can't even send a reply, at least close the connection */ + connection->state = MHD_CONNECTION_CLOSED; + return; + } iret = MHD_queue_response (connection, status_code, response); MHD_destroy_response (response); if (MHD_YES != iret) - { - /* can't even send a reply, at least close the connection */ - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (failed to queue response)\n")); - return; - } + { + /* can't even send a reply, at least close the connection */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (failed to queue response)\n")); + return; + } mhd_assert (NULL != connection->response); /* Do not reuse this connection. */ connection->keepalive = MHD_CONN_MUST_CLOSE; if (MHD_NO == build_header_response (connection)) - { - /* oops - close! */ - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (failed to create response header)\n")); - } + { + /* oops - close! */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (failed to create response header)\n")); + } else - { - connection->state = MHD_CONNECTION_HEADERS_SENDING; - } + { + connection->state = MHD_CONNECTION_HEADERS_SENDING; + } } @@ -1764,151 +1773,151 @@ MHD_connection_update_event_loop_info (struct MHD_Connection *connection) return; /* States will be updated after resume. */ #ifdef HTTPS_SUPPORT if (MHD_TLS_CONN_NO_TLS != connection->tls_state) - { /* HTTPS connection. */ - switch (connection->tls_state) - { - case MHD_TLS_CONN_INIT: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - return; - case MHD_TLS_CONN_HANDSHAKING: - if (0 == gnutls_record_get_direction (connection->tls_session)) - connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - else - connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - return; - default: - break; - } + { /* HTTPS connection. */ + switch (connection->tls_state) + { + case MHD_TLS_CONN_INIT: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + return; + case MHD_TLS_CONN_HANDSHAKING: + if (0 == gnutls_record_get_direction (connection->tls_session)) + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + return; + default: + break; } + } #endif /* HTTPS_SUPPORT */ while (1) - { + { #if DEBUG_STATES - MHD_DLOG (connection->daemon, - _("In function %s handling connection at state: %s\n"), - __FUNCTION__, - MHD_state_to_string (connection->state)); + MHD_DLOG (connection->daemon, + _ ("In function %s handling connection at state: %s\n"), + __FUNCTION__, + MHD_state_to_string (connection->state)); #endif - switch (connection->state) + switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: + /* while reading headers, we always grow the + read buffer if needed, no size-check required */ + if ( (connection->read_buffer_offset == connection->read_buffer_size) && + (! try_grow_read_buffer (connection, true)) ) + { + transmit_error_response (connection, + (connection->url != NULL) + ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE + : MHD_HTTP_URI_TOO_LONG, + REQUEST_TOO_BIG); + continue; + } + if (! connection->read_closed) + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_HEADERS_RECEIVED: + mhd_assert (0); + break; + case MHD_CONNECTION_HEADERS_PROCESSED: + mhd_assert (0); + break; + case MHD_CONNECTION_CONTINUE_SENDING: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_CONTINUE_SENT: + if (connection->read_buffer_offset == connection->read_buffer_size) + { + const bool internal_poll = (0 != (connection->daemon->options + & MHD_USE_INTERNAL_POLLING_THREAD)); + if ( (! try_grow_read_buffer (connection, true)) && + internal_poll) { - case MHD_CONNECTION_INIT: - case MHD_CONNECTION_URL_RECEIVED: - case MHD_CONNECTION_HEADER_PART_RECEIVED: - /* while reading headers, we always grow the - read buffer if needed, no size-check required */ - if ( (connection->read_buffer_offset == connection->read_buffer_size) && - (!try_grow_read_buffer (connection, true)) ) - { - transmit_error_response (connection, - (connection->url != NULL) - ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE - : MHD_HTTP_URI_TOO_LONG, - REQUEST_TOO_BIG); - continue; - } - if (! connection->read_closed) - connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - else - connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; - break; - case MHD_CONNECTION_HEADERS_RECEIVED: - mhd_assert (0); - break; - case MHD_CONNECTION_HEADERS_PROCESSED: - mhd_assert (0); - break; - case MHD_CONNECTION_CONTINUE_SENDING: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_CONTINUE_SENT: - if (connection->read_buffer_offset == connection->read_buffer_size) - { - const bool internal_poll = (0 != (connection->daemon->options & - MHD_USE_INTERNAL_POLLING_THREAD)); - if ( (!try_grow_read_buffer (connection, true)) && - internal_poll) - { - /* failed to grow the read buffer, and the - client which is supposed to handle the - received data in a *blocking* fashion - (in this mode) did not handle the data as - it was supposed to! - => we would either have to do busy-waiting - (on the client, which would likely fail), - or if we do nothing, we would just timeout - on the connection (if a timeout is even - set!). - Solution: we kill the connection with an error */ - transmit_error_response (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - INTERNAL_ERROR); - continue; - } - } - if ( (connection->read_buffer_offset < connection->read_buffer_size) && - (! connection->read_closed) ) - connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - else - connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; - break; - case MHD_CONNECTION_BODY_RECEIVED: - case MHD_CONNECTION_FOOTER_PART_RECEIVED: - /* while reading footers, we always grow the - read buffer if needed, no size-check required */ - if (connection->read_closed) - { - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; - /* transition to FOOTERS_RECEIVED - happens in read handler */ - break; - case MHD_CONNECTION_FOOTERS_RECEIVED: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; - break; - case MHD_CONNECTION_HEADERS_SENDING: - /* headers in buffer, keep writing */ - connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_HEADERS_SENT: - mhd_assert (0); - break; - case MHD_CONNECTION_NORMAL_BODY_READY: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_NORMAL_BODY_UNREADY: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; - break; - case MHD_CONNECTION_CHUNKED_BODY_READY: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_CHUNKED_BODY_UNREADY: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; - break; - case MHD_CONNECTION_BODY_SENT: - mhd_assert (0); - break; - case MHD_CONNECTION_FOOTERS_SENDING: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; - break; - case MHD_CONNECTION_FOOTERS_SENT: - mhd_assert (0); - break; - case MHD_CONNECTION_CLOSED: - connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; - return; /* do nothing, not even reading */ -#ifdef UPGRADE_SUPPORT - case MHD_CONNECTION_UPGRADE: - mhd_assert (0); - break; -#endif /* UPGRADE_SUPPORT */ - default: - mhd_assert (0); + /* failed to grow the read buffer, and the + client which is supposed to handle the + received data in a *blocking* fashion + (in this mode) did not handle the data as + it was supposed to! + => we would either have to do busy-waiting + (on the client, which would likely fail), + or if we do nothing, we would just timeout + on the connection (if a timeout is even + set!). + Solution: we kill the connection with an error */ + transmit_error_response (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + INTERNAL_ERROR); + continue; } + } + if ( (connection->read_buffer_offset < connection->read_buffer_size) && + (! connection->read_closed) ) + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + else + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + /* while reading footers, we always grow the + read buffer if needed, no size-check required */ + if (connection->read_closed) + { + CONNECTION_CLOSE_ERROR (connection, + NULL); + continue; + } + connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ; + /* transition to FOOTERS_RECEIVED + happens in read handler */ + break; + case MHD_CONNECTION_FOOTERS_RECEIVED: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_HEADERS_SENDING: + /* headers in buffer, keep writing */ + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_HEADERS_SENT: + mhd_assert (0); + break; + case MHD_CONNECTION_NORMAL_BODY_READY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK; break; + case MHD_CONNECTION_BODY_SENT: + mhd_assert (0); + break; + case MHD_CONNECTION_FOOTERS_SENDING: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE; + break; + case MHD_CONNECTION_FOOTERS_SENT: + mhd_assert (0); + break; + case MHD_CONNECTION_CLOSED: + connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + return; /* do nothing, not even reading */ +#ifdef UPGRADE_SUPPORT + case MHD_CONNECTION_UPGRADE: + mhd_assert (0); + break; +#endif /* UPGRADE_SUPPORT */ + default: + mhd_assert (0); } + break; + } } @@ -1942,21 +1951,21 @@ get_next_header_line (struct MHD_Connection *connection, pos++; if ( (pos == connection->read_buffer_offset - 1) && ('\n' != rbuf[pos]) ) + { + /* not found, consider growing... */ + if ( (connection->read_buffer_offset == connection->read_buffer_size) && + (! try_grow_read_buffer (connection, true)) ) { - /* not found, consider growing... */ - if ( (connection->read_buffer_offset == connection->read_buffer_size) && - (!try_grow_read_buffer (connection, true)) ) - { - transmit_error_response (connection, - (NULL != connection->url) - ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE - : MHD_HTTP_URI_TOO_LONG, - REQUEST_TOO_BIG); - } - if (line_len) - *line_len = 0; - return NULL; + transmit_error_response (connection, + (NULL != connection->url) + ? MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE + : MHD_HTTP_URI_TOO_LONG, + REQUEST_TOO_BIG); } + if (line_len) + *line_len = 0; + return NULL; + } if (line_len) *line_len = pos; @@ -1989,27 +1998,27 @@ static int connection_add_header (struct MHD_Connection *connection, const char *key, size_t key_size, - const char *value, - size_t value_size, - enum MHD_ValueKind kind) + const char *value, + size_t value_size, + enum MHD_ValueKind kind) { if (MHD_NO == MHD_set_connection_value_n (connection, - kind, - key, + kind, + key, key_size, - value, - value_size)) - { + value, + value_size)) + { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _("Not enough memory in pool to allocate header record!\n")); + MHD_DLOG (connection->daemon, + _ ("Not enough memory in pool to allocate header record!\n")); #endif - transmit_error_response (connection, - MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, - REQUEST_TOO_BIG); - return MHD_NO; - } + transmit_error_response (connection, + MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } return MHD_YES; } @@ -2038,7 +2047,8 @@ parse_cookie_header (struct MHD_Connection *connection) if (MHD_NO == MHD_lookup_connection_value_n (connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_COOKIE, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_COOKIE), + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_COOKIE), &hdr, &hdr_len)) return MHD_YES; @@ -2046,93 +2056,93 @@ parse_cookie_header (struct MHD_Connection *connection) hdr_len + 1, true); if (NULL == cpy) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _("Not enough memory in pool to parse cookies!\n")); + MHD_DLOG (connection->daemon, + _ ("Not enough memory in pool to parse cookies!\n")); #endif - transmit_error_response (connection, - MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, - REQUEST_TOO_BIG); - return MHD_NO; - } + transmit_error_response (connection, + MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } memcpy (cpy, hdr, hdr_len); cpy[hdr_len] = '\0'; pos = cpy; while (NULL != pos) + { + while (' ' == *pos) + pos++; /* skip spaces */ + + sce = pos; + while ( ((*sce) != '\0') && + ((*sce) != ',') && + ((*sce) != ';') && + ((*sce) != '=') ) + sce++; + /* remove tailing whitespace (if any) from key */ + ekill = sce - 1; + while ( (*ekill == ' ') && + (ekill >= pos) ) + *(ekill--) = '\0'; + old = *sce; + *sce = '\0'; + if (old != '=') { - while (' ' == *pos) - pos++; /* skip spaces */ - - sce = pos; - while ( ((*sce) != '\0') && - ((*sce) != ',') && - ((*sce) != ';') && - ((*sce) != '=') ) - sce++; - /* remove tailing whitespace (if any) from key */ - ekill = sce - 1; - while ( (*ekill == ' ') && - (ekill >= pos) ) - *(ekill--) = '\0'; - old = *sce; - *sce = '\0'; - if (old != '=') - { - /* value part omitted, use empty string... */ - if (MHD_NO == - connection_add_header (connection, - pos, - ekill - pos + 1, - "", - 0, - MHD_COOKIE_KIND)) - return MHD_NO; - if (old == '\0') - break; - pos = sce + 1; - continue; - } - equals = sce + 1; - quotes = 0; - semicolon = equals; - while ( ('\0' != semicolon[0]) && - ( (0 != quotes) || - ( (';' != semicolon[0]) && - (',' != semicolon[0]) ) ) ) - { - if ('"' == semicolon[0]) - quotes = (quotes + 1) & 1; - semicolon++; - } - end = semicolon; - if ('\0' == semicolon[0]) - semicolon = NULL; - if (NULL != semicolon) - { - semicolon[0] = '\0'; - semicolon++; - } - /* remove quotes */ - if ( ('"' == equals[0]) && - ('"' == end[-1]) ) - { - equals++; - end--; - *end = '\0'; - } + /* value part omitted, use empty string... */ if (MHD_NO == - connection_add_header (connection, - pos, + connection_add_header (connection, + pos, ekill - pos + 1, - equals, - end - equals, - MHD_COOKIE_KIND)) + "", + 0, + MHD_COOKIE_KIND)) return MHD_NO; - pos = semicolon; + if (old == '\0') + break; + pos = sce + 1; + continue; + } + equals = sce + 1; + quotes = 0; + semicolon = equals; + while ( ('\0' != semicolon[0]) && + ( (0 != quotes) || + ( (';' != semicolon[0]) && + (',' != semicolon[0]) ) ) ) + { + if ('"' == semicolon[0]) + quotes = (quotes + 1) & 1; + semicolon++; + } + end = semicolon; + if ('\0' == semicolon[0]) + semicolon = NULL; + if (NULL != semicolon) + { + semicolon[0] = '\0'; + semicolon++; + } + /* remove quotes */ + if ( ('"' == equals[0]) && + ('"' == end[-1]) ) + { + equals++; + end--; + *end = '\0'; } + if (MHD_NO == + connection_add_header (connection, + pos, + ekill - pos + 1, + equals, + end - equals, + MHD_COOKIE_KIND)) + return MHD_NO; + pos = semicolon; + } return MHD_YES; } @@ -2167,84 +2177,84 @@ parse_initial_message_line (struct MHD_Connection *connection, /* Skip any spaces. Not required by standard but allow to be more tolerant. */ while ( (' ' == uri[0]) && - ( (size_t)(uri - line) < line_len) ) + ( (size_t) (uri - line) < line_len) ) uri++; - if ((size_t)(uri - line) == line_len) + if ((size_t) (uri - line) == line_len) + { + /* No URI and no http version given */ + curi = ""; + uri = NULL; + connection->version = ""; + args = NULL; + } + else + { + size_t uri_len; + 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 points to character before HTTP version string */ + http_version[0] = '\0'; + connection->version = http_version + 1; + uri_len = http_version - uri; + } + else { - /* No URI and no http version given */ - curi = ""; - uri = NULL; connection->version = ""; - args = NULL; + uri_len = line_len - (uri - line); } - else + /* check for spaces in URI if we are "strict" */ + if ( (1 <= daemon->strict_for_client) && + (NULL != memchr (uri, + ' ', + uri_len)) ) { - size_t uri_len; - 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 points to character before HTTP version string */ - http_version[0] = '\0'; - connection->version = http_version + 1; - uri_len = http_version - uri; - } - else - { - connection->version = ""; - uri_len = line_len - (uri - line); - } - /* check for spaces in URI if we are "strict" */ - if ( (1 <= daemon->strict_for_client) && - (NULL != memchr (uri, - ' ', - uri_len)) ) - { - /* space exists in URI and we are supposed to be strict, reject */ - return MHD_NO; - } - - args = memchr (uri, - '?', - uri_len); + /* space exists in URI and we are supposed to be strict, reject */ + return MHD_NO; } + args = memchr (uri, + '?', + uri_len); + } + /* log callback before we modify URI *or* args */ if (NULL != daemon->uri_log_callback) - { - connection->client_aware = true; - connection->client_context - = daemon->uri_log_callback (daemon->uri_log_callback_cls, - uri, - connection); - } + { + connection->client_aware = true; + connection->client_context + = daemon->uri_log_callback (daemon->uri_log_callback_cls, + uri, + connection); + } 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); - } + { + 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); + } /* unescape URI *after* searching for arguments and log callback */ if (NULL != uri) daemon->unescape_callback (daemon->unescape_callback_cls, - connection, - uri); + connection, + uri); connection->url = curi; return MHD_YES; } @@ -2276,12 +2286,13 @@ call_connection_handler (struct MHD_Connection *connection) NULL, &processed, &connection->client_context)) - { - /* serious internal error, close connection */ - CONNECTION_CLOSE_ERROR (connection, - _("Application reported internal error, closing connection.\n")); - return; - } + { + /* serious internal error, close connection */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Application reported internal error, closing connection.\n")); + return; + } } @@ -2318,199 +2329,205 @@ process_request_body (struct MHD_Connection *connection) buffer_head = connection->read_buffer; available = connection->read_buffer_offset; do - { - size_t to_be_processed; - size_t left_unprocessed; - size_t processed_size; + { + size_t to_be_processed; + size_t left_unprocessed; + size_t processed_size; - instant_retry = MHD_NO; - if ( (connection->have_chunked_upload) && - (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) ) - { - if ( (connection->current_chunk_offset == connection->current_chunk_size) && - (0LLU != connection->current_chunk_offset) && - (available >= 2) ) - { - size_t i; - /* skip new line at the *end* of a chunk */ - i = 0; - if ( ('\r' == buffer_head[i]) || - ('\n' == buffer_head[i]) ) - i++; /* skip 1st part of line feed */ - if ( ('\r' == buffer_head[i]) || - ('\n' == buffer_head[i]) ) - i++; /* skip 2nd part of line feed */ - if (0 == i) - { - /* malformed encoding */ - CONNECTION_CLOSE_ERROR (connection, - _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); - return; - } - available -= i; - buffer_head += i; - connection->current_chunk_offset = 0; - connection->current_chunk_size = 0; - } - if (connection->current_chunk_offset < - connection->current_chunk_size) - { - uint64_t cur_chunk_left; - /* we are in the middle of a chunk, give - as much as possible to the client (without - crossing chunk boundaries) */ - cur_chunk_left - = connection->current_chunk_size - connection->current_chunk_offset; - if (cur_chunk_left > available) - to_be_processed = available; - else - { /* cur_chunk_left <= (size_t)available */ - to_be_processed = (size_t)cur_chunk_left; - if (available > to_be_processed) - instant_retry = MHD_YES; - } - } - else - { - size_t i; - size_t end_size; - bool malformed; - - /* we need to read chunk boundaries */ - i = 0; - while (i < available) - { - if ( ('\r' == buffer_head[i]) || - ('\n' == buffer_head[i]) || - (';' == buffer_head[i]) ) - break; - i++; - if (i >= 16) - break; - } - end_size = i; - /* find beginning of CRLF (skip over chunk extensions) */ - if (';' == buffer_head[i]) - { - while (i < available) - { - if ( ('\r' == buffer_head[i]) || - ('\n' == buffer_head[i]) ) - break; - i++; - } - } - /* take '\n' into account; if '\n' is the unavailable - character, we will need to wait until we have it - before going further */ - if ( (i + 1 >= available) && - ! ( (1 == i) && - (2 == available) && - ('0' == buffer_head[0]) ) ) - break; /* need more data... */ - i++; - malformed = (end_size >= 16); - if (! malformed) - { - size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head, - end_size, - &connection->current_chunk_size); - malformed = (end_size != num_dig); - } - if (malformed) - { - /* malformed encoding */ - CONNECTION_CLOSE_ERROR (connection, - _("Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); - return; - } - /* skip 2nd part of line feed */ - if ( (i < available) && - ( ('\r' == buffer_head[i]) || - ('\n' == buffer_head[i]) ) ) - i++; - - buffer_head += i; - available -= i; - connection->current_chunk_offset = 0; - - if (available > 0) - instant_retry = MHD_YES; - if (0LLU == connection->current_chunk_size) - { - connection->remaining_upload_size = 0; - break; - } - continue; - } - } - else - { - /* no chunked encoding, give all to the client */ - if ( (0 != connection->remaining_upload_size) && - (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && - (connection->remaining_upload_size < available) ) - { - to_be_processed = (size_t)connection->remaining_upload_size; - } - else - { - /** - * 1. no chunked encoding, give all to the client - * 2. client may send large chunked data, but only a smaller part is available at one time. - */ - to_be_processed = available; - } - } - left_unprocessed = to_be_processed; - connection->client_aware = true; - if (MHD_NO == - daemon->default_handler (daemon->default_handler_cls, - connection, - connection->url, - connection->method, - connection->version, - buffer_head, - &left_unprocessed, - &connection->client_context)) + instant_retry = MHD_NO; + if ( (connection->have_chunked_upload) && + (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) ) + { + if ( (connection->current_chunk_offset == + connection->current_chunk_size) && + (0LLU != connection->current_chunk_offset) && + (available >= 2) ) + { + size_t i; + /* skip new line at the *end* of a chunk */ + i = 0; + if ( ('\r' == buffer_head[i]) || + ('\n' == buffer_head[i]) ) + i++; /* skip 1st part of line feed */ + if ( ('\r' == buffer_head[i]) || + ('\n' == buffer_head[i]) ) + i++; /* skip 2nd part of line feed */ + if (0 == i) { - /* serious internal error, close connection */ + /* malformed encoding */ CONNECTION_CLOSE_ERROR (connection, - _("Application reported internal error, closing connection.\n")); + _ ( + "Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); return; } - if (left_unprocessed > to_be_processed) - mhd_panic (mhd_panic_cls, - __FILE__, - __LINE__ + available -= i; + buffer_head += i; + connection->current_chunk_offset = 0; + connection->current_chunk_size = 0; + } + if (connection->current_chunk_offset < + connection->current_chunk_size) + { + uint64_t cur_chunk_left; + /* we are in the middle of a chunk, give + as much as possible to the client (without + crossing chunk boundaries) */ + cur_chunk_left + = connection->current_chunk_size - connection->current_chunk_offset; + if (cur_chunk_left > available) + to_be_processed = available; + else + { /* cur_chunk_left <= (size_t)available */ + to_be_processed = (size_t) cur_chunk_left; + if (available > to_be_processed) + instant_retry = MHD_YES; + } + } + else + { + size_t i; + size_t end_size; + bool malformed; + + /* we need to read chunk boundaries */ + i = 0; + while (i < available) + { + if ( ('\r' == buffer_head[i]) || + ('\n' == buffer_head[i]) || + (';' == buffer_head[i]) ) + break; + i++; + if (i >= 16) + break; + } + end_size = i; + /* find beginning of CRLF (skip over chunk extensions) */ + if (';' == buffer_head[i]) + { + while (i < available) + { + if ( ('\r' == buffer_head[i]) || + ('\n' == buffer_head[i]) ) + break; + i++; + } + } + /* take '\n' into account; if '\n' is the unavailable + character, we will need to wait until we have it + before going further */ + if ( (i + 1 >= available) && + ! ( (1 == i) && + (2 == available) && + ('0' == buffer_head[0]) ) ) + break; /* need more data... */ + i++; + malformed = (end_size >= 16); + if (! malformed) + { + size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head, + end_size, + &connection-> + current_chunk_size); + malformed = (end_size != num_dig); + } + if (malformed) + { + /* malformed encoding */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Received malformed HTTP request (bad chunked encoding). Closing connection.\n")); + return; + } + /* skip 2nd part of line feed */ + if ( (i < available) && + ( ('\r' == buffer_head[i]) || + ('\n' == buffer_head[i]) ) ) + i++; + + buffer_head += i; + available -= i; + connection->current_chunk_offset = 0; + + if (available > 0) + instant_retry = MHD_YES; + if (0LLU == connection->current_chunk_size) + { + connection->remaining_upload_size = 0; + break; + } + continue; + } + } + else + { + /* no chunked encoding, give all to the client */ + if ( (0 != connection->remaining_upload_size) && + (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) && + (connection->remaining_upload_size < available) ) + { + to_be_processed = (size_t) connection->remaining_upload_size; + } + else + { + /** + * 1. no chunked encoding, give all to the client + * 2. client may send large chunked data, but only a smaller part is available at one time. + */ + to_be_processed = available; + } + } + left_unprocessed = to_be_processed; + connection->client_aware = true; + if (MHD_NO == + daemon->default_handler (daemon->default_handler_cls, + connection, + connection->url, + connection->method, + connection->version, + buffer_head, + &left_unprocessed, + &connection->client_context)) + { + /* serious internal error, close connection */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Application reported internal error, closing connection.\n")); + return; + } + if (left_unprocessed > to_be_processed) + mhd_panic (mhd_panic_cls, + __FILE__, + __LINE__ #ifdef HAVE_MESSAGES - , _("libmicrohttpd API violation") + , _ ("libmicrohttpd API violation") #else - , NULL + , NULL #endif - ); - if (0 != left_unprocessed) - { - instant_retry = MHD_NO; /* client did not process everything */ + ); + if (0 != left_unprocessed) + { + instant_retry = MHD_NO; /* client did not process everything */ #ifdef HAVE_MESSAGES - /* client did not process all upload data, complain if - the setup was incorrect, which may prevent us from - handling the rest of the request */ - if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && - (! connection->suspended) ) - MHD_DLOG (daemon, - _("WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n")); + /* client did not process all upload data, complain if + the setup was incorrect, which may prevent us from + handling the rest of the request */ + if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && + (! connection->suspended) ) + MHD_DLOG (daemon, + _ ( + "WARNING: incomplete upload processing and connection not suspended may result in hung connection.\n")); #endif - } - processed_size = to_be_processed - left_unprocessed; - if (connection->have_chunked_upload) - connection->current_chunk_offset += processed_size; - /* dh left "processed" bytes in buffer for next time... */ - buffer_head += processed_size; - available -= processed_size; - if (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) - connection->remaining_upload_size -= processed_size; } + processed_size = to_be_processed - left_unprocessed; + if (connection->have_chunked_upload) + connection->current_chunk_offset += processed_size; + /* dh left "processed" bytes in buffer for next time... */ + buffer_head += processed_size; + available -= processed_size; + if (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) + connection->remaining_upload_size -= processed_size; + } while (MHD_YES == instant_retry); if ( (available > 0) && (buffer_head != connection->read_buffer) ) @@ -2540,7 +2557,7 @@ check_write_done (struct MHD_Connection *connection, connection->write_buffer_send_offset = 0; connection->state = next_state; MHD_pool_reallocate (connection->pool, - connection->write_buffer, + connection->write_buffer, connection->write_buffer_size, 0); connection->write_buffer = NULL; @@ -2567,28 +2584,29 @@ process_header_line (struct MHD_Connection *connection, /* line should be normal header line, find colon */ colon = strchr (line, ':'); if (NULL == colon) - { - /* error in header line, die hard */ - CONNECTION_CLOSE_ERROR (connection, - _("Received malformed line (no colon). Closing connection.\n")); - return MHD_NO; - } + { + /* error in header line, die hard */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Received malformed line (no colon). Closing connection.\n")); + return MHD_NO; + } if (-1 >= connection->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, ' '); - if ( (NULL != white) && - (white < colon) ) - return MHD_NO; - white = strchr (line, '\t'); - if ( (NULL != white) && - (white < colon) ) - return MHD_NO; - } + { + /* 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, ' '); + if ( (NULL != white) && + (white < colon) ) + return MHD_NO; + white = strchr (line, '\t'); + if ( (NULL != white) && + (white < colon) ) + return MHD_NO; + } /* zero-terminate header */ colon[0] = '\0'; colon++; /* advance to value */ @@ -2630,69 +2648,69 @@ process_broken_line (struct MHD_Connection *connection, last = connection->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); - connection->last = last; - return MHD_YES; /* possibly more than 2 lines... */ - } - mhd_assert ( (NULL != last) && - (NULL != connection->colon) ); - if (MHD_NO == - connection_add_header (connection, - last, - strlen (last), - connection->colon, - strlen (connection->colon), - kind)) + { + /* 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); + connection->last = last; + return MHD_YES; /* possibly more than 2 lines... */ + } + mhd_assert ( (NULL != last) && + (NULL != connection->colon) ); + if (MHD_NO == + connection_add_header (connection, + last, + strlen (last), + connection->colon, + strlen (connection->colon), + kind)) + { + transmit_error_response (connection, + MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } /* we still have the current line to deal with... */ if (0 != line[0]) + { + if (MHD_NO == process_header_line (connection, + line)) { - if (MHD_NO == process_header_line (connection, - line)) - { - transmit_error_response (connection, - MHD_HTTP_BAD_REQUEST, - REQUEST_MALFORMED); - return MHD_NO; - } + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, + REQUEST_MALFORMED); + return MHD_NO; } + } return MHD_YES; } @@ -2715,88 +2733,93 @@ parse_connection_headers (struct MHD_Connection *connection) parse_cookie_header (connection); if ( (1 <= connection->daemon->strict_for_client) && (NULL != connection->version) && - (MHD_str_equal_caseless_(MHD_HTTP_VERSION_1_1, - connection->version)) && + (MHD_str_equal_caseless_ (MHD_HTTP_VERSION_1_1, + connection->version)) && (MHD_NO == MHD_lookup_connection_value_n (connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_HOST), + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_HOST), NULL, NULL)) ) - { - int iret; + { + int iret; - /* die, http 1.1 request without host and we are pedantic */ - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; - connection->read_closed = true; + /* die, http 1.1 request without host and we are pedantic */ + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + connection->read_closed = true; #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _("Received HTTP 1.1 request without `Host' header.\n")); + MHD_DLOG (connection->daemon, + _ ("Received HTTP 1.1 request without `Host' header.\n")); #endif - mhd_assert (NULL == connection->response); - response = - MHD_create_response_from_buffer (MHD_STATICSTR_LEN_ (REQUEST_LACKS_HOST), - REQUEST_LACKS_HOST, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - /* can't even send a reply, at least close the connection */ - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (failed to create response)\n")); - return; - } - iret = MHD_queue_response (connection, - MHD_HTTP_BAD_REQUEST, - response); - MHD_destroy_response (response); - if (MHD_YES != iret) - { - /* can't even send a reply, at least close the connection */ - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (failed to queue response)\n")); - } + mhd_assert (NULL == connection->response); + response = + MHD_create_response_from_buffer (MHD_STATICSTR_LEN_ (REQUEST_LACKS_HOST), + REQUEST_LACKS_HOST, + MHD_RESPMEM_PERSISTENT); + if (NULL == response) + { + /* can't even send a reply, at least close the connection */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (failed to create response)\n")); return; } + iret = MHD_queue_response (connection, + MHD_HTTP_BAD_REQUEST, + response); + MHD_destroy_response (response); + if (MHD_YES != iret) + { + /* can't even send a reply, at least close the connection */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (failed to queue response)\n")); + } + return; + } connection->remaining_upload_size = 0; if (MHD_NO != MHD_lookup_connection_value_n (connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_TRANSFER_ENCODING, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_TRANSFER_ENCODING), + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_TRANSFER_ENCODING), &enc, NULL)) - { - connection->remaining_upload_size = MHD_SIZE_UNKNOWN; - if (MHD_str_equal_caseless_(enc, - "chunked")) - connection->have_chunked_upload = true; - } + { + connection->remaining_upload_size = MHD_SIZE_UNKNOWN; + if (MHD_str_equal_caseless_ (enc, + "chunked")) + connection->have_chunked_upload = true; + } else + { + if (MHD_NO != MHD_lookup_connection_value_n (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_LENGTH, + MHD_STATICSTR_LEN_ ( + MHD_HTTP_HEADER_CONTENT_LENGTH), + &clen, + NULL)) { - if (MHD_NO != MHD_lookup_connection_value_n (connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_CONTENT_LENGTH, - MHD_STATICSTR_LEN_(MHD_HTTP_HEADER_CONTENT_LENGTH), - &clen, - NULL)) - { - end = clen + MHD_str_to_uint64_ (clen, - &connection->remaining_upload_size); - if ( (clen == end) || - ('\0' != *end) ) - { - connection->remaining_upload_size = 0; + end = clen + MHD_str_to_uint64_ (clen, + &connection->remaining_upload_size); + if ( (clen == end) || + ('\0' != *end) ) + { + connection->remaining_upload_size = 0; #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - "Failed to parse `Content-Length' header. Closing connection.\n"); + MHD_DLOG (connection->daemon, + "Failed to parse `Content-Length' header. Closing connection.\n"); #endif - CONNECTION_CLOSE_ERROR (connection, - NULL); - return; - } - } + CONNECTION_CLOSE_ERROR (connection, + NULL); + return; + } } + } } @@ -2818,7 +2841,7 @@ MHD_update_last_activity_ (struct MHD_Connection *connection) if (connection->suspended) return; /* no activity on suspended connections */ - connection->last_activity = MHD_monotonic_sec_counter(); + connection->last_activity = MHD_monotonic_sec_counter (); if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) return; /* each connection has personal timeout */ @@ -2829,11 +2852,11 @@ MHD_update_last_activity_ (struct MHD_Connection *connection) #endif /* move connection to head of timeout list (by remove + add operation) */ XDLL_remove (daemon->normal_timeout_head, - daemon->normal_timeout_tail, - connection); + daemon->normal_timeout_tail, + connection); XDLL_insert (daemon->normal_timeout_head, - daemon->normal_timeout_tail, - connection); + daemon->normal_timeout_tail, + connection); #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); #endif @@ -2856,13 +2879,13 @@ MHD_connection_handle_read (struct MHD_Connection *connection) return; #ifdef HTTPS_SUPPORT if (MHD_TLS_CONN_NO_TLS != connection->tls_state) - { /* HTTPS connection. */ - if (MHD_TLS_CONN_CONNECTED > connection->tls_state) - { - if (!MHD_run_tls_handshake_ (connection)) - return; - } + { /* HTTPS connection. */ + if (MHD_TLS_CONN_CONNECTED > connection->tls_state) + { + if (! MHD_run_tls_handshake_ (connection)) + return; } + } #endif /* HTTPS_SUPPORT */ /* make sure "read" has a reasonable number of bytes @@ -2870,82 +2893,85 @@ MHD_connection_handle_read (struct MHD_Connection *connection) if (connection->read_buffer_offset + connection->daemon->pool_increment > connection->read_buffer_size) try_grow_read_buffer (connection, - (connection->read_buffer_size == connection->read_buffer_offset)); + (connection->read_buffer_size == + connection->read_buffer_offset)); if (connection->read_buffer_size == connection->read_buffer_offset) return; /* No space for receiving data. */ bytes_read = connection->recv_cls (connection, &connection->read_buffer [connection->read_buffer_offset], - connection->read_buffer_size - - connection->read_buffer_offset); + connection->read_buffer_size + - connection->read_buffer_offset); if (bytes_read < 0) + { + if (MHD_ERR_AGAIN_ == bytes_read) + return; /* No new data to process. */ + if (MHD_ERR_CONNRESET_ == bytes_read) { - if (MHD_ERR_AGAIN_ == bytes_read) - return; /* No new data to process. */ - if (MHD_ERR_CONNRESET_ == bytes_read) - { - CONNECTION_CLOSE_ERROR (connection, - (MHD_CONNECTION_INIT == connection->state) ? - NULL : - _("Socket disconnected while reading request.\n")); - return; - } CONNECTION_CLOSE_ERROR (connection, (MHD_CONNECTION_INIT == connection->state) ? - NULL : - _("Connection socket is closed due to error when reading request.\n")); + NULL : + _ ( + "Socket disconnected while reading request.\n")); return; } + CONNECTION_CLOSE_ERROR (connection, + (MHD_CONNECTION_INIT == connection->state) ? + NULL : + _ ( + "Connection socket is closed due to error when reading request.\n")); + return; + } if (0 == bytes_read) - { /* Remote side closed connection. */ - connection->read_closed = true; - MHD_connection_close_ (connection, - MHD_REQUEST_TERMINATED_CLIENT_ABORT); - return; - } + { /* Remote side closed connection. */ + connection->read_closed = true; + MHD_connection_close_ (connection, + MHD_REQUEST_TERMINATED_CLIENT_ABORT); + return; + } connection->read_buffer_offset += bytes_read; MHD_update_last_activity_ (connection); #if DEBUG_STATES MHD_DLOG (connection->daemon, - _("In function %s handling connection at state: %s\n"), + _ ("In function %s handling connection at state: %s\n"), __FUNCTION__, MHD_state_to_string (connection->state)); #endif switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: + case MHD_CONNECTION_HEADERS_RECEIVED: + case MHD_CONNECTION_HEADERS_PROCESSED: + case MHD_CONNECTION_CONTINUE_SENDING: + case MHD_CONNECTION_CONTINUE_SENT: + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + /* nothing to do but default action */ + if (connection->read_closed) { - case MHD_CONNECTION_INIT: - case MHD_CONNECTION_URL_RECEIVED: - case MHD_CONNECTION_HEADER_PART_RECEIVED: - case MHD_CONNECTION_HEADERS_RECEIVED: - case MHD_CONNECTION_HEADERS_PROCESSED: - case MHD_CONNECTION_CONTINUE_SENDING: - case MHD_CONNECTION_CONTINUE_SENT: - case MHD_CONNECTION_BODY_RECEIVED: - case MHD_CONNECTION_FOOTER_PART_RECEIVED: - /* nothing to do but default action */ - if (connection->read_closed) - { - MHD_connection_close_ (connection, - MHD_REQUEST_TERMINATED_READ_ERROR); - } - return; - case MHD_CONNECTION_CLOSED: - return; + MHD_connection_close_ (connection, + MHD_REQUEST_TERMINATED_READ_ERROR); + } + return; + case MHD_CONNECTION_CLOSED: + return; #ifdef UPGRADE_SUPPORT - case MHD_CONNECTION_UPGRADE: - mhd_assert (0); - return; + case MHD_CONNECTION_UPGRADE: + mhd_assert (0); + return; #endif /* UPGRADE_SUPPORT */ - default: - /* shrink read buffer to how much is actually used */ - MHD_pool_reallocate (connection->pool, - connection->read_buffer, - connection->read_buffer_size + 1, - connection->read_buffer_offset); - break; - } + default: + /* shrink read buffer to how much is actually used */ + MHD_pool_reallocate (connection->pool, + connection->read_buffer, + connection->read_buffer_size + 1, + connection->read_buffer_offset); + break; + } return; } @@ -2966,258 +2992,261 @@ MHD_connection_handle_write (struct MHD_Connection *connection) #ifdef HTTPS_SUPPORT if (MHD_TLS_CONN_NO_TLS != connection->tls_state) - { /* HTTPS connection. */ - if (MHD_TLS_CONN_CONNECTED > connection->tls_state) - { - if (!MHD_run_tls_handshake_ (connection)) - return; - } + { /* HTTPS connection. */ + if (MHD_TLS_CONN_CONNECTED > connection->tls_state) + { + if (! MHD_run_tls_handshake_ (connection)) + return; } + } #endif /* HTTPS_SUPPORT */ #if DEBUG_STATES MHD_DLOG (connection->daemon, - _("In function %s handling connection at state: %s\n"), + _ ("In function %s handling connection at state: %s\n"), __FUNCTION__, MHD_state_to_string (connection->state)); #endif switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: + case MHD_CONNECTION_HEADERS_RECEIVED: + mhd_assert (0); + return; + case MHD_CONNECTION_HEADERS_PROCESSED: + return; + case MHD_CONNECTION_CONTINUE_SENDING: + ret = MHD_send_on_connection_ (connection, + &HTTP_100_CONTINUE + [connection->continue_message_write_offset], + MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) + - connection->continue_message_write_offset, + MHD_SSO_NO_CORK); + if (ret < 0) { - case MHD_CONNECTION_INIT: - case MHD_CONNECTION_URL_RECEIVED: - case MHD_CONNECTION_HEADER_PART_RECEIVED: - case MHD_CONNECTION_HEADERS_RECEIVED: - mhd_assert (0); - return; - case MHD_CONNECTION_HEADERS_PROCESSED: - return; - case MHD_CONNECTION_CONTINUE_SENDING: - ret = MHD_send_on_connection_ (connection, - &HTTP_100_CONTINUE - [connection->continue_message_write_offset], - MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE) - - connection->continue_message_write_offset, - MHD_SSO_NO_CORK); - if (ret < 0) - { - if (MHD_ERR_AGAIN_ == ret) - return; + if (MHD_ERR_AGAIN_ == ret) + return; #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _("Failed to send data in request for %s.\n"), - connection->url); + MHD_DLOG (connection->daemon, + _ ("Failed to send data in request for %s.\n"), + connection->url); #endif - CONNECTION_CLOSE_ERROR (connection, - NULL); - return; - } + CONNECTION_CLOSE_ERROR (connection, + NULL); + return; + } #if DEBUG_SEND_DATA - fprintf (stderr, - _("Sent 100 continue response: `%.*s'\n"), - (int) ret, - &HTTP_100_CONTINUE[connection->continue_message_write_offset]); + fprintf (stderr, + _ ("Sent 100 continue response: `%.*s'\n"), + (int) ret, + &HTTP_100_CONTINUE[connection->continue_message_write_offset]); #endif - connection->continue_message_write_offset += ret; - MHD_update_last_activity_ (connection); - return; - case MHD_CONNECTION_CONTINUE_SENT: - case MHD_CONNECTION_BODY_RECEIVED: - case MHD_CONNECTION_FOOTER_PART_RECEIVED: - case MHD_CONNECTION_FOOTERS_RECEIVED: - mhd_assert (0); - return; - case MHD_CONNECTION_HEADERS_SENDING: - { - const size_t wb_ready = connection->write_buffer_append_offset - - connection->write_buffer_send_offset; + connection->continue_message_write_offset += ret; + MHD_update_last_activity_ (connection); + return; + case MHD_CONNECTION_CONTINUE_SENT: + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + case MHD_CONNECTION_FOOTERS_RECEIVED: + mhd_assert (0); + return; + case MHD_CONNECTION_HEADERS_SENDING: + { + const size_t wb_ready = connection->write_buffer_append_offset + - connection->write_buffer_send_offset; - /* if the response body is not available, we use MHD_send_on_connection_() */ - if (NULL != connection->response->crc) - { - ret = MHD_send_on_connection_ (connection, - &connection->write_buffer - [connection->write_buffer_send_offset], - wb_ready, - MHD_SSO_MAY_CORK); - } - else - { - ret = MHD_send_on_connection2_ (connection, - &connection->write_buffer - [connection->write_buffer_send_offset], - wb_ready, - connection->response->data, - connection->response->data_buffer_size); - } + /* if the response body is not available, we use MHD_send_on_connection_() */ + if (NULL != connection->response->crc) + { + ret = MHD_send_on_connection_ (connection, + &connection->write_buffer + [connection->write_buffer_send_offset], + wb_ready, + MHD_SSO_MAY_CORK); + } + else + { + ret = MHD_send_on_connection2_ (connection, + &connection->write_buffer + [connection->write_buffer_send_offset], + wb_ready, + connection->response->data, + connection->response->data_buffer_size); + } - if (ret < 0) - { - if (MHD_ERR_AGAIN_ == ret) - return; - CONNECTION_CLOSE_ERROR (connection, - _("Connection was closed while sending response headers.\n")); - return; - } - if (ret > wb_ready) - { - mhd_assert (NULL == connection->repsonse->crc); - /* We sent not just header data but also some response data, - update both offsets! */ - connection->write_buffer_send_offset += wb_ready; - ret -= wb_ready; - connection->response_write_position += ret; - } - else - connection->write_buffer_send_offset += ret; - MHD_update_last_activity_ (connection); - if (MHD_CONNECTION_HEADERS_SENDING != connection->state) + if (ret < 0) + { + if (MHD_ERR_AGAIN_ == ret) return; - check_write_done (connection, - MHD_CONNECTION_HEADERS_SENT); + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Connection was closed while sending response headers.\n")); return; } - case MHD_CONNECTION_HEADERS_SENT: + if (ret > wb_ready) + { + mhd_assert (NULL == connection->repsonse->crc); + /* We sent not just header data but also some response data, + update both offsets! */ + connection->write_buffer_send_offset += wb_ready; + ret -= wb_ready; + connection->response_write_position += ret; + } + else + connection->write_buffer_send_offset += ret; + MHD_update_last_activity_ (connection); + if (MHD_CONNECTION_HEADERS_SENDING != connection->state) + return; + check_write_done (connection, + MHD_CONNECTION_HEADERS_SENT); return; - case MHD_CONNECTION_NORMAL_BODY_READY: - response = connection->response; - if (connection->response_write_position < - connection->response->total_size) - { - uint64_t data_write_offset; + } + case MHD_CONNECTION_HEADERS_SENT: + return; + case MHD_CONNECTION_NORMAL_BODY_READY: + response = connection->response; + if (connection->response_write_position < + connection->response->total_size) + { + uint64_t data_write_offset; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != response->crc) - MHD_mutex_lock_chk_ (&response->mutex); + if (NULL != response->crc) + MHD_mutex_lock_chk_ (&response->mutex); #endif - if (MHD_YES != try_ready_normal_body (connection)) - { - /* mutex was already unlocked by try_ready_normal_body */ - return; - } + if (MHD_YES != try_ready_normal_body (connection)) + { + /* mutex was already unlocked by try_ready_normal_body */ + return; + } #if defined(_MHD_HAVE_SENDFILE) - if (MHD_resp_sender_sendfile == connection->resp_sender) - { - ret = MHD_send_sendfile_ (connection); - } - else + if (MHD_resp_sender_sendfile == connection->resp_sender) + { + ret = MHD_send_sendfile_ (connection); + } + else #else /* ! _MHD_HAVE_SENDFILE */ - if (1) + if (1) #endif /* ! _MHD_HAVE_SENDFILE */ - { - data_write_offset = connection->response_write_position - - response->data_start; - if (data_write_offset > (uint64_t)SIZE_MAX) - MHD_PANIC (_("Data offset exceeds limit")); - ret = MHD_send_on_connection_ (connection, - &response->data - [(size_t)data_write_offset], - response->data_size - - (size_t)data_write_offset, - MHD_SSO_NO_CORK); + { + data_write_offset = connection->response_write_position + - response->data_start; + if (data_write_offset > (uint64_t) SIZE_MAX) + MHD_PANIC (_ ("Data offset exceeds limit")); + ret = MHD_send_on_connection_ (connection, + &response->data + [(size_t) data_write_offset], + response->data_size + - (size_t) data_write_offset, + MHD_SSO_NO_CORK); #if DEBUG_SEND_DATA - if (ret > 0) - fprintf (stderr, - _("Sent %d-byte DATA response: `%.*s'\n"), - (int) ret, - (int) ret, - &response->data[connection->response_write_position - - response->data_start]); + if (ret > 0) + fprintf (stderr, + _ ("Sent %d-byte DATA response: `%.*s'\n"), + (int) ret, + (int) ret, + &response->data[connection->response_write_position + - response->data_start]); #endif - } + } #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != response->crc) - MHD_mutex_unlock_chk_ (&response->mutex); + if (NULL != response->crc) + MHD_mutex_unlock_chk_ (&response->mutex); #endif - if (ret < 0) - { - if (MHD_ERR_AGAIN_ == ret) - return; -#ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _("Failed to send data in request for `%s'.\n"), - connection->url); -#endif - CONNECTION_CLOSE_ERROR (connection, - NULL); - return; - } - connection->response_write_position += ret; - MHD_update_last_activity_ (connection); - } - if (connection->response_write_position == - connection->response->total_size) - connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */ - return; - case MHD_CONNECTION_NORMAL_BODY_UNREADY: - mhd_assert (0); - return; - case MHD_CONNECTION_CHUNKED_BODY_READY: - ret = MHD_send_on_connection_ (connection, - &connection->write_buffer - [connection->write_buffer_send_offset], - connection->write_buffer_append_offset - - connection->write_buffer_send_offset, - MHD_SSO_NO_CORK); if (ret < 0) - { - if (MHD_ERR_AGAIN_ == ret) - return; - CONNECTION_CLOSE_ERROR (connection, - _("Connection was closed while sending response body.\n")); + { + if (MHD_ERR_AGAIN_ == ret) return; - } - connection->write_buffer_send_offset += ret; +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("Failed to send data in request for `%s'.\n"), + connection->url); +#endif + CONNECTION_CLOSE_ERROR (connection, + NULL); + return; + } + connection->response_write_position += ret; MHD_update_last_activity_ (connection); - if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state) + } + if (connection->response_write_position == + connection->response->total_size) + connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers */ + return; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + mhd_assert (0); + return; + case MHD_CONNECTION_CHUNKED_BODY_READY: + ret = MHD_send_on_connection_ (connection, + &connection->write_buffer + [connection->write_buffer_send_offset], + connection->write_buffer_append_offset + - connection->write_buffer_send_offset, + MHD_SSO_NO_CORK); + if (ret < 0) + { + if (MHD_ERR_AGAIN_ == ret) return; - check_write_done (connection, - (connection->response->total_size == - connection->response_write_position) ? - MHD_CONNECTION_BODY_SENT : - MHD_CONNECTION_CHUNKED_BODY_UNREADY); + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Connection was closed while sending response body.\n")); return; - case MHD_CONNECTION_CHUNKED_BODY_UNREADY: - case MHD_CONNECTION_BODY_SENT: - mhd_assert (0); + } + connection->write_buffer_send_offset += ret; + MHD_update_last_activity_ (connection); + if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state) return; - case MHD_CONNECTION_FOOTERS_SENDING: - ret = MHD_send_on_connection_ (connection, - &connection->write_buffer - [connection->write_buffer_send_offset], - connection->write_buffer_append_offset - - connection->write_buffer_send_offset, - MHD_SSO_HDR_CORK); - if (ret < 0) - { - if (MHD_ERR_AGAIN_ == ret) - return; - CONNECTION_CLOSE_ERROR (connection, - _("Connection was closed while sending response body.\n")); - return; - } - connection->write_buffer_send_offset += ret; - MHD_update_last_activity_ (connection); - if (MHD_CONNECTION_FOOTERS_SENDING != connection->state) + check_write_done (connection, + (connection->response->total_size == + connection->response_write_position) ? + MHD_CONNECTION_BODY_SENT : + MHD_CONNECTION_CHUNKED_BODY_UNREADY); + return; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + case MHD_CONNECTION_BODY_SENT: + mhd_assert (0); + return; + case MHD_CONNECTION_FOOTERS_SENDING: + ret = MHD_send_on_connection_ (connection, + &connection->write_buffer + [connection->write_buffer_send_offset], + connection->write_buffer_append_offset + - connection->write_buffer_send_offset, + MHD_SSO_HDR_CORK); + if (ret < 0) + { + if (MHD_ERR_AGAIN_ == ret) return; - check_write_done (connection, - MHD_CONNECTION_FOOTERS_SENT); - return; - case MHD_CONNECTION_FOOTERS_SENT: - mhd_assert (0); + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Connection was closed while sending response body.\n")); return; - case MHD_CONNECTION_CLOSED: + } + connection->write_buffer_send_offset += ret; + MHD_update_last_activity_ (connection); + if (MHD_CONNECTION_FOOTERS_SENDING != connection->state) return; + check_write_done (connection, + MHD_CONNECTION_FOOTERS_SENT); + return; + case MHD_CONNECTION_FOOTERS_SENT: + mhd_assert (0); + return; + case MHD_CONNECTION_CLOSED: + return; #ifdef UPGRADE_SUPPORT - case MHD_CONNECTION_UPGRADE: - mhd_assert (0); - return; + case MHD_CONNECTION_UPGRADE: + mhd_assert (0); + return; #endif /* UPGRADE_SUPPORT */ - default: - mhd_assert (0); - CONNECTION_CLOSE_ERROR (connection, - _("Internal error\n")); - break; - } + default: + mhd_assert (0); + CONNECTION_CLOSE_ERROR (connection, + _ ("Internal error\n")); + break; + } return; } @@ -3239,59 +3268,60 @@ cleanup_connection (struct MHD_Connection *connection) return; /* Prevent double cleanup. */ connection->in_cleanup = true; if (NULL != connection->response) - { - MHD_destroy_response (connection->response); - connection->response = NULL; - } + { + MHD_destroy_response (connection->response); + connection->response = NULL; + } #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); #endif if (connection->suspended) - { - DLL_remove (daemon->suspended_connections_head, - daemon->suspended_connections_tail, - connection); - connection->suspended = false; - } + { + DLL_remove (daemon->suspended_connections_head, + daemon->suspended_connections_tail, + connection); + connection->suspended = false; + } else + { + if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) { - if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) - { - if (connection->connection_timeout == daemon->connection_timeout) - XDLL_remove (daemon->normal_timeout_head, - daemon->normal_timeout_tail, - connection); - else - XDLL_remove (daemon->manual_timeout_head, - daemon->manual_timeout_tail, - connection); - } - DLL_remove (daemon->connections_head, - daemon->connections_tail, - connection); + if (connection->connection_timeout == daemon->connection_timeout) + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_remove (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); } + DLL_remove (daemon->connections_head, + daemon->connections_tail, + connection); + } DLL_insert (daemon->cleanup_head, - daemon->cleanup_tail, - connection); + daemon->cleanup_tail, + connection); connection->resuming = false; connection->in_idle = false; #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_(&daemon->cleanup_connection_mutex); + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); #endif if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + /* if we were at the connection limit before and are in + thread-per-connection mode, signal the main thread + to resume accepting connections */ + if ( (MHD_ITC_IS_VALID_ (daemon->itc)) && + (! MHD_itc_activate_ (daemon->itc, "c")) ) { - /* if we were at the connection limit before and are in - thread-per-connection mode, signal the main thread - to resume accepting connections */ - if ( (MHD_ITC_IS_VALID_ (daemon->itc)) && - (! MHD_itc_activate_ (daemon->itc, "c")) ) - { #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Failed to signal end of connection via inter-thread communication channel")); + MHD_DLOG (daemon, + _ ( + "Failed to signal end of connection via inter-thread communication channel")); #endif - } } + } } @@ -3315,471 +3345,475 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) connection->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; - } + 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; + } #endif /* HTTPS_SUPPORT */ #if DEBUG_STATES - MHD_DLOG (daemon, - _("In function %s handling connection at state: %s\n"), - __FUNCTION__, - MHD_state_to_string (connection->state)); + MHD_DLOG (daemon, + _ ("In function %s handling connection at state: %s\n"), + __FUNCTION__, + MHD_state_to_string (connection->state)); #endif - switch (connection->state) + switch (connection->state) + { + case MHD_CONNECTION_INIT: + line = get_next_header_line (connection, + &line_len); + /* Check for empty string, as we might want + to tolerate 'spurious' empty lines; also + NULL means we didn't get a full line yet; + line is not 0-terminated here. */ + if ( (NULL == line) || + (0 == line[0]) ) + { + if (MHD_CONNECTION_INIT != connection->state) + continue; + if (connection->read_closed) { - case MHD_CONNECTION_INIT: - line = get_next_header_line (connection, - &line_len); - /* Check for empty string, as we might want - to tolerate 'spurious' empty lines; also - NULL means we didn't get a full line yet; - line is not 0-terminated here. */ - if ( (NULL == line) || - (0 == line[0]) ) - { - if (MHD_CONNECTION_INIT != connection->state) - continue; - if (connection->read_closed) - { - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - break; - } - if (MHD_NO == parse_initial_message_line (connection, - line, - line_len)) - CONNECTION_CLOSE_ERROR (connection, - NULL); - else - connection->state = MHD_CONNECTION_URL_RECEIVED; + CONNECTION_CLOSE_ERROR (connection, + NULL); continue; - case MHD_CONNECTION_URL_RECEIVED: - line = get_next_header_line (connection, - NULL); - if (NULL == line) - { - if (MHD_CONNECTION_URL_RECEIVED != connection->state) - continue; - if (connection->read_closed) - { - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - break; - } - if (0 == line[0]) - { - connection->state = MHD_CONNECTION_HEADERS_RECEIVED; - connection->header_size = (size_t) (line - connection->read_buffer); - continue; - } - if (MHD_NO == process_header_line (connection, - line)) - { - transmit_error_response (connection, - MHD_HTTP_BAD_REQUEST, - REQUEST_MALFORMED); - break; - } - connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; + } + break; + } + if (MHD_NO == parse_initial_message_line (connection, + line, + line_len)) + CONNECTION_CLOSE_ERROR (connection, + NULL); + else + connection->state = MHD_CONNECTION_URL_RECEIVED; + continue; + case MHD_CONNECTION_URL_RECEIVED: + line = get_next_header_line (connection, + NULL); + if (NULL == line) + { + if (MHD_CONNECTION_URL_RECEIVED != connection->state) continue; - case MHD_CONNECTION_HEADER_PART_RECEIVED: - line = get_next_header_line (connection, - NULL); - if (NULL == line) - { - if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) - continue; - if (connection->read_closed) - { - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - break; - } - if (MHD_NO == - process_broken_line (connection, - line, - MHD_HEADER_KIND)) - continue; - if (0 == line[0]) - { - connection->state = MHD_CONNECTION_HEADERS_RECEIVED; - connection->header_size = (size_t) (line - connection->read_buffer); - continue; - } + if (connection->read_closed) + { + CONNECTION_CLOSE_ERROR (connection, + NULL); continue; - case MHD_CONNECTION_HEADERS_RECEIVED: - parse_connection_headers (connection); - if (MHD_CONNECTION_CLOSED == connection->state) - continue; - connection->state = MHD_CONNECTION_HEADERS_PROCESSED; - if (connection->suspended) - break; + } + break; + } + if (0 == line[0]) + { + connection->state = MHD_CONNECTION_HEADERS_RECEIVED; + connection->header_size = (size_t) (line - connection->read_buffer); + continue; + } + if (MHD_NO == process_header_line (connection, + line)) + { + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, + REQUEST_MALFORMED); + break; + } + connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; + continue; + case MHD_CONNECTION_HEADER_PART_RECEIVED: + line = get_next_header_line (connection, + NULL); + if (NULL == line) + { + if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) continue; - case MHD_CONNECTION_HEADERS_PROCESSED: - call_connection_handler (connection); /* first call */ - if (MHD_CONNECTION_CLOSED == connection->state) - continue; - if (need_100_continue (connection)) - { - connection->state = MHD_CONNECTION_CONTINUE_SENDING; - break; - } - if ( (NULL != connection->response) && - ( (MHD_str_equal_caseless_ (connection->method, - MHD_HTTP_METHOD_POST)) || - (MHD_str_equal_caseless_ (connection->method, - MHD_HTTP_METHOD_PUT))) ) - { - /* we refused (no upload allowed!) */ - connection->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; - if (connection->suspended) - break; + if (connection->read_closed) + { + CONNECTION_CLOSE_ERROR (connection, + NULL); continue; - case MHD_CONNECTION_CONTINUE_SENDING: - if (connection->continue_message_write_offset == - MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) - { - connection->state = MHD_CONNECTION_CONTINUE_SENT; - continue; - } - break; - case MHD_CONNECTION_CONTINUE_SENT: - if (0 != connection->read_buffer_offset) - { - process_request_body (connection); /* loop call */ - if (MHD_CONNECTION_CLOSED == connection->state) - continue; - } - if ( (0 == connection->remaining_upload_size) || - ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) && - (0 == connection->read_buffer_offset) && - (connection->read_closed) ) ) - { - if ( (connection->have_chunked_upload) && - (! connection->read_closed) ) - connection->state = MHD_CONNECTION_BODY_RECEIVED; - else - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; - if (connection->suspended) - break; - continue; - } + } + break; + } + if (MHD_NO == + process_broken_line (connection, + line, + MHD_HEADER_KIND)) + continue; + if (0 == line[0]) + { + connection->state = MHD_CONNECTION_HEADERS_RECEIVED; + connection->header_size = (size_t) (line - connection->read_buffer); + continue; + } + continue; + case MHD_CONNECTION_HEADERS_RECEIVED: + parse_connection_headers (connection); + if (MHD_CONNECTION_CLOSED == connection->state) + continue; + connection->state = MHD_CONNECTION_HEADERS_PROCESSED; + if (connection->suspended) + break; + continue; + case MHD_CONNECTION_HEADERS_PROCESSED: + call_connection_handler (connection); /* first call */ + if (MHD_CONNECTION_CLOSED == connection->state) + continue; + if (need_100_continue (connection)) + { + connection->state = MHD_CONNECTION_CONTINUE_SENDING; + break; + } + if ( (NULL != connection->response) && + ( (MHD_str_equal_caseless_ (connection->method, + MHD_HTTP_METHOD_POST)) || + (MHD_str_equal_caseless_ (connection->method, + MHD_HTTP_METHOD_PUT))) ) + { + /* we refused (no upload allowed!) */ + connection->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; + if (connection->suspended) + break; + continue; + case MHD_CONNECTION_CONTINUE_SENDING: + if (connection->continue_message_write_offset == + MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)) + { + connection->state = MHD_CONNECTION_CONTINUE_SENT; + continue; + } + break; + case MHD_CONNECTION_CONTINUE_SENT: + if (0 != connection->read_buffer_offset) + { + process_request_body (connection); /* loop call */ + if (MHD_CONNECTION_CLOSED == connection->state) + continue; + } + if ( (0 == connection->remaining_upload_size) || + ( (MHD_SIZE_UNKNOWN == connection->remaining_upload_size) && + (0 == connection->read_buffer_offset) && + (connection->read_closed) ) ) + { + if ( (connection->have_chunked_upload) && + (! connection->read_closed) ) + connection->state = MHD_CONNECTION_BODY_RECEIVED; + else + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + if (connection->suspended) break; - case MHD_CONNECTION_BODY_RECEIVED: - line = get_next_header_line (connection, - NULL); - if (NULL == line) - { - if (connection->state != MHD_CONNECTION_BODY_RECEIVED) - continue; - if (connection->read_closed) - { - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - break; - } - if (0 == line[0]) - { - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; - if (connection->suspended) - break; - continue; - } - if (MHD_NO == process_header_line (connection, - line)) - { - transmit_error_response (connection, - MHD_HTTP_BAD_REQUEST, - REQUEST_MALFORMED); - break; - } - connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; + continue; + } + break; + case MHD_CONNECTION_BODY_RECEIVED: + line = get_next_header_line (connection, + NULL); + if (NULL == line) + { + if (connection->state != MHD_CONNECTION_BODY_RECEIVED) continue; - case MHD_CONNECTION_FOOTER_PART_RECEIVED: - line = get_next_header_line (connection, - NULL); - if (NULL == line) - { - if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) - continue; - if (connection->read_closed) - { - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - break; - } - if (MHD_NO == - process_broken_line (connection, - line, - MHD_FOOTER_KIND)) - continue; - if (0 == line[0]) - { - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; - if (connection->suspended) - break; - continue; - } + if (connection->read_closed) + { + CONNECTION_CLOSE_ERROR (connection, + NULL); continue; - case MHD_CONNECTION_FOOTERS_RECEIVED: - call_connection_handler (connection); /* "final" call */ - if (connection->state == MHD_CONNECTION_CLOSED) - continue; - if (NULL == connection->response) - break; /* try again next time */ - if (MHD_NO == build_header_response (connection)) - { - /* oops - close! */ - CONNECTION_CLOSE_ERROR (connection, - _("Closing connection (failed to create response header)\n")); - continue; - } - connection->state = MHD_CONNECTION_HEADERS_SENDING; + } + break; + } + if (0 == line[0]) + { + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + if (connection->suspended) break; - case MHD_CONNECTION_HEADERS_SENDING: - /* no default action */ + continue; + } + if (MHD_NO == process_header_line (connection, + line)) + { + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, + REQUEST_MALFORMED); + break; + } + connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; + continue; + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + line = get_next_header_line (connection, + NULL); + if (NULL == line) + { + if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) + continue; + if (connection->read_closed) + { + CONNECTION_CLOSE_ERROR (connection, + NULL); + continue; + } + break; + } + if (MHD_NO == + process_broken_line (connection, + line, + MHD_FOOTER_KIND)) + continue; + if (0 == line[0]) + { + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + if (connection->suspended) break; - case MHD_CONNECTION_HEADERS_SENT: - /* Some clients may take some actions right after header receive */ - if (socket_flush_possible (connection)) - socket_start_no_buffering_flush (connection); /* REMOVE: Dead */ + continue; + } + continue; + case MHD_CONNECTION_FOOTERS_RECEIVED: + call_connection_handler (connection); /* "final" call */ + if (connection->state == MHD_CONNECTION_CLOSED) + continue; + if (NULL == connection->response) + break; /* try again next time */ + if (MHD_NO == build_header_response (connection)) + { + /* oops - close! */ + CONNECTION_CLOSE_ERROR (connection, + _ ( + "Closing connection (failed to create response header)\n")); + continue; + } + connection->state = MHD_CONNECTION_HEADERS_SENDING; + break; + case MHD_CONNECTION_HEADERS_SENDING: + /* no default action */ + break; + case MHD_CONNECTION_HEADERS_SENT: + /* Some clients may take some actions right after header receive */ + if (socket_flush_possible (connection)) + socket_start_no_buffering_flush (connection); /* REMOVE: Dead */ #ifdef UPGRADE_SUPPORT - if (NULL != connection->response->upgrade_handler) - { - connection->state = MHD_CONNECTION_UPGRADE; - /* This connection is "upgraded". Pass socket to application. */ - if (MHD_YES != - MHD_response_execute_upgrade_ (connection->response, - connection)) - { - /* upgrade failed, fail hard */ - CONNECTION_CLOSE_ERROR (connection, - NULL); - continue; - } - /* Response is not required anymore for this connection. */ - { - struct MHD_Response * const resp = connection->response; - - connection->response = NULL; - MHD_destroy_response (resp); - } - continue; - } + if (NULL != connection->response->upgrade_handler) + { + connection->state = MHD_CONNECTION_UPGRADE; + /* This connection is "upgraded". Pass socket to application. */ + if (MHD_YES != + MHD_response_execute_upgrade_ (connection->response, + connection)) + { + /* upgrade failed, fail hard */ + CONNECTION_CLOSE_ERROR (connection, + NULL); + continue; + } + /* Response is not required anymore for this connection. */ + { + struct MHD_Response *const resp = connection->response; + + connection->response = NULL; + MHD_destroy_response (resp); + } + continue; + } #endif /* UPGRADE_SUPPORT */ - if (connection->have_chunked_upload) - connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; - else - connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; - continue; - case MHD_CONNECTION_NORMAL_BODY_READY: - /* nothing to do here */ - break; - case MHD_CONNECTION_NORMAL_BODY_UNREADY: + if (connection->have_chunked_upload) + connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; + else + connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; + continue; + case MHD_CONNECTION_NORMAL_BODY_READY: + /* nothing to do here */ + break; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != connection->response->crc) - MHD_mutex_lock_chk_ (&connection->response->mutex); + if (NULL != connection->response->crc) + MHD_mutex_lock_chk_ (&connection->response->mutex); #endif - if (0 == connection->response->total_size) - { + if (0 == connection->response->total_size) + { #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); + if (NULL != connection->response->crc) + MHD_mutex_unlock_chk_ (&connection->response->mutex); #endif - connection->state = MHD_CONNECTION_BODY_SENT; - continue; - } - if (MHD_YES == try_ready_normal_body (connection)) - { + connection->state = MHD_CONNECTION_BODY_SENT; + continue; + } + if (MHD_YES == try_ready_normal_body (connection)) + { #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); + if (NULL != connection->response->crc) + MHD_mutex_unlock_chk_ (&connection->response->mutex); #endif - connection->state = MHD_CONNECTION_NORMAL_BODY_READY; - /* Buffering for flushable socket was already enabled*/ + connection->state = MHD_CONNECTION_NORMAL_BODY_READY; + /* Buffering for flushable socket was already enabled*/ - break; - } - /* mutex was already unlocked by "try_ready_normal_body */ - /* not ready, no socket action */ - break; - case MHD_CONNECTION_CHUNKED_BODY_READY: - /* nothing to do here */ - break; - case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + break; + } + /* mutex was already unlocked by "try_ready_normal_body */ + /* not ready, no socket action */ + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + /* nothing to do here */ + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != connection->response->crc) - MHD_mutex_lock_chk_ (&connection->response->mutex); + if (NULL != connection->response->crc) + MHD_mutex_lock_chk_ (&connection->response->mutex); #endif - if ( (0 == connection->response->total_size) || - (connection->response_write_position == - connection->response->total_size) ) - { + if ( (0 == connection->response->total_size) || + (connection->response_write_position == + connection->response->total_size) ) + { #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); + if (NULL != connection->response->crc) + MHD_mutex_unlock_chk_ (&connection->response->mutex); #endif - connection->state = MHD_CONNECTION_BODY_SENT; - continue; - } - if (MHD_YES == try_ready_chunked_body (connection)) - { + connection->state = MHD_CONNECTION_BODY_SENT; + continue; + } + if (MHD_YES == try_ready_chunked_body (connection)) + { #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); + if (NULL != connection->response->crc) + MHD_mutex_unlock_chk_ (&connection->response->mutex); #endif - connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; - /* Buffering for flushable socket was already enabled */ + connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; + /* Buffering for flushable socket was already enabled */ - continue; - } - /* mutex was already unlocked by try_ready_chunked_body */ - break; - case MHD_CONNECTION_BODY_SENT: - if (MHD_NO == build_header_response (connection)) - { - /* 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; - else - connection->state = MHD_CONNECTION_FOOTERS_SENDING; - continue; - case MHD_CONNECTION_FOOTERS_SENDING: - /* no default action */ - break; - case MHD_CONNECTION_FOOTERS_SENT: - if (MHD_HTTP_PROCESSING == connection->responseCode) - { - /* After this type of response, we allow sending another! */ - connection->state = MHD_CONNECTION_HEADERS_PROCESSED; - MHD_destroy_response (connection->response); - connection->response = NULL; - /* FIXME: maybe partially reset memory pool? */ - continue; - } - MHD_destroy_response (connection->response); - connection->response = NULL; - if ( (NULL != daemon->notify_completed) && - (connection->client_aware) ) - { - daemon->notify_completed (daemon->notify_completed_cls, - connection, - &connection->client_context, - MHD_REQUEST_TERMINATED_COMPLETED_OK); - } - connection->client_aware = false; - if ( (MHD_CONN_USE_KEEPALIVE != connection->keepalive) || - (connection->read_closed) ) - { - /* have to close for some reason */ - MHD_connection_close_ (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; - } - else - { - /* can try to keep-alive */ - - connection->version = NULL; - connection->state = MHD_CONNECTION_INIT; - connection->last = NULL; - connection->colon = NULL; - connection->header_size = 0; - connection->keepalive = MHD_CONN_KEEPALIVE_UNKOWN; - /* Reset the read buffer to the starting size, - preserving the bytes we have already read. */ - connection->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; - } - 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; - continue; - case MHD_CONNECTION_CLOSED: - cleanup_connection (connection); - connection->in_idle = false; - return MHD_NO; + continue; + } + /* mutex was already unlocked by try_ready_chunked_body */ + break; + case MHD_CONNECTION_BODY_SENT: + if (MHD_NO == build_header_response (connection)) + { + /* 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; + else + connection->state = MHD_CONNECTION_FOOTERS_SENDING; + continue; + case MHD_CONNECTION_FOOTERS_SENDING: + /* no default action */ + break; + case MHD_CONNECTION_FOOTERS_SENT: + if (MHD_HTTP_PROCESSING == connection->responseCode) + { + /* After this type of response, we allow sending another! */ + connection->state = MHD_CONNECTION_HEADERS_PROCESSED; + MHD_destroy_response (connection->response); + connection->response = NULL; + /* FIXME: maybe partially reset memory pool? */ + continue; + } + MHD_destroy_response (connection->response); + connection->response = NULL; + if ( (NULL != daemon->notify_completed) && + (connection->client_aware) ) + { + daemon->notify_completed (daemon->notify_completed_cls, + connection, + &connection->client_context, + MHD_REQUEST_TERMINATED_COMPLETED_OK); + } + connection->client_aware = false; + if ( (MHD_CONN_USE_KEEPALIVE != connection->keepalive) || + (connection->read_closed) ) + { + /* have to close for some reason */ + MHD_connection_close_ (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; + } + else + { + /* can try to keep-alive */ + + connection->version = NULL; + connection->state = MHD_CONNECTION_INIT; + connection->last = NULL; + connection->colon = NULL; + connection->header_size = 0; + connection->keepalive = MHD_CONN_KEEPALIVE_UNKOWN; + /* Reset the read buffer to the starting size, + preserving the bytes we have already read. */ + connection->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; + } + 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; + continue; + case MHD_CONNECTION_CLOSED: + cleanup_connection (connection); + connection->in_idle = false; + return MHD_NO; #ifdef UPGRADE_SUPPORT - case MHD_CONNECTION_UPGRADE: - connection->in_idle = false; - return MHD_YES; /* keep open */ + case MHD_CONNECTION_UPGRADE: + connection->in_idle = false; + return MHD_YES; /* keep open */ #endif /* UPGRADE_SUPPORT */ - default: - mhd_assert (0); - break; - } + default: + mhd_assert (0); break; } + break; + } if (! connection->suspended) + { + time_t timeout; + timeout = connection->connection_timeout; + if ( (0 != timeout) && + (timeout < (MHD_monotonic_sec_counter () + - connection->last_activity)) ) { - time_t timeout; - timeout = connection->connection_timeout; - if ( (0 != timeout) && - (timeout < (MHD_monotonic_sec_counter() - connection->last_activity)) ) - { - MHD_connection_close_ (connection, - MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); - connection->in_idle = false; - return MHD_YES; - } + MHD_connection_close_ (connection, + MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); + connection->in_idle = false; + return MHD_YES; } + } MHD_connection_update_event_loop_info (connection); ret = MHD_YES; #ifdef EPOLL_SUPPORT if ( (! connection->suspended) && (0 != (daemon->options & MHD_USE_EPOLL)) ) - { - ret = MHD_connection_epoll_update_ (connection); - } + { + ret = MHD_connection_epoll_update_ (connection); + } #endif /* EPOLL_SUPPORT */ connection->in_idle = false; return ret; @@ -3805,31 +3839,31 @@ MHD_connection_epoll_update_ (struct MHD_Connection *connection) (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) && ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) && (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) || - ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) && - (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) ) + ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) ) + { + /* add to epoll set */ + struct epoll_event event; + + event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; + event.data.ptr = connection; + if (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_ADD, + connection->socket_fd, + &event)) { - /* add to epoll set */ - struct epoll_event event; - - event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET; - event.data.ptr = connection; - if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_ADD, - connection->socket_fd, - &event)) - { #ifdef HAVE_MESSAGES - if (0 != (daemon->options & MHD_USE_ERROR_LOG)) - MHD_DLOG (daemon, - _("Call to epoll_ctl failed: %s\n"), - MHD_socket_last_strerr_ ()); + if (0 != (daemon->options & MHD_USE_ERROR_LOG)) + MHD_DLOG (daemon, + _ ("Call to epoll_ctl failed: %s\n"), + MHD_socket_last_strerr_ ()); #endif - connection->state = MHD_CONNECTION_CLOSED; - cleanup_connection (connection); - return MHD_NO; - } - connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; + connection->state = MHD_CONNECTION_CLOSED; + cleanup_connection (connection); + return MHD_NO; } + connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; + } return MHD_YES; } #endif @@ -3864,45 +3898,48 @@ MHD_get_connection_info (struct MHD_Connection *connection, ...) { switch (info_type) - { + { #ifdef HTTPS_SUPPORT - case MHD_CONNECTION_INFO_CIPHER_ALGO: - if (NULL == connection->tls_session) - return NULL; - connection->cipher = gnutls_cipher_get (connection->tls_session); - return (const union MHD_ConnectionInfo *) &connection->cipher; - case MHD_CONNECTION_INFO_PROTOCOL: - if (NULL == connection->tls_session) - return NULL; - connection->protocol = gnutls_protocol_get_version (connection->tls_session); - return (const union MHD_ConnectionInfo *) &connection->protocol; - case MHD_CONNECTION_INFO_GNUTLS_SESSION: - if (NULL == connection->tls_session) - return NULL; - return (const union MHD_ConnectionInfo *) &connection->tls_session; -#endif /* HTTPS_SUPPORT */ - case MHD_CONNECTION_INFO_CLIENT_ADDRESS: - return (const union MHD_ConnectionInfo *) &connection->addr; - case MHD_CONNECTION_INFO_DAEMON: - return (const union MHD_ConnectionInfo *) &connection->daemon; - case MHD_CONNECTION_INFO_CONNECTION_FD: - return (const union MHD_ConnectionInfo *) &connection->socket_fd; - case MHD_CONNECTION_INFO_SOCKET_CONTEXT: - return (const union MHD_ConnectionInfo *) &connection->socket_context; - case MHD_CONNECTION_INFO_CONNECTION_SUSPENDED: - connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO; - return (const union MHD_ConnectionInfo *) &connection->suspended_dummy; - case MHD_CONNECTION_INFO_CONNECTION_TIMEOUT: - connection->connection_timeout_dummy = (unsigned int)connection->connection_timeout; - return (const union MHD_ConnectionInfo *) &connection->connection_timeout_dummy; - case MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE: - if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) || - (MHD_CONNECTION_CLOSED == connection->state) ) - return NULL; /* invalid, too early! */ - return (const union MHD_ConnectionInfo *) &connection->header_size; - default: + case MHD_CONNECTION_INFO_CIPHER_ALGO: + if (NULL == connection->tls_session) return NULL; - } + connection->cipher = gnutls_cipher_get (connection->tls_session); + return (const union MHD_ConnectionInfo *) &connection->cipher; + case MHD_CONNECTION_INFO_PROTOCOL: + if (NULL == connection->tls_session) + return NULL; + connection->protocol = gnutls_protocol_get_version ( + connection->tls_session); + return (const union MHD_ConnectionInfo *) &connection->protocol; + case MHD_CONNECTION_INFO_GNUTLS_SESSION: + if (NULL == connection->tls_session) + return NULL; + return (const union MHD_ConnectionInfo *) &connection->tls_session; +#endif /* HTTPS_SUPPORT */ + case MHD_CONNECTION_INFO_CLIENT_ADDRESS: + return (const union MHD_ConnectionInfo *) &connection->addr; + case MHD_CONNECTION_INFO_DAEMON: + return (const union MHD_ConnectionInfo *) &connection->daemon; + case MHD_CONNECTION_INFO_CONNECTION_FD: + return (const union MHD_ConnectionInfo *) &connection->socket_fd; + case MHD_CONNECTION_INFO_SOCKET_CONTEXT: + return (const union MHD_ConnectionInfo *) &connection->socket_context; + case MHD_CONNECTION_INFO_CONNECTION_SUSPENDED: + connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO; + return (const union MHD_ConnectionInfo *) &connection->suspended_dummy; + case MHD_CONNECTION_INFO_CONNECTION_TIMEOUT: + connection->connection_timeout_dummy = (unsigned + int) connection->connection_timeout; + return (const union MHD_ConnectionInfo *) &connection-> + connection_timeout_dummy; + case MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE: + if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) || + (MHD_CONNECTION_CLOSED == connection->state) ) + return NULL; /* invalid, too early! */ + return (const union MHD_ConnectionInfo *) &connection->header_size; + default: + return NULL; + } } @@ -3917,56 +3954,56 @@ MHD_get_connection_info (struct MHD_Connection *connection, */ int MHD_set_connection_option (struct MHD_Connection *connection, - enum MHD_CONNECTION_OPTION option, - ...) + enum MHD_CONNECTION_OPTION option, + ...) { va_list ap; struct MHD_Daemon *daemon; daemon = connection->daemon; switch (option) - { - case MHD_CONNECTION_OPTION_TIMEOUT: - if (0 == connection->connection_timeout) - connection->last_activity = MHD_monotonic_sec_counter(); + { + case MHD_CONNECTION_OPTION_TIMEOUT: + if (0 == connection->connection_timeout) + connection->last_activity = MHD_monotonic_sec_counter (); #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); #endif - if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && - (! connection->suspended) ) - { - if (connection->connection_timeout == daemon->connection_timeout) - XDLL_remove (daemon->normal_timeout_head, - daemon->normal_timeout_tail, - connection); - else - XDLL_remove (daemon->manual_timeout_head, - daemon->manual_timeout_tail, - connection); - } - va_start (ap, option); - connection->connection_timeout = va_arg (ap, - unsigned int); - va_end (ap); - if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && - (! connection->suspended) ) - { - if (connection->connection_timeout == daemon->connection_timeout) - XDLL_insert (daemon->normal_timeout_head, - daemon->normal_timeout_tail, - connection); - else - XDLL_insert (daemon->manual_timeout_head, - daemon->manual_timeout_tail, - connection); - } + if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (! connection->suspended) ) + { + if (connection->connection_timeout == daemon->connection_timeout) + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_remove (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); + } + va_start (ap, option); + connection->connection_timeout = va_arg (ap, + unsigned int); + va_end (ap); + if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (! connection->suspended) ) + { + if (connection->connection_timeout == daemon->connection_timeout) + XDLL_insert (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_insert (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); + } #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); #endif - return MHD_YES; - default: - return MHD_NO; - } + return MHD_YES; + default: + return MHD_NO; + } } @@ -3992,7 +4029,7 @@ MHD_queue_response (struct MHD_Connection *connection, (NULL == response) || (NULL != connection->response) || ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) && - (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) ) + (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) ) return MHD_NO; daemon = connection->daemon; @@ -4001,36 +4038,38 @@ MHD_queue_response (struct MHD_Connection *connection, * response will be aborted now or on later stage. */ #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) - if ( (!connection->suspended) && + if ( (! connection->suspended) && (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && - (!MHD_thread_ID_match_current_(connection->pid.ID)) ) - { + (! MHD_thread_ID_match_current_ (connection->pid.ID)) ) + { #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Attempted to queue response on wrong thread!\n")); + MHD_DLOG (daemon, + _ ("Attempted to queue response on wrong thread!\n")); #endif - return MHD_NO; - } + return MHD_NO; + } #endif #ifdef UPGRADE_SUPPORT if ( (NULL != response->upgrade_handler) && (0 == (daemon->options & MHD_ALLOW_UPGRADE)) ) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n")); + MHD_DLOG (daemon, + _ ( + "Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n")); #endif - return MHD_NO; - } + return MHD_NO; + } if ( (MHD_HTTP_SWITCHING_PROTOCOLS != status_code) && (NULL != response->upgrade_handler) ) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - _("Application used invalid status code for 'upgrade' response!\n")); + MHD_DLOG (daemon, + _ ( + "Application used invalid status code for 'upgrade' response!\n")); #endif - return MHD_NO; - } + return MHD_NO; + } #endif /* UPGRADE_SUPPORT */ MHD_increment_response_rc (response); connection->response = response; @@ -4049,24 +4088,24 @@ MHD_queue_response (struct MHD_Connection *connection, (MHD_HTTP_OK > status_code) || (MHD_HTTP_NO_CONTENT == status_code) || (MHD_HTTP_NOT_MODIFIED == status_code) ) - { - /* if this is a "HEAD" request, or a status code for - which a body is not allowed, pretend that we - have already sent the full message body. */ - connection->response_write_position = response->total_size; - } + { + /* if this is a "HEAD" request, or a status code for + which a body is not allowed, pretend that we + have already sent the full message body. */ + connection->response_write_position = response->total_size; + } if ( (MHD_CONNECTION_HEADERS_PROCESSED == connection->state) && (NULL != connection->method) && ( (MHD_str_equal_caseless_ (connection->method, MHD_HTTP_METHOD_POST)) || - (MHD_str_equal_caseless_ (connection->method, + (MHD_str_equal_caseless_ (connection->method, MHD_HTTP_METHOD_PUT))) ) - { - /* response was queued "early", refuse to read body / footers or - further requests! */ - connection->read_closed = true; - connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; - } + { + /* response was queued "early", refuse to read body / footers or + further requests! */ + connection->read_closed = true; + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + } if (! connection->in_idle) (void) MHD_connection_handle_idle (connection); MHD_update_last_activity_ (connection);