]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: mux-h1: don't spread-close idle conns with idle-close-on-response
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 7 Oct 2026 16:12:50 +0000 (18:12 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 16 Oct 2026 17:10:27 +0000 (19:10 +0200)
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.

src/mux_h1.c

index 3362d54c1108f4b25647f49b6dd10da3afe2a3f3..14dcea35d095f4fc57aae67666923e0492c9b67f 100644 (file)
@@ -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. */