From 849b24f15bf3de6ba03290688023330c0de14578 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 24 May 2022 17:22:07 +0200 Subject: [PATCH] MINOR: h3: abort read on unknown uni stream As specified by HTTP/3 draft, an unknown unidirectional stream can be aborted. To do this, use a new flag QC_SF_READ_ABORTED. When the MUX detects this flag, QCS instance is automatically freed. Previously, such streams were instead automatically drained. By aborting them, we economize some useless memcpy instruction. On future data reception, QCS instance is not found in the tree and considered as already closed. The frame payload is thus deleted without copying it. --- include/haproxy/mux_quic-t.h | 1 + src/h3.c | 15 ++++++++++----- src/mux_quic.c | 10 ++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index fca28f7fa..40f784c31 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -100,6 +100,7 @@ struct qcc { #define QC_SF_DETACH 0x00000008 /* cs is detached but there is remaining data to send */ #define QC_SF_BLK_SFCTL 0x00000010 /* stream blocked due to stream flow control limit */ #define QC_SF_DEM_FULL 0x00000020 /* demux blocked on request channel buffer full */ +#define QC_SF_READ_ABORTED 0x00000040 /* stream rejected by app layer */ struct qcs { struct qcc *qcc; diff --git a/src/h3.c b/src/h3.c index a792851ab..3fb6942b8 100644 --- a/src/h3.c +++ b/src/h3.c @@ -144,8 +144,13 @@ static int h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs, break; default: - h3s->flags |= H3_SF_UNI_NO_H3; - break; + /* draft-ietf-quic-http34 9. Extensions to HTTP/3 + * + * Implementations MUST [...] abort reading on unidirectional + * streams that have unknown or unsupported types. + */ + qcs->flags |= QC_SF_READ_ABORTED; + return 1; }; h3s->flags |= H3_SF_UNI_INIT; @@ -175,10 +180,10 @@ static int h3_parse_uni_stream_no_h3(struct qcs *qcs, struct ncbuf *rxbuf) if (!qpack_decode_enc(qcs, NULL)) return 1; break; + case H3S_T_UNKNOWN: default: - /* unknown uni stream : just consume it. */ - qcs_consume(qcs, ncb_data(rxbuf, 0)); - break; + /* Unknown stream should be flagged with QC_SF_READ_ABORTED. */ + ABORT_NOW(); } return 0; diff --git a/src/mux_quic.c b/src/mux_quic.c index c47e83a2c..b7d1e17f4 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -584,6 +584,11 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset, if (ncb_data(&qcs->rx.ncbuf, 0) && !(qcs->flags & QC_SF_DEM_FULL)) qcc_decode_qcs(qcc, qcs); + if (qcs->flags & QC_SF_READ_ABORTED) { + /* TODO should send a STOP_SENDING */ + qcs_free(qcs); + } + TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn); return 0; } @@ -1192,6 +1197,11 @@ static int qc_recv(struct qcc *qcc) qcc_decode_qcs(qcc, qcs); node = eb64_next(node); + + if (qcs->flags & QC_SF_READ_ABORTED) { + /* TODO should send a STOP_SENDING */ + qcs_free(qcs); + } } TRACE_LEAVE(QMUX_EV_QCC_RECV);