From: Amaury Denoyelle Date: Fri, 23 Oct 2026 08:44:41 +0000 (+0200) Subject: BUG/MINOR: h3: do not retry on trailers too large X-Git-Tag: v3.5-dev10~66 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=6e4154d1fa45043ef4b6c4a2c7fbcc1f1a0bdd3b;p=haproxy.git BUG/MINOR: h3: do not retry on trailers too large The following patch adds the ability for the QUIC transcoder to release a buffer if there is not enough space in it and allocate a new one instead. This is mostly used during DATA and trailers encoding. cd22200d239773a851c6b78e722864fa5103af6a MEDIUM: mux-quic: release Tx buf on too small room For trailers encoding it may cause an infinite loop if the content is larger than a whole buffer. In this case, transcoder will release and allocate a new buffer without interruption before the watchdog is triggered. Fix this by extending h3_resp_trailers_send(). The buffer is now released only when it contains residual not yet sent or acknowledged data. If the buffer is empty, trailers are too large and an error is returned, which will close the connection with INTERNAL_ERROR code. This method was in fact already implemented in h3_resp_headers_send(). This must be backported up to 3.0. --- diff --git a/src/h3.c b/src/h3.c index 564b654cd..9516a1579 100644 --- a/src/h3.c +++ b/src/h3.c @@ -2975,7 +2975,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx, char *fin) list[hdr].n = ist(""); - start: + retry: if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) { if (err) { TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); @@ -3002,11 +3002,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx, char *fin) */ if (b_size(&headers_buf) <= 9) { TRACE_STATE("not enough room for trailers frame", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); - if (qcc_release_stream_txbuf(qcs)) - goto end; - - /* Buffer released, restart processing. */ - goto start; + goto err_full; } /* Start the headers after frame type + length */ @@ -3014,11 +3010,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx, char *fin) if (qpack_encode_field_section_line(&headers_buf)) { TRACE_STATE("not enough room for trailers section line", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); - if (qcc_release_stream_txbuf(qcs)) - goto end; - - /* Buffer released, restart processing. */ - goto start; + goto err_full; } tail = b_tail(&headers_buf); @@ -3040,11 +3032,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx, char *fin) if (h3_encode_header(&headers_buf, list[hdr].n, list[hdr].v)) { TRACE_STATE("not enough room for all trailers", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); - if (qcc_release_stream_txbuf(qcs)) - goto end; - - /* Buffer released, restart processing. */ - goto start; + goto err_full; } } @@ -3085,6 +3073,20 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx, char *fin) TRACE_LEAVE(H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); return ret; + err_full: + /* Try to release buffer if not empty. */ + if (b_data(res)) { + if (qcc_release_stream_txbuf(qcs)) { + TRACE_DEVEL("cannot release buf", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); + return 0; + } + + TRACE_DEVEL("retry after buf release", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); + goto retry; + } + + TRACE_ERROR("trailers too large for encoding", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); + err: TRACE_DEVEL("leaving on error", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); return -1;