]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: h1-htx: Properly handle bodyless messages
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jan 2025 16:42:44 +0000 (17:42 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jan 2025 17:20:26 +0000 (18:20 +0100)
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.

src/h1_htx.c

index 0ae28318e51d2810d1294a1ca407d4633a38b1e8..611519c45285c984928e65257e817542cf1442f8 100644 (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: