]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic/h3: send SETTINGS as soon as transport is ready
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 24 Jan 2023 16:35:37 +0000 (17:35 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 25 Jan 2023 15:01:55 +0000 (16:01 +0100)
As specified by HTTP3 RFC, SETTINGS frame should be sent as soon as
possible. Before this patch, this was only done on the first qc_send()
invocation. This delay significantly SETTINGS emission until the first
H3 response is ready to be transferred.

This patch fixes this by ensuring SETTINGS is emitted when MUX-QUIC is
being setup.

As a side point, return value of finalize operation is checked. This
means that an error during SETTINGS emission will cause the connection
init to fail.

This should be backported up to 2.7.

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

index 43a7cccb8f4b6e5aeddc74992c8a4ae359de19a3..4ce088e61a1ae1cba87971c2cd57461e1f1ce4d7 100644 (file)
@@ -30,7 +30,6 @@ enum qcs_type {
 #define QC_CF_CC_EMIT   0x00000001 /* A CONNECTION_CLOSE is set by the MUX */
 #define QC_CF_BLK_MFCTL 0x00000002 /* sending blocked due to connection flow-control */
 #define QC_CF_CONN_FULL 0x00000004 /* no stream buffers available on connection */
-#define QC_CF_APP_FINAL 0x00000008 /* The application layer was finalized */
 
 struct qcc {
        struct connection *conn;
index f7bd8a12c842d8fa39cd89227761741b8d44c14d..9a1d97d40c02f22b6b31ddb381f562da9e9c5d0f 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -1636,6 +1636,10 @@ static void h3_detach(struct qcs *qcs)
        TRACE_LEAVE(H3_EV_H3S_END, qcs->qcc->conn, qcs);
 }
 
+/* Initialize H3 control stream and prepare SETTINGS emission.
+ *
+ * Returns 0 on success else non-zero.
+ */
 static int h3_finalize(void *ctx)
 {
        struct h3c *h3c = ctx;
@@ -1643,12 +1647,12 @@ static int h3_finalize(void *ctx)
 
        qcs = qcc_init_stream_local(h3c->qcc, 0);
        if (!qcs)
-               return 0;
+               return 1;
 
        h3_control_send(qcs, h3c);
        h3c->ctrl_strm = qcs;
 
-       return 1;
+       return 0;
 }
 
 /* Generate a GOAWAY frame for <h3c> connection on the control stream.
index 31d5a3ab04751088d833a50831ad3109775093a7..b7b843e357e875f71e6b9fbca538f5575cde3fab 100644 (file)
@@ -883,6 +883,21 @@ int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops)
 
        TRACE_PROTO("application layer initialized", QMUX_EV_QCC_NEW, qcc->conn);
 
+       /* RFC 9114 7.2.4.2. Initialization
+        *
+        * Endpoints MUST NOT require any data to be
+        * received from the peer prior to sending the SETTINGS frame;
+        * settings MUST be sent as soon as the transport is ready to
+        * send data.
+        */
+       if (qcc->app_ops->finalize) {
+               if (qcc->app_ops->finalize(qcc->ctx)) {
+                       TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn);
+                       goto err;
+               }
+               tasklet_wakeup(qcc->wait_event.tasklet);
+       }
+
        TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn);
        return 0;
 
@@ -1741,15 +1756,6 @@ static int qc_send(struct qcc *qcc)
        if (qcc->flags & QC_CF_BLK_MFCTL)
                goto err;
 
-       if (!(qcc->flags & QC_CF_APP_FINAL) && !eb_is_empty(&qcc->streams_by_id) &&
-           qcc->app_ops->finalize) {
-               /* Finalize the application layer before sending any stream.
-                * For h3 this consists in preparing the control stream data (SETTINGS h3).
-                */
-               qcc->app_ops->finalize(qcc->ctx);
-               qcc->flags |= QC_CF_APP_FINAL;
-       }
-
        /* Send STREAM/STOP_SENDING/RESET_STREAM data for registered streams. */
        list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_list, el_send) {
                /* Stream must not be present in send_list if it has nothing to send. */