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.
diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h
index fca28f7..40f784c 100644
--- a/include/haproxy/mux_quic-t.h
+++ b/include/haproxy/mux_quic-t.h
@@ -100,6 +100,7 @@
#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 a792851..3fb6942 100644
--- a/src/h3.c
+++ b/src/h3.c
@@ -144,8 +144,13 @@
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 @@
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 c47e83a..b7d1e17 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -584,6 +584,11 @@
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 @@
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);