BUG/MEDIUM: h1-htx: Properly handle bodyless messages

During h1 parsing, there are some postparsing checks to detect bodyless
messages and switch the parsing in DONE state. However, a case was not
properly handled. Responses to HEAD requests with a "transfer-encoding"
header. The response parser remained blocked waiting for the response body.

To fix the issue, the postparsing was sliglty modified. Instead of trying to
handle bodyless messages in a common way between the request and the
response, it is now performed in the dedicated postparsing functions. It is
easier to enumerate all cases, especially because there is already a test
for responses to HEAD requests.

This patch should fix the issue #2836. It must be backported as far as 2.9.
This commit is contained in:
Christopher Faulet 2025-01-08 17:42:44 +01:00
parent ca773e1a2a
commit b9cc361b35

View File

@ -176,10 +176,19 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
if (h1sl->rq.meth == HTTP_METH_CONNECT) {
h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
h1m->curr_len = h1m->body_len = 0;
h1m->state = H1_MSG_DONE;
htx->flags |= HTX_FL_EOM;
}
else if (h1sl->rq.meth == HTTP_METH_HEAD)
flags |= HTX_SL_F_BODYLESS_RESP;
else {
if (h1sl->rq.meth == HTTP_METH_HEAD)
flags |= HTX_SL_F_BODYLESS_RESP;
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
(h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) {
h1m->state = H1_MSG_DONE;
htx->flags |= HTX_FL_EOM;
}
}
flags |= h1m_htx_sl_flags(h1m);
@ -295,6 +304,8 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
h1m->flags |= H1_MF_XFER_LEN;
h1m->curr_len = h1m->body_len = 0;
h1m->state = H1_MSG_DONE;
htx->flags |= HTX_FL_EOM;
}
else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) ||
(code == 204) || (code == 304)) {
@ -303,10 +314,20 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
h1m->curr_len = h1m->body_len = 0;
if (code >= 200)
flags |= HTX_SL_F_BODYLESS_RESP;
h1m->state = H1_MSG_DONE;
htx->flags |= HTX_FL_EOM;
}
else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
/* Responses with a known body length. */
h1m->flags |= H1_MF_XFER_LEN;
else {
if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
/* Responses with a known body length. */
h1m->flags |= H1_MF_XFER_LEN;
}
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
(h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) {
h1m->state = H1_MSG_DONE;
htx->flags |= HTX_FL_EOM;
}
}
flags |= h1m_htx_sl_flags(h1m);
@ -402,13 +423,6 @@ int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
return ret;
}
/* Switch messages without any payload to DONE state */
if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN)) {
h1m->state = H1_MSG_DONE;
dsthtx->flags |= HTX_FL_EOM;
}
end:
return total;
error: