]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: h3: encode request headers
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 16 Jun 2025 13:38:26 +0000 (15:38 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 16 Jun 2025 16:11:09 +0000 (18:11 +0200)
Implement encoding of HTTP/3 request headers during HTX->H3 conversion
on the backend side. This simply relies on h3_encode_header().

Special check is implemented to ensure that connection-specific headers
are ignored. An HTTP/3 endpoint must never generate them, or the peer
will consider the message as malformed.

src/h3.c

index ccf6eae7a3543d8b6abf9380f1055ee659e8c9d4..de236ba4d7683cb7e2b4699be4b42a8d23d59eaf 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -1700,13 +1700,51 @@ static int h3_encode_header(struct buffer *buf,
  */
 static int h3_req_headers_send(struct qcs *qcs, struct htx *htx)
 {
+       struct http_hdr list[global.tune.max_http_hdr * 2];
        struct buffer outbuf;
        struct buffer headers_buf = BUF_NULL;
        struct buffer *res;
-       struct htx_blk *blk;
        enum htx_blk_type type;
+       struct htx_blk *blk;
+       struct htx_sl *sl;
        int frame_length_size;  /* size in bytes of frame length varint field */
-       int ret, err;
+       int ret, err, hdr;
+
+       hdr = 0;
+       sl = NULL;
+       for (blk = htx_get_head_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
+               type = htx_get_blk_type(blk);
+
+               switch (type) {
+               case HTX_BLK_EOH:
+                       goto end_loop;
+               case HTX_BLK_UNUSED:
+                       break;
+
+               case HTX_BLK_REQ_SL:
+                       BUG_ON_HOT(sl); /* Only one start-line expected */
+                       sl = htx_get_blk_ptr(htx, blk);
+                       break;
+
+               case HTX_BLK_HDR:
+                       if (unlikely(hdr >= sizeof(list) / sizeof(list[0]) - 1))
+                               goto err;
+
+                       list[hdr].n = htx_get_blk_name(htx, blk);
+                       list[hdr].v = htx_get_blk_value(htx, blk);
+
+                       ++hdr;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+ end_loop:
+       BUG_ON_HOT(!sl); /* start-line must be present. */
+       /* marker for end of headers */
+       list[hdr].n = ist("");
 
        res = qcc_get_stream_txbuf(qcs, &err, 0);
        BUG_ON(!res);
@@ -1734,6 +1772,39 @@ static int h3_req_headers_send(struct qcs *qcs, struct htx *htx)
        if (h3_encode_header(&headers_buf, ist(":authority"), ist("127.0.0.1:20443")))
                goto err;
 
+       /* Encode every parsed headers, stop at empty one. */
+       for (hdr = 0; hdr < sizeof(list) / sizeof(list[0]); ++hdr) {
+               if (isteq(list[hdr].n, ist("")))
+                       break;
+
+               /* RFC 9114 4.2. HTTP Fields
+                *
+                * An intermediary transforming an HTTP/1.x message to HTTP/3
+                * MUST remove connection-specific header fields as discussed in
+                * Section 7.6.1 of [HTTP], or their messages will be treated by
+                * other HTTP/3 endpoints as malformed.
+                */
+               if (isteq(list[hdr].n, ist("connection")) ||
+                   isteq(list[hdr].n, ist("proxy-connection")) ||
+                   isteq(list[hdr].n, ist("keep-alive")) ||
+                   isteq(list[hdr].n, ist("upgrade")) ||
+                   isteq(list[hdr].n, ist("transfer-encoding"))) {
+                       continue;
+               }
+               else if (isteq(list[hdr].n, ist("te"))) {
+                       /* "te" may only be sent with "trailers" if this value
+                        * is present, otherwise it must be deleted.
+                        */
+                       const struct ist v = istist(list[hdr].v, ist("trailers"));
+                       if (!isttest(v) || (v.len > 8 && v.ptr[8] != ','))
+                               continue;
+                       list[hdr].v = ist("trailers");
+               }
+
+               if (h3_encode_header(&headers_buf, list[hdr].n, list[hdr].v))
+                       goto err;
+       }
+
        /* Now that all headers are encoded, we are certain that res buffer is
         * big enough
         */