]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: h2: make use of client-fin timeout after GOAWAY
authorWilly Tarreau <w@1wt.eu>
Fri, 24 Nov 2017 09:16:00 +0000 (10:16 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 24 Nov 2017 09:16:00 +0000 (10:16 +0100)
At the moment, the "client" timeout is used on an HTTP/2 connection once
it's idle with no active stream. With this patch, this timeout is replaced
by client-fin once a GOAWAY frame is sent. This closely matches what is
done on HTTP/1 since the principle is the same, as it indicates a willing
ness to quickly close a connection on which we don't expect to see anything
anymore.

doc/configuration.txt
src/mux_h2.c

index 809adebf941173e739d74f48fdbc2dfe56b1cfdc..27e370230510326bc3463a7eed19cd1b2a9ff0c0 100644 (file)
@@ -9826,7 +9826,9 @@ timeout client-fin <timeout>
   FIN_WAIT state for too long when clients do not disconnect cleanly. This
   problem is particularly common long connections such as RDP or WebSocket.
   Note that this timeout can override "timeout tunnel" when a connection shuts
-  down in one direction.
+  down in one direction. It is applied to idle HTTP/2 connections once a GOAWAY
+  frame was sent, often indicating an expectation that the connection quickly
+  ends.
 
   This parameter is specific to frontends, but can be specified once for all in
   "defaults" sections. By default it is not set, so half-closed connections
index 13d1bb316446b386274ccf282c140fb50bd955fb..90bd36e631ff83c31cdb39d4fd209d753873798d 100644 (file)
@@ -104,6 +104,7 @@ struct h2c {
        int32_t mfs; /* mux's max frame size */
 
        int timeout;        /* idle timeout duration in ticks */
+       int shut_timeout;   /* idle timeout duration in ticks after GOAWAY was sent */
        struct task *task;  /* timeout management task */
        struct eb_root streams_by_id; /* all active streams by their ID */
        struct list send_list; /* list of blocked streams requesting to send */
@@ -332,7 +333,10 @@ static int h2c_frt_init(struct connection *conn)
                goto fail;
 
 
-       h2c->timeout = sess->fe->timeout.client;
+       h2c->shut_timeout = h2c->timeout = sess->fe->timeout.client;
+       if (tick_isset(sess->fe->timeout.clientfin))
+               h2c->shut_timeout = sess->fe->timeout.clientfin;
+
        h2c->task = NULL;
        if (tick_isset(h2c->timeout)) {
                t = task_new(tid_bit);
@@ -2143,7 +2147,7 @@ static int h2_wake(struct connection *conn)
 
        if (h2c->task) {
                if (eb_is_empty(&h2c->streams_by_id)) {
-                       h2c->task->expire = tick_add(now_ms, h2c->timeout);
+                       h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
                        task_queue(h2c->task);
                }
                else
@@ -2175,6 +2179,7 @@ static struct task *h2_timeout_task(struct task *t)
        }
 
        /* try to send but no need to insist */
+       h2c->last_sid = h2c->max_id;
        if (h2c_send_goaway_error(h2c, NULL) <= 0)
                h2c->flags |= H2_CF_GOAWAY_FAILED;
 
@@ -2310,7 +2315,7 @@ static void h2_detach(struct conn_stream *cs)
                }
                else if (h2c->task) {
                        if (eb_is_empty(&h2c->streams_by_id)) {
-                               h2c->task->expire = tick_add(now_ms, h2c->timeout);
+                               h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
                                task_queue(h2c->task);
                        }
                        else