From: Christopher Faulet Date: Tue, 1 Dec 2020 10:42:53 +0000 (+0100) Subject: BUG/MINOR: mux-h1: Handle keep-alive timeout for idle frontend connections X-Git-Tag: v2.4-dev3~94 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=268c92e2f8454569c1d2354f22cbe3187d548c3c;p=thirdparty%2Fhaproxy.git 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). --- diff --git a/src/mux_h1.c b/src/mux_h1.c index 6e85b129be..cc34bba365 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); } } }