conn_data_send.c: refactored to make sure than new states are not missed

This commit is contained in:
Evgeny Grin (Karlson2k)
2024-09-30 01:59:44 +02:00
parent 756f361ab0
commit aa17193bca
+185 -154
View File
@@ -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)