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);
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;
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:
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,
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);
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:
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 */