From aa17193bcabc3abe30c6e81d21a9d34b2369f1b3 Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Mon, 30 Sep 2024 01:59:44 +0200 Subject: [PATCH] conn_data_send.c: refactored to make sure than new states are not missed --- src/mhd2/conn_data_send.c | 339 +++++++++++++++++++++----------------- 1 file changed, 185 insertions(+), 154 deletions(-) diff --git a/src/mhd2/conn_data_send.c b/src/mhd2/conn_data_send.c index 39cac988..b5732328 100644 --- a/src/mhd2/conn_data_send.c +++ b/src/mhd2/conn_data_send.c @@ -91,8 +91,9 @@ mhd_conn_data_send (struct MHD_Connection *restrict c) res = mhd_SOCKET_ERR_INTERNAL; - if (MHD_CONNECTION_CONTINUE_SENDING == c->state) + switch (c->state) { + case MHD_CONNECTION_CONTINUE_SENDING: res = mhd_send_data (c, http_100_continue_msg_len - c->continue_message_write_offset, @@ -102,177 +103,176 @@ mhd_conn_data_send (struct MHD_Connection *restrict c) &sent); if (mhd_SOCKET_ERR_NO_ERROR == res) c->continue_message_write_offset += sent; - } - else if (MHD_CONNECTION_HEADERS_SENDING == c->state) - { - struct MHD_Response *const restrict resp = c->rp.response; - const size_t wb_ready = c->write_buffer_append_offset - - c->write_buffer_send_offset; - mhd_assert (c->write_buffer_append_offset >= \ - c->write_buffer_send_offset); - mhd_assert (NULL != resp); - mhd_assert ((mhd_CONN_MUST_UPGRADE != c->conn_reuse) || \ - (! c->rp.props.send_reply_body)); - - // TODO: support body generating alongside with header sending - - if ((c->rp.props.send_reply_body) && - (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc)) + break; + case MHD_CONNECTION_HEADERS_SENDING: + if (1) { - /* Send response headers alongside the response body, if the body - * data is available. */ - mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype); - mhd_assert (! c->rp.props.chunked); + struct MHD_Response *const restrict resp = c->rp.response; + const size_t wb_ready = c->write_buffer_append_offset + - c->write_buffer_send_offset; + mhd_assert (c->write_buffer_append_offset >= \ + c->write_buffer_send_offset); + mhd_assert (NULL != resp); + mhd_assert ((mhd_CONN_MUST_UPGRADE != c->conn_reuse) || \ + (! c->rp.props.send_reply_body)); - res = mhd_send_hdr_and_body (c, - wb_ready, - c->write_buffer - + c->write_buffer_send_offset, - false, - resp->cntn_size, - (const char *) resp->cntn.buf, - true, - &sent); - } - else - { - /* This is response for HEAD request or reply body is not allowed - * for any other reason or reply body is dynamically generated. */ - /* Do not send the body data even if it's available. */ - res = mhd_send_hdr_and_body (c, - wb_ready, - c->write_buffer - + c->write_buffer_send_offset, - false, - 0, - NULL, - ((0 == resp->cntn_size) || - (! c->rp.props.send_reply_body)), - &sent); - } - if (mhd_SOCKET_ERR_NO_ERROR == res) - { - mhd_assert (MHD_CONNECTION_HEADERS_SENDING == c->state); + // TODO: support body generating alongside with header sending - if (sent > wb_ready) + if ((c->rp.props.send_reply_body) && + (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc)) { - /* The complete header and some response data have been sent, - * update both offsets. */ - mhd_assert (0 == c->rp.rsp_cntn_read_pos); + /* Send response headers alongside the response body, if the body + * data is available. */ + mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype); mhd_assert (! c->rp.props.chunked); - mhd_assert (c->rp.props.send_reply_body); - c->state = MHD_CONNECTION_UNCHUNKED_BODY_READY; - c->write_buffer_send_offset += wb_ready; - c->rp.rsp_cntn_read_pos = sent - wb_ready; - if (c->rp.rsp_cntn_read_pos == c->rp.response->cntn_size) - c->state = MHD_CONNECTION_FULL_REPLY_SENT; + + res = mhd_send_hdr_and_body (c, + wb_ready, + c->write_buffer + + c->write_buffer_send_offset, + false, + resp->cntn_size, + (const char *) resp->cntn.buf, + true, + &sent); } else { - c->write_buffer_send_offset += sent; - // TODO: move it to data processing - check_write_done (c, - MHD_CONNECTION_HEADERS_SENT); + /* This is response for HEAD request or reply body is not allowed + * for any other reason or reply body is dynamically generated. */ + /* Do not send the body data even if it's available. */ + res = mhd_send_hdr_and_body (c, + wb_ready, + c->write_buffer + + c->write_buffer_send_offset, + false, + 0, + NULL, + ((0 == resp->cntn_size) || + (! c->rp.props.send_reply_body)), + &sent); } - - - } - - } - else if ((MHD_CONNECTION_UNCHUNKED_BODY_READY == c->state) || - (MHD_CONNECTION_CHUNKED_BODY_READY == c->state)) - { - struct MHD_Response *const restrict resp = c->rp.response; - mhd_assert (c->rp.props.send_reply_body); - mhd_assert (c->rp.rsp_cntn_read_pos < resp->cntn_size); - mhd_assert ((MHD_CONNECTION_CHUNKED_BODY_READY != c->state) || \ - (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc)); - if (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc) - { - mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype); - - res = mhd_send_data (c, - c->rp.rsp_cntn_read_pos - resp->cntn_size, - (const char *) resp->cntn.buf - + c->rp.rsp_cntn_read_pos, - true, - &sent); - } - else if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc) - { - mhd_assert (c->write_buffer_append_offset > \ - c->write_buffer_send_offset); - - res = mhd_send_data (c, - c->write_buffer_append_offset - - c->write_buffer_send_offset, - c->write_buffer + c->write_buffer_send_offset, - true, - &sent); - } - else if (mhd_REPLY_CNTN_LOC_IOV == c->rp.cntn_loc) - { - mhd_assert (mhd_RESPONSE_CONTENT_DATA_IOVEC == resp->cntn_dtype); - - res = mhd_send_iovec (c, - &c->rp.resp_iov, - true, - &sent); - } -#if defined(MHD_USE_SENDFILE) - else if (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc) - { - mhd_assert (mhd_RESPONSE_CONTENT_DATA_FILE == resp->cntn_dtype); - - res = mhd_send_sendfile (c, &sent); - if (mhd_SOCKET_ERR_INTR == res) + if (mhd_SOCKET_ERR_NO_ERROR == res) { - if (! c->rp.response->cntn.file.use_sf) - { /* Switch to filereader */ + mhd_assert (MHD_CONNECTION_HEADERS_SENDING == c->state); + + if (sent > wb_ready) + { + /* The complete header and some response data have been sent, + * update both offsets. */ + mhd_assert (0 == c->rp.rsp_cntn_read_pos); mhd_assert (! c->rp.props.chunked); - c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_CONN_BUF; - c->state = MHD_CONNECTION_UNCHUNKED_BODY_UNREADY; + mhd_assert (c->rp.props.send_reply_body); + c->state = MHD_CONNECTION_UNCHUNKED_BODY_READY; + c->write_buffer_send_offset += wb_ready; + c->rp.rsp_cntn_read_pos = sent - wb_ready; + if (c->rp.rsp_cntn_read_pos == c->rp.response->cntn_size) + c->state = MHD_CONNECTION_FULL_REPLY_SENT; + } + else + { + c->write_buffer_send_offset += sent; + // TODO: move it to data processing + check_write_done (c, + MHD_CONNECTION_HEADERS_SENT); } } } -#endif /* MHD_USE_SENDFILE */ - else + break; + case MHD_CONNECTION_UNCHUNKED_BODY_READY: + case MHD_CONNECTION_CHUNKED_BODY_READY: + if (1) { - mhd_assert (0 && "Should be unreachable"); - res = mhd_SOCKET_ERR_INTERNAL; - } - - if (mhd_SOCKET_ERR_NO_ERROR == res) - { - if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc) + struct MHD_Response *const restrict resp = c->rp.response; + mhd_assert (c->rp.props.send_reply_body); + mhd_assert (c->rp.rsp_cntn_read_pos < resp->cntn_size); + mhd_assert ((MHD_CONNECTION_CHUNKED_BODY_READY != c->state) || \ + (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc)); + if (mhd_REPLY_CNTN_LOC_RESP_BUF == c->rp.cntn_loc) { - enum MHD_CONNECTION_STATE next_state; - c->write_buffer_send_offset += sent; - // TODO: move it to data processing - if (MHD_CONNECTION_CHUNKED_BODY_READY == c->state) - next_state = - (c->rp.response->cntn_size == c->rp.rsp_cntn_read_pos) ? - MHD_CONNECTION_CHUNKED_BODY_SENT : - MHD_CONNECTION_CHUNKED_BODY_UNREADY; - else - next_state = - (c->rp.rsp_cntn_read_pos == resp->cntn_size) ? - MHD_CONNECTION_FULL_REPLY_SENT : - MHD_CONNECTION_UNCHUNKED_BODY_UNREADY; - check_write_done (c, - next_state); + mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype); + + res = mhd_send_data (c, + c->rp.rsp_cntn_read_pos - resp->cntn_size, + (const char *) resp->cntn.buf + + c->rp.rsp_cntn_read_pos, + true, + &sent); } + else if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc) + { + mhd_assert (c->write_buffer_append_offset > \ + c->write_buffer_send_offset); + + res = mhd_send_data (c, + c->write_buffer_append_offset + - c->write_buffer_send_offset, + c->write_buffer + c->write_buffer_send_offset, + true, + &sent); + } + else if (mhd_REPLY_CNTN_LOC_IOV == c->rp.cntn_loc) + { + mhd_assert (mhd_RESPONSE_CONTENT_DATA_IOVEC == resp->cntn_dtype); + + res = mhd_send_iovec (c, + &c->rp.resp_iov, + true, + &sent); + } + #if defined(MHD_USE_SENDFILE) + else if (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc) + { + mhd_assert (mhd_RESPONSE_CONTENT_DATA_FILE == resp->cntn_dtype); + + res = mhd_send_sendfile (c, &sent); + if (mhd_SOCKET_ERR_INTR == res) + { + if (! c->rp.response->cntn.file.use_sf) + { /* Switch to filereader */ + mhd_assert (! c->rp.props.chunked); + c->rp.cntn_loc = mhd_REPLY_CNTN_LOC_CONN_BUF; + c->state = MHD_CONNECTION_UNCHUNKED_BODY_UNREADY; + } + } + } + #endif /* MHD_USE_SENDFILE */ else { - c->rp.rsp_cntn_read_pos += sent; - if (c->rp.rsp_cntn_read_pos == resp->cntn_size) - c->state = MHD_CONNECTION_FULL_REPLY_SENT; + mhd_assert (0 && "Should be unreachable"); + res = mhd_SOCKET_ERR_INTERNAL; + } + + if (mhd_SOCKET_ERR_NO_ERROR == res) + { + if (mhd_REPLY_CNTN_LOC_CONN_BUF == c->rp.cntn_loc) + { + enum MHD_CONNECTION_STATE next_state; + c->write_buffer_send_offset += sent; + // TODO: move it to data processing + if (MHD_CONNECTION_CHUNKED_BODY_READY == c->state) + next_state = + (c->rp.response->cntn_size == c->rp.rsp_cntn_read_pos) ? + MHD_CONNECTION_CHUNKED_BODY_SENT : + MHD_CONNECTION_CHUNKED_BODY_UNREADY; + else + next_state = + (c->rp.rsp_cntn_read_pos == resp->cntn_size) ? + MHD_CONNECTION_FULL_REPLY_SENT : + MHD_CONNECTION_UNCHUNKED_BODY_UNREADY; + check_write_done (c, + next_state); + } + else + { + c->rp.rsp_cntn_read_pos += sent; + if (c->rp.rsp_cntn_read_pos == resp->cntn_size) + c->state = MHD_CONNECTION_FULL_REPLY_SENT; + } } } - - } - else if (MHD_CONNECTION_FOOTERS_SENDING == c->state) - { + break; + case MHD_CONNECTION_FOOTERS_SENDING: res = mhd_send_data (c, c->write_buffer_append_offset - c->write_buffer_send_offset, @@ -287,11 +287,42 @@ mhd_conn_data_send (struct MHD_Connection *restrict c) check_write_done (c, MHD_CONNECTION_FULL_REPLY_SENT); } - } - else - { + break; + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_REQ_LINE_RECEIVING: + case MHD_CONNECTION_REQ_LINE_RECEIVED: + case MHD_CONNECTION_REQ_HEADERS_RECEIVING: + case MHD_CONNECTION_HEADERS_RECEIVED: + case MHD_CONNECTION_HEADERS_PROCESSED: + case MHD_CONNECTION_BODY_RECEIVING: + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTERS_RECEIVING: + case MHD_CONNECTION_FOOTERS_RECEIVED: + case MHD_CONNECTION_FULL_REQ_RECEIVED: + case MHD_CONNECTION_REQ_RECV_FINISHED: + case MHD_CONNECTION_START_REPLY: + case MHD_CONNECTION_HEADERS_SENT: + case MHD_CONNECTION_UNCHUNKED_BODY_UNREADY: + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + case MHD_CONNECTION_CHUNKED_BODY_SENT: + case MHD_CONNECTION_FULL_REPLY_SENT: + case MHD_CONNECTION_PRE_CLOSING: + case MHD_CONNECTION_CLOSED: +#ifdef MHD_UPGRADE_SUPPORT + case MHD_CONNECTION_UPGRADE_HEADERS_SENDING: + case MHD_CONNECTION_UPGRADING: + case MHD_CONNECTION_UPGRADED: + case MHD_CONNECTION_UPGRADED_CLEANING: +#endif /* MHD_UPGRADE_SUPPORT */ mhd_assert (0 && "Should be unreachable"); + MHD_UNREACHABLE_; res = mhd_SOCKET_ERR_INTERNAL; + break; + default: + mhd_assert (0 && "Impossible value"); + MHD_UNREACHABLE_; + res = mhd_SOCKET_ERR_INTERNAL; + break; } if (mhd_SOCKET_ERR_NO_ERROR == res)