From: Christopher Faulet Date: Wed, 7 Oct 2026 16:12:50 +0000 (+0200) Subject: BUG/MEDIUM: mux-h1: don't spread-close idle conns with idle-close-on-response X-Git-Tag: v3.5-dev10~131 X-Git-Url: https://git.kaiwu.me/$%7BISSUES%7D/static/gitweb.js?a=commitdiff_plain;h=15be046d48fa06cd507f5e13714f112183f2174c;p=haproxy.git BUG/MEDIUM: mux-h1: don't spread-close idle conns with idle-close-on-response With "option idle-close-on-response", idle frontend connections must not be closed during a soft-stop: haproxy waits for the next request and closes the connection after responding to it, so that clients (or load balancers in front of haproxy) don't send a request on a connection being closed. h1_process() properly checks this option before closing an idle connection when the proxy is stopping. But when "close-spread-time" is set, h1_refresh_timeout() also considers idle frontend connections as candidates to be closed during the spread window, without checking the option, and shortens their timeout to a random point within the window. The timeout task then silently closes them. Let's not consider idle connections for the spread close when the option is set, as done in h1_process(). This should be backported as far as 2.6. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index 3362d54c1..14dcea35d 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -773,7 +773,13 @@ static void h1_refresh_timeout(struct h1c *h1c) /* idle front connections. */ h1c->task->expire = (tick_isset(h1c->idle_exp) ? h1c->idle_exp : tick_add_ifset(now_ms, h1c->timeout)); TRACE_DEVEL("refreshing connection's timeout (idle front h1c)", H1_EV_H1C_SEND|H1_EV_H1C_RECV, h1c->conn); - is_idle_conn = 1; + /* With "option idle-close-on-response", idle connections + * must not be closed during a soft-stop, the next response + * will carry a "Connection: close" instead (see + * h1_process()). + */ + if (!(h1c->px->options & PR_O_IDLE_CLOSE_RESP)) + is_idle_conn = 1; } else if (!(h1c->flags & H1C_F_IS_BACK) && (h1c->state != H1_CS_RUNNING)) { /* alive front connections waiting for a fully usable stream need a timeout. */