]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: Properly consume padding for DATA frames
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 7 May 2026 09:41:51 +0000 (11:41 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 7 May 2026 12:59:28 +0000 (14:59 +0200)
Since the commit 617592c9e ("MEDIUM: mux-h2: try to coalesce outgoing
WINDOW_UPDATE frames"), padding of DATA frames is no longer
consumed. Instead, this padidng is left in the demux buffer and used as the
header of the next frame. Because all bytes of the padding must be zero,
this lead to trigger a PROTOCOL_ERROR because haproxy erroneously thinks the
peer sent a DATA frame for the stream-id 0. It is true for a padding of 9
bytes or more, but similar issues may be exprienced with smaller padding.

Before the commit above, the padding was consumed in h2_process_demux to
restore the H2_CS_FRAME_H state at the end of the while loop processing
received frames.

However, it seems a bit strange to deal with the padding at this stage,
espcially because it is not obvious at all. So to fix the issue, the padding
is now consumed at the end of h2_frt_transfer_data(), inside "end_tranfer"
label. At the stage, we know all payload of the current DATA frame were
consumed and only the padding is still there, if any. We must only take care
to not consume more than available in the demux buffer. The padding may have
been partially received.

This patch should fix the issue #3354. It must be backported as far as 2.8.

src/mux_h2.c

index 4d1bef4b29d3cbe4b371398ac8667d5f3df3c193..c89d184a4705258a9f6d36c8395c508a683223fe 100644 (file)
@@ -6521,8 +6521,22 @@ try_again:
 
  end_transfer:
        /* here we're done with the frame, all the payload (except padding) was
-        * transferred.
+        * transferred. So let's consume the padding now.
+        *
+        * The padding may not have been fully received, so we must take care to
+        * not consume more than avaiable and eventually retry later.
         */
+       BUG_ON(h2c->dfl != h2c->dpl);
+       flen = b_data(&h2c->dbuf);
+       if (flen >  h2c->dfl)
+               flen = h2c->dfl;
+       b_del(&h2c->dbuf, flen);
+       h2c->dfl -= flen;
+       h2c->dpl -= flen;
+       h2c->rcvd_c += flen;
+       h2c->rcvd_s += flen;
+       if (h2c->dfl)
+               goto fail;
 
        if (!(h2s->flags & H2_SF_BODY_TUNNEL) && (h2c->dff & H2_F_DATA_END_STREAM)) {
                /* no more data are expected for this message. This add the EOM
@@ -6537,9 +6551,6 @@ try_again:
                }
        }
 
-       h2c->rcvd_c += h2c->dpl;
-       h2c->rcvd_s += h2c->dpl;
-       h2c->dpl = 0;
        h2c->st0 = H2_CS_FRAME_A; // send the corresponding window update
        htx_to_buf(htx, scbuf);
        TRACE_LEAVE(H2_EV_RX_FRAME|H2_EV_RX_DATA, h2c->conn, h2s);