Hi Christopher, Thanks for the review and the suggested adaptation. I will certainly resubmit the patch based on your proposal. I verified it would work in the situation we were describing, and it definitely makes sense and seems like an improvement. Appreciate your help.
However - I want to share additional context about our trigger scenario, since it may affect the severity assessment. Our setup is H1.1 frontend -> H2 backend (reverse proxy to an S3-style storage system). HEAD requests are used for metadata checks (content-length, object existence). I _think_ our H2 backend responds to HEAD with: 1. HEADERS frame (status + content-length, NO END_STREAM) 2. DATA frame (0 bytes payload, END_STREAM) I suspect that when these frames arrive in separate TCP segments (timing-dependent, but happens in practice on all requests), the H2 demux processes HEADERS first, notifies the stream (deferred via tasklet_wakeup_after), and process_stream forwards headers to the H1 frontend without EOM. At that point htx_expect_more() returns true, CO_SFL_MSG_MORE propagates to h1_snd_buf(), and the kernel corks for ~200ms waiting for body data that will never come. The fix (as well as your suggested fix) addresses this path. But I suspect no body payload is needed in the channel, just the absence of EOM when headers are first forwarded. For H1 backends, h1_postparse_res_hdrs() correctly sets HTX_FL_EOM during header parsing for HEAD responses, eliminating the timing dependency entirely. I _think_ this explains why reproduction requires set-method GET with H1 backends - the bug is latent with H1 (unless you add http-request set-method GET), but I think often (or perhaps always) active with H2 backend. I am wondering - in your test, did you happen to have an H2 backend? or an H1.1 backend. Thanks. Regardless, I verified that the adapted patch solves our issue - I really appreciate your help and feedback - thanks again! I will re-submit the updated patch as suggested. - Cody On Fri, Mar 27, 2026 at 1:25 AM Christopher Faulet <[email protected]> wrote: > > > 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 >

