MINOR: qmux: change API for snd_buf FIN transmission
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 10 Jul 2025 13:27:23 +0000 (15:27 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 17 Oct 2025 09:19:40 +0000 (11:19 +0200)
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
<fin> 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.

(cherry picked from commit f349df44b4e21d8bf9b575a0aa869056a2ebaa58)
[ad: fix context due to mising comment on h3_snd_buf]
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
(cherry picked from commit 96896b408d0fb0b45e5ebf59cc74a5a5c2b03dc9)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit ea3cf3af3554c31213e0b72e99e3b9bf3bd4803e)
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>

include/haproxy/mux_quic-t.h
src/h3.c
src/hq_interop.c
src/qmux_http.c

index e4196e3..474afa8 100644 (file)
@@ -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);
index 9ae1b8b..c311386 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -2126,7 +2126,7 @@ static int h3_resp_data_send(struct qcs *qcs, struct htx *htx,
        return -1;
 }
 
-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;
@@ -2134,11 +2134,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);
@@ -2232,6 +2236,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);
index 3f309bb..8c4f3eb 100644 (file)
@@ -86,7 +86,7 @@ static ssize_t hq_interop_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
 }
 
 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;
@@ -97,6 +97,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)) {
@@ -174,6 +175,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;
index 092eb15..37a28a7 100644 (file)
@@ -73,7 +73,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);
 
@@ -87,9 +86,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);