]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: h3: support HTTP request framing state
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 2 Aug 2022 09:32:45 +0000 (11:32 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 3 Aug 2022 13:04:18 +0000 (15:04 +0200)
Store the current step of HTTP message in h3s stream. This reports if we
are in the parsing of headers, content or trailers section. A new enum
h3s_st_req is defined for this.

This field is stored in h3s struct but only used for request stream. It
is left undefined for other streams (control or QPACK streams).

h3_is_frame_valid() has been extended to take into account this state
information. A connection error H3_FRAME_UNEXPECTED is reported if an
invalid frame according to the current state is received; for example a
DATA frame at the beginning of a stream.

include/haproxy/h3.h
src/h3.c

index 5953da61489ac551a66edd5ba204b4badcdd49e8..504e9bfedec5efa0df8b994a59c5f1aa4e4d829b 100644 (file)
@@ -101,6 +101,14 @@ enum h3s_t {
        H3S_T_UNKNOWN
 };
 
+/* State for request streams */
+enum h3s_st_req {
+       H3S_ST_REQ_BEFORE = 0, /* initial state */
+       H3S_ST_REQ_HEADERS,    /* header section received */
+       H3S_ST_REQ_DATA,       /* first DATA frame for content received */
+       H3S_ST_REQ_TRAILERS,   /* trailer section received */
+};
+
 extern const struct qcc_app_ops h3_ops;
 
 size_t h3_snd_buf(struct stconn *sc, struct buffer *buf, size_t count, int flags);
index bda99cd2c6700e7372786df744323f065343cb35..f00281e8d6c9c5e51248c57299e8ee1e7a90e98c 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -138,6 +138,7 @@ struct h3s {
        struct h3c *h3c;
 
        enum h3s_t type;
+       enum h3s_st_req st_req; /* only used for request streams */
        int demux_frame_len;
        int demux_frame_type;
 
@@ -284,8 +285,11 @@ static int h3_is_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype)
 
        switch (ftype) {
        case H3_FT_DATA:
+               return h3s->type != H3S_T_CTRL && (h3s->st_req == H3S_ST_REQ_HEADERS ||
+                                                  h3s->st_req == H3S_ST_REQ_DATA);
+
        case H3_FT_HEADERS:
-               return h3s->type != H3S_T_CTRL;
+               return h3s->type != H3S_T_CTRL && h3s->st_req != H3S_ST_REQ_TRAILERS;
 
        case H3_FT_CANCEL_PUSH:
        case H3_FT_GOAWAY:
@@ -344,6 +348,8 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
 
        TRACE_ENTER(H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
 
+       /* TODO support trailer parsing in this function */
+
        /* TODO support buffer wrapping */
        BUG_ON(b_head(buf) + len >= b_wrap(buf));
        ret = qpack_decode_fs((const unsigned char *)b_head(buf), len, tmp,
@@ -673,6 +679,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
                        ret = h3_data_to_htx(qcs, b, flen, last_stream_frame);
                        /* TODO handle error reporting. Stream closure required. */
                        if (ret < 0) { ABORT_NOW(); }
+                       h3s->st_req = H3S_ST_REQ_DATA;
                        break;
                case H3_FT_HEADERS:
                        ret = h3_headers_to_htx(qcs, b, flen, last_stream_frame);
@@ -684,6 +691,8 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
                                qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
                                return -1;
                        }
+                       h3s->st_req = (h3s->st_req == H3S_ST_REQ_BEFORE) ?
+                                       H3S_ST_REQ_HEADERS : H3S_ST_REQ_TRAILERS;
                        break;
                case H3_FT_CANCEL_PUSH:
                case H3_FT_PUSH_PROMISE:
@@ -1070,6 +1079,7 @@ static int h3_attach(struct qcs *qcs, void *conn_ctx)
 
        if (quic_stream_is_bidi(qcs->id)) {
                h3s->type = H3S_T_REQ;
+               h3s->st_req = H3S_ST_REQ_BEFORE;
        }
        else {
                /* stream type must be decoded for unidirectional streams */