mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-04 12:41:00 +02:00
MEDIUM: mux-quic: extend shut to app proto layer
Previously, shut callback was entirely implemented in QUIC mux layer. However, this operation depends on the above application protocol, as it may define its own closure procedure and error codes. This is the case notably with HTTP/3 specification. This patch defines a stream shut API between QUIC mux and application protocol layers via the new qcc_app_ops callback lclose(). The closure reason is specified via an enum argument. Application protcol can then perform the stream closure as intended. This patch is only an architecture adjustment but should not have any functional impact. Stream closure logic was moved identically from QUIC mux into h3 and h09 lclose callback.
This commit is contained in:
parent
64383e655b
commit
d0bd6a946b
@ -214,6 +214,12 @@ enum qcc_app_ops_close_side {
|
||||
QCC_APP_OPS_CLOSE_SIDE_WR /* Write channel closed (STOP_SENDING received). */
|
||||
};
|
||||
|
||||
enum qcc_app_ops_lclose_mode {
|
||||
QCC_APP_OPS_LCLO_MODE_NORMAL,
|
||||
QCC_APP_OPS_LCLO_MODE_ABORT,
|
||||
QCC_APP_OPS_LCLO_MODE_KILL_CONN,
|
||||
};
|
||||
|
||||
/* QUIC application layer operations */
|
||||
struct qcc_app_ops {
|
||||
const char *alpn;
|
||||
@ -236,8 +242,10 @@ struct qcc_app_ops {
|
||||
size_t (*nego_ff)(struct qcs *qcs, size_t count);
|
||||
size_t (*done_ff)(struct qcs *qcs);
|
||||
|
||||
/* Notify about <qcs> stream closure. */
|
||||
/* Notify about <qcs> stream remote closure. */
|
||||
int (*close)(struct qcs *qcs, enum qcc_app_ops_close_side side);
|
||||
/* Notify about <qcs> stream upper layer closure. */
|
||||
void (*lclose)(struct qcs *qcs, enum qcc_app_ops_lclose_mode mode);
|
||||
/* Free <qcs> stream app context. */
|
||||
void (*detach)(struct qcs *qcs);
|
||||
|
||||
|
||||
28
src/h3.c
28
src/h3.c
@ -3095,6 +3095,33 @@ static int h3_close(struct qcs *qcs, enum qcc_app_ops_close_side side)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void h3_lclose(struct qcs *qcs, enum qcc_app_ops_lclose_mode mode)
|
||||
{
|
||||
TRACE_ENTER(H3_EV_H3S_END, qcs->qcc->conn, qcs);
|
||||
|
||||
switch (mode) {
|
||||
case QCC_APP_OPS_LCLO_MODE_NORMAL:
|
||||
/* Close stream with FIN. This can only be performed if at
|
||||
* least HEADERS frame was emitted, or else some clients close
|
||||
* the connection with H3_FRAME_UNEXPECTED.
|
||||
*/
|
||||
if (qcs->tx.fc.off_soft) {
|
||||
qcs->flags |= QC_SF_FIN_STREAM;
|
||||
qcc_send_stream(qcs, 0, 0);
|
||||
}
|
||||
else {
|
||||
qcc_reset_stream(qcs, 0, se_tevt_type_shutw);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
qcc_reset_stream(qcs, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_LEAVE(H3_EV_H3S_END, qcs->qcc->conn, qcs);
|
||||
}
|
||||
|
||||
/* Allocates HTTP/3 stream context relative to <qcs>. If the operation cannot
|
||||
* be performed, an error is returned and <qcs> context is unchanged.
|
||||
*
|
||||
@ -3500,6 +3527,7 @@ const struct qcc_app_ops h3_ops = {
|
||||
.nego_ff = h3_nego_ff,
|
||||
.done_ff = h3_done_ff,
|
||||
.close = h3_close,
|
||||
.lclose = h3_lclose,
|
||||
.detach = h3_detach,
|
||||
.shutdown = h3_shutdown,
|
||||
.inc_err_cnt = h3_stats_inc_err_cnt,
|
||||
|
||||
@ -323,6 +323,20 @@ static int hq_interop_attach(struct qcs *qcs, void *conn_ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hq_interop_lclose(struct qcs *qcs, enum qcc_app_ops_lclose_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case QCC_APP_OPS_LCLO_MODE_NORMAL:
|
||||
qcs->flags |= QC_SF_FIN_STREAM;
|
||||
qcc_send_stream(qcs, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
qcc_reset_stream(qcs, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const struct qcc_app_ops hq_interop_ops = {
|
||||
.alpn = "hq-interop",
|
||||
|
||||
@ -331,4 +345,5 @@ const struct qcc_app_ops hq_interop_ops = {
|
||||
.nego_ff = hq_interop_nego_ff,
|
||||
.done_ff = hq_interop_done_ff,
|
||||
.attach = hq_interop_attach,
|
||||
.lclose = hq_interop_lclose,
|
||||
};
|
||||
|
||||
@ -4591,25 +4591,12 @@ static void qmux_strm_shut(struct stconn *sc, unsigned int mode, struct se_abort
|
||||
/* Early closure reported if QC_SF_FIN_STREAM not yet set. */
|
||||
if (!qcs_is_close_local(qcs) &&
|
||||
!(qcs->flags & (QC_SF_FIN_STREAM|QC_SF_TO_RESET))) {
|
||||
|
||||
/* Close stream with FIN if length unknown and some data are
|
||||
* ready to be/already transmitted.
|
||||
* TODO select closure method on app proto layer
|
||||
*/
|
||||
if (qcs->flags & QC_SF_UNKNOWN_PL_LENGTH &&
|
||||
qcs->tx.fc.off_soft) {
|
||||
if (!(qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL))) {
|
||||
TRACE_STATE("set FIN STREAM",
|
||||
QMUX_EV_STRM_SHUT, qcc->conn, qcs);
|
||||
qcs->flags |= QC_SF_FIN_STREAM;
|
||||
qcc_send_stream(qcs, 0, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* RESET_STREAM necessary. */
|
||||
qcc_reset_stream(qcs, 0, 0);
|
||||
}
|
||||
|
||||
if (qcs->flags & QC_SF_UNKNOWN_PL_LENGTH)
|
||||
qcc->app_ops->lclose(qcs, QCC_APP_OPS_LCLO_MODE_NORMAL);
|
||||
else if (se_fl_test(qcs->sd, SE_FL_KILL_CONN))
|
||||
qcc->app_ops->lclose(qcs, QCC_APP_OPS_LCLO_MODE_KILL_CONN);
|
||||
else
|
||||
qcc->app_ops->lclose(qcs, QCC_APP_OPS_LCLO_MODE_ABORT);
|
||||
tasklet_wakeup(qcc->wait_event.tasklet);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user