From f349df44b4e21d8bf9b575a0aa869056a2ebaa58 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Thu, 10 Jul 2025 15:27:23 +0200 Subject: [PATCH] MINOR: qmux: change API for snd_buf FIN transmission Previous patches have fixes interim response encoding via h3_resp_headers_send(). However, it is still necessary to adjust h3 layer state-machine so that several successive HTTP responses are accepted for a single stream. Prior to this, QMUX was responsible to decree that the final HTX message was encoded so that FIN stream can be emitted. However, with interim response, MUX is in fact unable to properly determine this. As such, this is the responsibility of the application protocol layer. To reflect this, app_ops snd_buf callback is modified so that a new output argument is added to it. Note that for now this commit does not bring any functional change. However, it will be necessary for the following patch. As such, it should be backported prior to it to every versions as necessary. --- include/haproxy/mux_quic-t.h | 2 +- src/h3.c | 13 ++++++++++++- src/hq_interop.c | 5 ++++- src/qmux_http.c | 5 +---- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index c24db7962..6b7f1218a 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -209,7 +209,7 @@ struct qcc_app_ops { ssize_t (*rcv_buf)(struct qcs *qcs, struct buffer *b, int fin); /* Convert HTX to HTTP payload for sending. */ - size_t (*snd_buf)(struct qcs *qcs, struct buffer *b, size_t count); + size_t (*snd_buf)(struct qcs *qcs, struct buffer *b, size_t count, char *fin); /* Negotiate and commit fast-forward data from opposite MUX. */ size_t (*nego_ff)(struct qcs *qcs, size_t count); diff --git a/src/h3.c b/src/h3.c index ac39feef4..2adda3d21 100644 --- a/src/h3.c +++ b/src/h3.c @@ -2635,11 +2635,14 @@ static int h3_resp_data_send(struct qcs *qcs, struct htx *htx, * stream instance. Successfully transcoded HTX blocks are removed from input * buffer. * + * is used as an output boolean. It will be set if the last blocks of the + * HTX message were encoded, which should trigger a FIN STREAM emission. + * * Returns the amount of consumed bytes from . In case of error, * connection is flagged and transcoding is interrupted. The returned value is * unchanged though. */ -static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count) +static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count, char *fin) { size_t total = 0; enum htx_blk_type btype; @@ -2647,11 +2650,15 @@ static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count) struct htx_blk *blk; uint32_t bsize; int32_t idx; + char eom; int ret = 0; TRACE_ENTER(H3_EV_STRM_SEND, qcs->qcc->conn, qcs); + *fin = 0; htx = htx_from_buf(buf); + /* EOM is saved here, useful if 0-copy is performed with HTX buf. */ + eom = htx->flags & HTX_FL_EOM; while (count && !htx_is_empty(htx) && qcc_stream_can_send(qcs) && ret >= 0) { idx = htx_get_head(htx); @@ -2752,6 +2759,10 @@ static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count) #endif out: + if (eom && htx_is_empty(htx)) { + TRACE_USER("transcoding last HTX message", H3_EV_STRM_SEND, qcs->qcc->conn, qcs); + *fin = 1; + } htx_to_buf(htx, buf); TRACE_LEAVE(H3_EV_STRM_SEND, qcs->qcc->conn, qcs); diff --git a/src/hq_interop.c b/src/hq_interop.c index 6f9f47a95..4dbd9adf4 100644 --- a/src/hq_interop.c +++ b/src/hq_interop.c @@ -161,7 +161,7 @@ static ssize_t hq_interop_rcv_buf(struct qcs *qcs, struct buffer *b, int fin) /* Returns the amount of consumed bytes from . */ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, - size_t count) + size_t count, char *fin) { enum htx_blk_type btype; struct htx *htx = NULL; @@ -173,6 +173,7 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, size_t total = 0; int err; + *fin = 0; htx = htx_from_buf(buf); while (count && !htx_is_empty(htx) && qcc_stream_can_send(qcs)) { @@ -266,6 +267,8 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, } end: + if (htx->flags & HTX_FL_EOM && htx_is_empty(htx)) + *fin = 1; htx_to_buf(htx, buf); return total; diff --git a/src/qmux_http.c b/src/qmux_http.c index b4e85ef22..57b1eef35 100644 --- a/src/qmux_http.c +++ b/src/qmux_http.c @@ -94,7 +94,6 @@ size_t qcs_http_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count, { struct htx *htx; size_t ret; - int eom = 0; TRACE_ENTER(QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); @@ -108,9 +107,7 @@ size_t qcs_http_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count, if (htx->extra && htx->extra == HTX_UNKOWN_PAYLOAD_LENGTH) qcs->flags |= QC_SF_UNKNOWN_PL_LENGTH; - eom = (htx->flags & HTX_FL_EOM); - ret = qcs->qcc->app_ops->snd_buf(qcs, buf, count); - *fin = (eom && !b_data(buf)); + ret = qcs->qcc->app_ops->snd_buf(qcs, buf, count, fin); TRACE_LEAVE(QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); -- 2.47.2