mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
conn_data_send.c: refactored to make sure than new states are not missed
This commit is contained in:
+185
-154
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user