From: Christopher Faulet Date: Wed, 8 Jan 2025 16:42:44 +0000 (+0100) Subject: BUG/MEDIUM: h1-htx: Properly handle bodyless messages X-Git-Tag: v3.2-dev3~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b9cc361b35e66c1f2d26a9b703f8759f70cbc03c;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/src/h1_htx.c b/src/h1_htx.c index 0ae28318e5..611519c452 100644 --- a/src/h1_htx.c +++ b/src/h1_htx.c @@ -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: