From: Christopher Faulet Date: Wed, 7 Oct 2026 14:05:00 +0000 (+0200) Subject: BUG/MINOR: mux-h1: only rely on the client's method for bodyless responses X-Git-Tag: v3.5-dev10~134 X-Git-Url: https://git.kaiwu.me/$%7BISSUES%7D/static/gitweb.js?a=commitdiff_plain;h=786d7077b0d803167aca7410e1403fb55d4915ec;p=haproxy.git BUG/MINOR: mux-h1: only rely on the client's method for bodyless responses 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. --- 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 index 000000000..b1be6e566 --- /dev/null +++ b/reg-tests/http-messaging/h1_set_method_head_resp.vtc @@ -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 diff --git a/src/mux_h1.c b/src/mux_h1.c index 093a749f9..e1f087912 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -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