]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h3: reject client CANCEL_PUSH frame
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 26 May 2026 09:22:16 +0000 (11:22 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 26 May 2026 11:52:03 +0000 (13:52 +0200)
CANCEL_PUSH frames are silently ignored on both client and server sides.
However, as push support is not implemented by haproxy, clients are thus
forbidden to emit any of those frames.

Fix this by closing the connection with ID_ERROR when receiving a client
CANCEL_PUSH as a server. On client side, the frame is still silently
discarded.

This must be backported up to 2.6.

src/h3.c

index c412eb8ee030965ff8ea5ef254ce27e5c2384c9a..3e28c2e41f8feec3d2a745669c6d50bc3779d7f2 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -1955,6 +1955,25 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
                                h3s->st_req = H3S_ST_REQ_TRAILERS;
                        }
                        break;
+               case H3_FT_CANCEL_PUSH:
+                       if (!conn_is_back(qcs->qcc->conn)) {
+                               /* RFC 9114 7.2.3. CANCEL_PUSH
+                                *
+                                * If a server receives a CANCEL_PUSH frame for a push ID
+                                * that has not yet been mentioned by a PUSH_PROMISE frame, this MUST be
+                                * treated as a connection error of type H3_ID_ERROR.
+                                */
+                               TRACE_ERROR("reject CANCEL_PUSH from client", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
+                               qcc_set_error(qcs->qcc, H3_ERR_ID_ERROR, 1,
+                                             muxc_tevt_type_proto_err);
+                               qcc_report_glitch(qcs->qcc, 1);
+                               goto err;
+                       }
+                       else {
+                               /* Not supported */
+                               ret = flen;
+                       }
+                       break;
                case H3_FT_GOAWAY:
                        ret = h3_parse_goaway_frm(qcs->qcc->ctx, b, flen);
                        if (ret < 0) {
@@ -1963,7 +1982,6 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
                                goto err;
                        }
                        break;
-               case H3_FT_CANCEL_PUSH:
                case H3_FT_PUSH_PROMISE:
                case H3_FT_MAX_PUSH_ID:
                        /* Not supported */