]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: also consider the fctl_list as pending data for the timeout
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 9 Nov 2026 12:29:50 +0000 (13:29 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 9 Nov 2026 12:33:52 +0000 (13:33 +0100)
The previous commit 87cf2a6b ("BUG/MEDIUM: mux-h2: consider the send list
as pending data for the timeout") was incomplete: a stream blocked on the
connection window (H2_SF_BLK_MFCTL) may also be orphaned by h2_detach()
after its stream connector left, in which case it sits on the fctl_list
and not on the send_list. Nothing of its frame was emitted yet (typically
an ES/RST frame via a WANT_SHUTW, or the remaining fast-forward bytes of
its iobuf), so br_data() on the mux buffer can be zero.

Such a connection was still considered idle and, on a backend connection,
was armed with no timeout at all while not being reusable: the orphan is
still in streams_by_id so it is not moved to the idle list either. It
then relied on the peer to send a WINDOW_UPDATE to ever wake up, which a
stalled peer never does.

The blocked_list is deliberately not considered: streams blocked on their
own stream window (H2_SF_BLK_SFCTL) are never orphaned by h2_detach(), so
this list is always empty once the last stream connector detached.

This matches the original h2c_may_expire() from before commit 3439583dd
("MEDIUM: mux-h2: slightly relax timeout management rules") which
considered both lists. mux-fcgi is not affected, it has no flow-control
window and no fctl list.

This could be backported as far as 2.6, along with 87cf2a6b.

Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
src/mux_h2.c

index 8293ea22726ece259856553c9b92549e489800b8..355ec837d28ab63c55b1c5bb7aef8cd76720a034 100644 (file)
@@ -1016,11 +1016,13 @@ static void h2c_update_timeout(struct h2c *h2c)
 
        if (h2c_may_expire(h2c)) {
                /* no more streams attached */
-               if (br_data(h2c->mbuf) || !LIST_ISEMPTY(&h2c->send_list)) {
+               if (br_data(h2c->mbuf) || !LIST_ISEMPTY(&h2c->send_list) ||
+                   !LIST_ISEMPTY(&h2c->fctl_list)) {
                        /* pending output data, or streams still queued to send
-                        * some (blocked on a missing mux buffer, their data
-                        * being still in their own iobuf): always the regular
-                        * data timeout.
+                        * some (blocked on a missing mux buffer or on the
+                        * connection window, their data or the frame to emit
+                        * being still pending): always the regular data
+                        * timeout.
                         */
                        h2c->task->expire = tick_add_ifset(now_ms, h2c->timeout);
                }