Le 26/03/2026 à 4:00 PM, Cody Ohlsen a écrit :
Hi,
I'd like to submit a patch for a bug we found in the H1 mux that adds ~200ms of
artificial latency to every HEAD response served over an HTTP/1.1 frontend under
many conditions.
We discovered this while debugging elevated latencies in a production proxy
chain
(S3 client -> HAProxy -> upstream origin) where HEAD requests were consistently
2-3x slower than GET requests despite being functionally simpler. The root cause
turned out to be MSG_MORE being incorrectly asserted on the sendmsg() call for
bodyless responses, causing the Linux kernel to cork the TCP segment for ~200ms
waiting for body data that never arrives.
The details and fix are in the patch below. Happy to answer any questions or
rework the patch as needed.
Hi Cody,
Thanks for the detailed analysis. The fix should be adapted a bit because we
cannot systematically remove H1C_F_CO_MSG_MORE flag when H1S_F_BODYLESS_RESP is
set. This last flag is also set on the server side, to be able to drop payload
for responses to HEAD requests. In attachment, my proposal to fix the issue.
You've done all the work. Do you want to adapt your patch ?
In addition, I proposed to flag it as a minor bug because it only concerns
bodyless responses with a payload, which should not happen.
On my side, I'm only able to reproduce the issue by changing the HEAD method
with an "http-request set-method GET" rule. Otherwise, the payload is ignored on
server side. So I'm curious. On your side, how are you able to trigger the issue ?
Regards,
--
Christopher Faulet
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 47cdfff2a..d165b88d6 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -4885,8 +4885,14 @@ static size_t h1_snd_buf(struct stconn *sc, struct buffer *buf, size_t count, in
/* Inherit some flags from the upper layer */
h1c->flags &= ~(H1C_F_CO_MSG_MORE|H1C_F_CO_STREAMER);
- if (flags & CO_SFL_MSG_MORE)
- h1c->flags |= H1C_F_CO_MSG_MORE;
+ if (flags & CO_SFL_MSG_MORE) {
+ /* Don't set H1C_F_CO_MSG_MORE when sending a bodyless response to client.
+ * We must do that if the response is not finished, regardless it a bodyless
+ * response, to be sure to send it ASAP.
+ */
+ if ((h1c->flags & H1C_F_IS_BACK) || !(h1s->flags & H1S_F_BODYLESS_RESP))
+ h1c->flags |= H1C_F_CO_MSG_MORE;
+ }
if (flags & CO_SFL_STREAMER)
h1c->flags |= H1C_F_CO_STREAMER;