mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 07:07:04 +02:00
MINOR: mux-quic/h3: support temporary blocking on control stream sending
When HTTP/3 layer is initialized via QUIC MUX, it first emits a SETTINGS frame on an unidirectional control stream. However, this could be prevented if client did not provide initial flow control. Previously, QUIC MUX was unable to deal with such situation. Thus, the connection was closed immediately and no transfer could occur. Improve this by extending QUIC MUX application layer API : initialization may now return a transient error. This allows MUX to continue to use the connection normally. Initialization will be retried periodically alter until it can succeed. This new API allows to deal with the flow control issue described above. Note that this patch is not considered as a bug fix. Indeed, clients are strongly advised to provide enough flow control for a SETTINGS frame exchange.
This commit is contained in:
parent
06e7674399
commit
a7645d7cd5
24
src/h3.c
24
src/h3.c
@ -1531,11 +1531,6 @@ static int h3_control_send(struct qcs *qcs, void *ctx)
|
||||
b_quic_enc_int(&pos, h3_settings_max_field_section_size, 0);
|
||||
}
|
||||
|
||||
if (qfctl_sblocked(&qcs->tx.fc) || qfctl_sblocked(&qcs->qcc->tx.fc)) {
|
||||
TRACE_ERROR("not enough initial credit for control stream", H3_EV_TX_FRAME|H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) {
|
||||
/* Only memory failure can cause buf alloc error for control stream due to qcs_send_metadata() usage. */
|
||||
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs);
|
||||
@ -2409,16 +2404,19 @@ static int h3_init(struct qcc *qcc)
|
||||
/* Open control stream for <ctx> HTTP/3 connection and schedule a SETTINGS
|
||||
* frame emission on it.
|
||||
*
|
||||
* Returns 0 on success else non-zero.
|
||||
* Returns 0 on success. If a transient error was encountered, a positive value
|
||||
* is returned, finalize operation should be recalled later. A negative value is
|
||||
* used for a fatal error, in this case the connection should be closed.
|
||||
*/
|
||||
static int h3_finalize(void *ctx)
|
||||
{
|
||||
struct h3c *h3c = ctx;
|
||||
struct qcc *qcc = h3c->qcc;
|
||||
struct qcs *qcs;
|
||||
struct qcs *qcs = h3c->ctrl_strm;
|
||||
|
||||
TRACE_ENTER(H3_EV_H3C_NEW, qcc->conn);
|
||||
|
||||
if (!qcs) {
|
||||
qcs = qcc_init_stream_local(qcc, 0);
|
||||
if (!qcs) {
|
||||
/* Error must be set by qcc_init_stream_local(). */
|
||||
@ -2429,6 +2427,12 @@ static int h3_finalize(void *ctx)
|
||||
|
||||
qcs_send_metadata(qcs);
|
||||
h3c->ctrl_strm = qcs;
|
||||
}
|
||||
|
||||
if (qfctl_sblocked(&qcs->tx.fc) || qfctl_sblocked(&qcs->qcc->tx.fc)) {
|
||||
TRACE_STATE("not enough initial credit for control stream", H3_EV_TX_FRAME|H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* RFC 9114 7.2.4.2. Initialization
|
||||
*
|
||||
@ -2445,9 +2449,13 @@ static int h3_finalize(void *ctx)
|
||||
TRACE_LEAVE(H3_EV_H3C_NEW, qcc->conn);
|
||||
return 0;
|
||||
|
||||
again:
|
||||
TRACE_DEVEL("leaving on transient state", H3_EV_H3C_NEW, qcc->conn);
|
||||
return 1;
|
||||
|
||||
err:
|
||||
TRACE_DEVEL("leaving on error", H3_EV_H3C_NEW, qcc->conn);
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send a HTTP/3 GOAWAY followed by a CONNECTION_CLOSE_APP. */
|
||||
|
@ -2465,21 +2465,34 @@ static void qcc_wakeup_pacing(struct qcc *qcc)
|
||||
++qcc->tx.paced_sent_ctr;
|
||||
}
|
||||
|
||||
/* Finalize <qcc> app layer initialization with I/O operations.
|
||||
/* Conduct I/O operations to finalize <qcc> app layer initialization. Note that
|
||||
* <qcc> app state may remain NULL even on success, if only a transient
|
||||
* blocking was encountered. Finalize operation can be retry later.
|
||||
*
|
||||
* Returns 0 on success else non-zero.
|
||||
*/
|
||||
static int qcc_app_init(struct qcc *qcc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
|
||||
|
||||
if (qcc->app_ops->finalize && qcc->app_ops->finalize(qcc->ctx)) {
|
||||
if (qcc->app_ops->finalize) {
|
||||
ret = qcc->app_ops->finalize(qcc->ctx);
|
||||
if (ret < 0) {
|
||||
TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
TRACE_STATE("cannot finalize app ops yet", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
qcc->app_st = QCC_APP_ST_INIT;
|
||||
|
||||
again:
|
||||
TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user