From: Christopher Faulet Date: Wed, 7 Oct 2026 09:25:10 +0000 (+0200) Subject: BUG/MEDIUM: mux-h1: don't stall when draining more than a buffer of data X-Git-Tag: v3.5-dev10~147 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=f3aa948606e188a3b72dd0f1407fa91397aba2cf;p=haproxy.git BUG/MEDIUM: mux-h1: don't stall when draining more than a buffer of data When the H1 connection is in DRAINING state, h1_process() parses the input data using a stream rxbuf, which limits the amount of data consumed per call to a buffer minus the reserve. But the input buffer may contain more data than that. If no more data are received, nothing calls h1_process() again: the connection only subscribes for reads. The remaining data, the end of the request payload and possibly the next pipelined request, are then left unprocessed until the client timeout strikes, which kills the connection and the pipelined request is lost. Now, when data are still pending in the input buffer after a parsing pass in DRAINING state, the parsing is retried. This was introduced by commit 077906da1 ("MAJOR: mux-h1: Drain requests on client side before shut a stream down") in 3.0. It must be backported as far as 3.0. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index 63f363796..588eb5dc1 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -4296,6 +4296,7 @@ static int h1_process(struct h1c * h1c) if (h1s->sess->t_idle == -1) h1s->sess->t_idle = ns_to_ms(now_ns - h1s->sess->accept_ts) - h1s->sess->t_handshake; + retry_parsing: /* Get the stream rxbuf */ buf = h1_get_rxbuf(h1s); if (!buf) { @@ -4321,6 +4322,10 @@ static int h1_process(struct h1c * h1c) TRACE_ERROR("parsing error detected", H1_EV_H1C_WAKE|H1_EV_H1C_ERR); } else { + /* When draining, if input data remain to parse, retry the parsing now the rxbuf was emptied */ + if (h1c->state == H1_CS_DRAINING && (h1s->flags & H1S_F_RX_CONGESTED) && b_data(&h1c->ibuf)) + goto retry_parsing; + TRACE_STATE("Incomplete message, subscribing", H1_EV_RX_DATA|H1_EV_H1C_BLK|H1_EV_H1C_WAKE, h1c->conn, h1s); h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event); }