Skip to content

Commit

Permalink
BUG/MEDIUM: h1-htx: Properly handle bodyless messages
Browse files Browse the repository at this point in the history
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 haproxy#2836. It must be backported as far as 2.9.
  • Loading branch information
capflam committed Jan 8, 2025
1 parent ca773e1 commit b9cc361
Showing 1 changed file with 26 additions and 12 deletions.
38 changes: 26 additions & 12 deletions src/h1_htx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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)) {
Expand All @@ -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);
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit b9cc361

Please sign in to comment.