]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
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>
Tue, 15 Jul 2025 16:39:23 +0000 (18:39 +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.

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

index c24db79623edd52c8e2ab052fcb801908805d63b..6b7f1218a39a2a66512d7ed3fadbfaaf53d19a0c 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 ac39feef4191a5eb22b95deea53bb3ad0473e360..2adda3d21297ef54da31d1e3b85b1e80b4c84f79 100644 (file)
--- 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.
  *
+ * <fin> 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 <buf>. 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);
index 6f9f47a952294918247e5f8f3654fba8f310eef4..4dbd9adf4d5de0b687fdd60da620ea35ce9db66f 100644 (file)
@@ -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 <buf>. */
 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;
index b4e85ef22b1d8c16ca718d945e825786356cf47a..57b1eef350d0604188358c57e2f922bfde6a2cd2 100644 (file)
@@ -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);