BUG/MINOR: h3: properly handle connection headers

Connection headers are not used in HTTP/3. As specified by RFC 9114, a
received message containing one of those is considered as malformed and
rejected. When converting an HTX message to HTTP/3, these headers are
silently skipped.

This must be backported up to 2.6. Note that assignment to <h3s.err>
must be removed on 2.6 as stream level error has been introduced in 2.7
so this field does not exist in 2.6 A connection error will be used
instead automatically.
This commit is contained in:
Amaury Denoyelle 2023-01-17 17:47:06 +01:00
parent d1ebee1774
commit 8ad2669175

View File

@ -599,6 +599,37 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
goto out;
}
}
else if (isteq(list[hdr_idx].n, ist("connection")) ||
isteq(list[hdr_idx].n, ist("proxy-connection")) ||
isteq(list[hdr_idx].n, ist("keep-alive")) ||
isteq(list[hdr_idx].n, ist("transfer-encoding"))) {
/* RFC 9114 4.2. HTTP Fields
*
* HTTP/3 does not use the Connection header field to indicate
* connection-specific fields; in this protocol, connection-
* specific metadata is conveyed by other means. An endpoint
* MUST NOT generate an HTTP/3 field section containing
* connection-specific fields; any message containing
* connection-specific fields MUST be treated as malformed.
*/
TRACE_ERROR("invalid connection header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
h3s->err = H3_MESSAGE_ERROR;
len = -1;
goto out;
}
else if (isteq(list[hdr_idx].n, ist("te")) &&
!isteq(list[hdr_idx].v, ist("trailers"))) {
/* RFC 9114 4.2. HTTP Fields
*
* The only exception to this is the TE header field, which MAY
* be present in an HTTP/3 request header; when it is, it MUST
* NOT contain any value other than "trailers".
*/
TRACE_ERROR("invalid te header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
h3s->err = H3_MESSAGE_ERROR;
len = -1;
goto out;
}
if (!htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v)) {
h3c->err = H3_INTERNAL_ERROR;
@ -1113,13 +1144,28 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
if (isteq(list[hdr].n, ist("")))
break;
/* draft-ietf-quic-http34 4.1. HTTP Message Exchanges
* Transfer codings (see Section 6.1 of [HTTP11]) are not
* defined for HTTP/3; the Transfer-Encoding header field MUST
* NOT be used.
/* 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("transfer-encoding")))
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("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 (qpack_encode_header(&headers_buf, list[hdr].n, list[hdr].v))
ABORT_NOW();