From: Christopher Faulet Date: Tue, 29 Sep 2026 12:20:26 +0000 (+0200) Subject: BUG/MEDIUM: mux-h1: Don't subscribe for sends while output is blocked X-Git-Tag: v3.5-dev8~97 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=1e0478331e0b3dd84daf8e3be731e65411c2b1be;p=haproxy.git BUG/MEDIUM: mux-h1: Don't subscribe for sends while output is blocked A wakup loop could be experienced when tunnel data remained blocked on server side while waiting for the server response. Indeed, after sending a CONNECT request, the backend H1 mux blocks output processing until the server response decides whether a tunnel is established. Early tunnel data must remain pending during this time. When the stream connector subscribes for sends, h1_subscribe() normally subscribes to the transport too if the mux has no pending send subscription. However, when output processing is blocked, the socket may already be writable. The transport then wakes the mux, which wakes the stream, which cannot send and subscribes again. This causes a wakeup loop while waiting for the response. Do not add a transport send subscription while H1S_F_TX_BLK is set. Keep the stream's subscription so that the receive path can wake it when the tunnel is established, the rejection response completes, or EOS is reported. This does not prevent flushing the mux's output buffer: h1_send() maintains its own transport subscription for pending output. This should be backported to stable versions after a period of observation. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index a047749a4..385342635 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -4797,10 +4797,13 @@ static int h1_subscribe(struct stconn *sc, int event_type, struct wait_event *es * If the stconn attempts to subscribe, and the * mux isn't subscribed to the connection, then it * probably means the connection wasn't established - * yet, so we have to subscribe. + * yet, so we have to subscribe. However, if output + * processing is blocked waiting for the response, + * connection send readiness cannot unblock it. The + * receive path will wake the stream instead. */ h1c = h1s->h1c; - if (!(h1c->wait_event.events & SUB_RETRY_SEND)) + if (!(h1c->wait_event.events & SUB_RETRY_SEND) && !(h1s->flags & H1S_F_TX_BLK)) h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_SEND,