From dca161b7ba784c5f23af12537c46787492a4ed5a Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Wed, 8 Jan 2025 17:42:44 +0100 Subject: [PATCH] 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. (cherry picked from commit b9cc361b35e66c1f2d26a9b703f8759f70cbc03c) Signed-off-by: Christopher Faulet (cherry picked from commit becc475a16dea31037617baa91d1a5de01ccdd1e) Signed-off-by: Christopher Faulet --- src/h1_htx.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/h1_htx.c b/src/h1_htx.c index 6e2c67a..8d8aeee 100644 --- a/src/h1_htx.c +++ b/src/h1_htx.c @@ -174,10 +174,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); @@ -293,6 +302,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)) { @@ -301,10 +312,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); @@ -395,13 +416,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: -- 1.7.10.4