From bcc516267d5fd84edc8f86e582b5aaabca242807 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Tue, 1 Dec 2020 11:42:53 +0100 Subject: [PATCH] BUG/MINOR: mux-h1: Handle keep-alive timeout for idle frontend connections 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). (cherry picked from commit 268c92e2f8454569c1d2354f22cbe3187d548c3c) Signed-off-by: Christopher Faulet --- src/mux_h1.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/mux_h1.c b/src/mux_h1.c index 6e85b12..cc34bba 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -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); } } } -- 1.7.10.4