]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: Properly handle shutdowns when received with data
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 23 Apr 2021 10:25:18 +0000 (12:25 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 23 Apr 2021 13:42:39 +0000 (15:42 +0200)
The H2_CF_RCVD_SHUT flag is used to report a read0 was encountered. It is
used by the H2 mux to properly handle shutdowns. However, this flag is only
set when no data are received. If it is detected at the socket level when
some data are received, it is not handled. And because the event was
reported on the connection, any other read attempts are blocked. In this
case, we are unable to close the connection and release the mux
immediately. We must wait the mux timeout expires.

This patch should fix the issue #1231. It must be backported as far as 2.0.

src/mux_h2.c

index 35767b1853795f321333ccf996f2157f15add01f..950dc9e73a3f231b9eaed423d5f0d3e4210b8cd3 100644 (file)
@@ -3631,17 +3631,17 @@ static int h2_recv(struct h2c *h2c)
 
        ret = max ? conn->xprt->rcv_buf(conn, conn->xprt_ctx, buf, max, 0) : 0;
 
-       if (max && !ret) {
-               if (conn_xprt_read0_pending(h2c->conn)) {
-                       TRACE_DATA("received read0", H2_EV_H2C_RECV, h2c->conn);
-                       h2c->flags |= H2_CF_RCVD_SHUT;
-               } else if (h2_recv_allowed(h2c)) {
-                       TRACE_DATA("failed to receive data, subscribing", H2_EV_H2C_RECV, h2c->conn);
-                       conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_RECV, &h2c->wait_event);
-               }
+       if (max && !ret && h2_recv_allowed(h2c)) {
+               TRACE_DATA("failed to receive data, subscribing", H2_EV_H2C_RECV, h2c->conn);
+               conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_RECV, &h2c->wait_event);
        } else if (ret)
                TRACE_DATA("received data", H2_EV_H2C_RECV, h2c->conn, 0, 0, (void*)(long)ret);
 
+       if (conn_xprt_read0_pending(h2c->conn)) {
+               TRACE_DATA("received read0", H2_EV_H2C_RECV, h2c->conn);
+               h2c->flags |= H2_CF_RCVD_SHUT;
+       }
+
        if (!b_data(buf)) {
                h2_release_buf(h2c, &h2c->dbuf);
                TRACE_LEAVE(H2_EV_H2C_RECV, h2c->conn);