From: Olivier Houchard Date: Thu, 13 Aug 2026 18:58:18 +0000 (+0200) Subject: BUG/MEDIUM: mux-h1: close the connection on a short content-length X-Git-Tag: v3.5-dev6~77 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=75dd2c18dda29f9893574ef982ddf66de16f0408;p=haproxy.git BUG/MEDIUM: mux-h1: close the connection on a short content-length When a fixed-length message completes while curr_len is still non-zero, fewer bytes than announced were sent and the peer keeps waiting, so reusing the connection desynchronizes the next request (request smuggling). In h1s_destroy(), when either the request or the response still expects data, flag the connection on error, unless the message is legitimately bodyless. It is then closed instead of being returned to the idle pool. This can be reproduced with an H2 frontend, that will send less data than announced before sending an end of stream, to an H1 backend that replies before it received the whole request. This should be backported up to 2.8. Many thanks to truff@projet7.org for reporting the issue and providing an initial fix. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index 3d95f042f..eda34f252 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -1084,6 +1084,15 @@ static void h1s_destroy(struct h1s *h1s) H1C_F_IN_SALLOC|H1C_F_IN_SMAYALLOC| H1C_F_CO_MSG_MORE|H1C_F_CO_STREAMER); + /* + * If we reached the end of the stream and sent less bits than + * announced in Content-Length, we have little choice but to + * close the connection, as the peer will expect more. + */ + if (((h1s->req.flags & H1_MF_CLEN) && h1s->req.curr_len && !(h1s->flags & H1S_F_BODYLESS_REQ)) || + ((h1s->res.flags & H1_MF_CLEN) && h1s->res.curr_len && !(h1s->flags & H1S_F_BODYLESS_RESP))) + h1c->flags |= H1C_F_ERROR; + if (!(h1c->flags & (H1C_F_EOS|H1C_F_ERR_PENDING|H1C_F_ERROR|H1C_F_ABRT_PENDING|H1C_F_ABRTED)) && /* No error/read0/abort */ h1_is_alive(h1c) && /* still alive */ (h1s->flags & H1S_F_WANT_KAL) && /* K/A possible */