]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: mux-h1: only rely on the client's method for bodyless responses
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 7 Oct 2026 14:05:00 +0000 (16:05 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 16 Oct 2026 17:10:27 +0000 (19:10 +0200)
When the response is emitted to the client, the H1 stream is marked as
expecting a bodyless response if the HTX start-line has the
HTX_SL_F_BODYLESS_RESP flag, which is set when the response is parsed on the
server side for a response to a HEAD request. But this is the method sent to
the server, which may differ from the client's one. With "http-request
set-method HEAD" applied to a GET request, the response received from the
server has no payload but carries a content-length, which is forwarded to
the client. Since the response was considered as bodyless on the client
side, the connection was kept alive instead of being closed, so the client
took the next response as the payload of the first one:

    HTTP/1.1 200 OK\r\ncontent-length: 1234\r\n\r\nHTTP/1.1 200 OK\r\n...

A response to a client's HEAD request is already marked as bodyless when the
request is parsed. So only 204 and 304 statuses must be considered
here. Then the connection is closed as for any response announcing a payload
that is not received.

A reg-test was added for this.

This should be backported as far as 3.0.

reg-tests/http-messaging/h1_set_method_head_resp.vtc [new file with mode: 0644]
src/mux_h1.c

diff --git a/reg-tests/http-messaging/h1_set_method_head_resp.vtc b/reg-tests/http-messaging/h1_set_method_head_resp.vtc
new file mode 100644 (file)
index 0000000..b1be6e5
--- /dev/null
@@ -0,0 +1,35 @@
+varnishtest "H1 response to a GET turned into a HEAD by the configuration"
+
+# When the request method is changed from GET to HEAD, the response from the
+# server has no payload but the client expects one: the connection must be
+# closed instead of being kept alive.
+
+feature ignore_unknown_macro
+
+server s1 {
+       rxreq
+       expect req.method == "HEAD"
+       txresp -nolen -hdr "Content-Length: 1234"
+} -start
+
+haproxy h1 -conf {
+    defaults
+        mode http
+        timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout client  "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout server  "${HAPROXY_TEST_TIMEOUT-5s}"
+
+    listen li1
+        bind "fd@${li1}"
+        http-request set-method HEAD
+        server s1 ${s1_addr}:${s1_port}
+} -start
+
+client c1 -connect ${h1_li1_sock} {
+       txreq -req GET -url /
+       rxresp -no_obj
+       expect resp.status == 200
+       expect resp.http.content-length == "1234"
+       expect resp.http.connection == "close"
+       expect_close
+} -run
index 093a749f9b2499f601199d5ceb36ab6a7805a9ee..e1f087912be2007323bed1f957feafc643b3d398 100644 (file)
@@ -2625,9 +2625,10 @@ static size_t h1_make_stline(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
                if (sl->flags & HTX_SL_F_XFER_ENC)
                        h1m->flags |= H1_MF_XFER_ENC;
        }
+
        if (h1s->status < 200)
                h1s->flags |= H1S_F_HAVE_O_CONN;
-       else if ((sl->flags & HTX_SL_F_BODYLESS_RESP) || h1s->status == 204 || h1s->status == 304)
+       else if (h1s->status == 204 || h1s->status == 304)
                h1s->flags |= H1S_F_BODYLESS_RESP;
 
        /* The chunked transfer-coding must not be used in a response to an