]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: Properly handle connection error during preface sending
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 30 Jun 2025 14:23:39 +0000 (16:23 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 30 Jun 2025 14:48:00 +0000 (16:48 +0200)
On backend side, an error at connection level during the preface sending was
not properly handled and could lead to a spinning loop on process_stream()
when the h2 stream on client side was blocked, for instance because of h2
flow control.

It appeared that no transition was perfromed from the PREFACE state to an
ERROR state on the H2 connection when an error occurred on the underlying
connection. In that case, the H2 connection was woken up in loop to try to
receive data, waking up the upper stream at the same time.

To fix the issue, an H2C error must be reported. Most state transitions are
handled by the demux function. So it is the right place to do so. First, in
PREFACE state and on server side, if an error occurred on the TCP
connection, an error is now reported on the H2 connection. REFUSED_STREAM
error code is used in that case. In addition, in that case, we also take
care to properly handle the connection shutdown.

This patch should fix the issue #3020. It must be backported to all stable
versions.

src/mux_h2.c

index c5f12fca3c9c4dfc0b4d1a214bacdf7c25931fd5..46c2d756cf1976438ef53739f04641b4b461d948 100644 (file)
@@ -4139,8 +4139,11 @@ static void h2_process_demux(struct h2c *h2c)
        if (unlikely(h2c->st0 < H2_CS_FRAME_H)) {
                if (h2c->st0 == H2_CS_PREFACE) {
                        TRACE_STATE("expecting preface", H2_EV_RX_PREFACE, h2c->conn);
-                       if (h2c->flags & H2_CF_IS_BACK)
-                               goto out;
+                       if (h2c->flags & H2_CF_IS_BACK) {
+                               if (h2c->conn->flags & CO_FL_ERROR)
+                                       h2c_error(h2c, H2_ERR_REFUSED_STREAM);
+                               goto done;
+                       }
 
                        if (unlikely(h2c_frt_recv_preface(h2c) <= 0)) {
                                /* RFC7540#3.5: a GOAWAY frame MAY be omitted */