]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: mux-h1: Handle keep-alive timeout for idle frontend connections
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 1 Dec 2020 10:42:53 +0000 (11:42 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 4 Dec 2020 13:41:48 +0000 (14:41 +0100)
IDLE frontend connections have no stream attached. The stream is only
created when new data are received, when the parsing of the next request
starts. Thus the keep-alive timeout, handled into the HTTP analysers, is not
considered while nothing is received. But this is especially when this
timeout must be considered. Concretely the http-keep-alive is ignored while
no data are received. Only the client timeout is used. It will only be
considered on incomplete requests, if the http-request timeout is not set.

To fix the bug, the http-keep-alive timeout must be handled at the mux
level, for IDLE frontend connection only.

This patch should fix the issue #984. It must be backported as far as
2.2. On prior versions, the stream is created earlier. So, it is not a
problem, except if this behavior changes of course (it was an optim of the
2.2, but don't remember the commit).

src/mux_h1.c

index 6e85b129bea6fca4b0c67cfb0662c941e47596aa..cc34bba3656df5398be9199c3e8ec8786e9cbbef 100644 (file)
@@ -468,15 +468,28 @@ static void h1_refresh_timeout(struct h1c *h1c)
                        h1c->task->expire = tick_add(now_ms, h1c->shut_timeout);
                        task_queue(h1c->task);
                        TRACE_DEVEL("refreshing connection's timeout (half-closed)", H1_EV_H1C_SEND, h1c->conn);
-               } else if ((!h1c->h1s && !conn_is_back(h1c->conn)) || b_data(&h1c->obuf)) {
-                       /* front connections waiting for a stream, as well as any connection with
-                        * pending data, need a timeout.
+               } else if (b_data(&h1c->obuf)) {
+                       /* any connection with pending data, need a timeout (server or client).
                         */
                        h1c->task->expire = tick_add(now_ms, ((h1c->flags & H1C_F_CS_SHUTW_NOW)
                                                              ? h1c->shut_timeout
                                                              : h1c->timeout));
                        task_queue(h1c->task);
                        TRACE_DEVEL("refreshing connection's timeout", H1_EV_H1C_SEND, h1c->conn);
+               } else if ((h1c->flags & (H1C_F_CS_IDLE|H1C_F_WAIT_NEXT_REQ)) && !conn_is_back(h1c->conn)) {
+                       /* front connections waiting for a stream need a timeout. client timeout by
+                        * default but http-keep-alive if defined
+                        */
+                       int timeout = h1c->timeout;
+
+                       if (h1c->flags & H1C_F_WAIT_NEXT_REQ)
+                               timeout = tick_first(timeout, h1c->px->timeout.httpka);
+
+                       h1c->task->expire = tick_add(now_ms, ((h1c->flags & H1C_F_CS_SHUTW_NOW)
+                                                             ? h1c->shut_timeout
+                                                             : timeout));
+                       task_queue(h1c->task);
+                       TRACE_DEVEL("refreshing connection's timeout", H1_EV_H1C_SEND, h1c->conn);
                }
        }
 }