From: Christopher Faulet Date: Fri, 11 Sep 2026 15:43:13 +0000 (+0200) Subject: MEDIUM: mux-h2: Don't mix HTTP and tunneled data in the same buffer X-Git-Tag: v3.5-dev8~156 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=d11682dfc0313ced9380a510f05c7add562556cf;p=haproxy.git MEDIUM: mux-h2: Don't mix HTTP and tunneled data in the same buffer For a tunneled stream, the end of the HTTP message is reported just after the headers while the tunneled data are received after. Because the information about the end of the message was a flag on the HTX message itself, both could be stored in the same buffer without any issue. This is no longer true. The end of the message is now carried by the tail block of the HTX message. So nothing must be added after this block, otherwise the message would no longer be seen as ended. It means HTTP data and tunneled data must never be mixed in the same buffer. Two changes are required for that: * h2s_may_append_to_rxbuf() now refuses to append data to an rxbuf carrying a message already ended. h2_frt_transfer_data() thus gets an extra rxbuf to store the tunneled data. If no buffer is available, the demux is blocked, as usual. * h2_rcv_buf() no longer transfers an rxbuf to the upper layer when the HTX message in the channel buffer was already ended. SE_FL_RCV_MORE and SE_FL_WANT_ROOM are reported instead, so the transfer is retried once the HTTP part was consumed. Note the H1 multiplexer does not have this issue because the demux is blocked, thanks to H1S_F_RX_BLK flag, until the tunnel is established. This patch is a prerequisite to be able to harden the HTX API and forbid any addition in a message already ended. --- diff --git a/src/mux_h2.c b/src/mux_h2.c index 42feb750a..5cea5cab6 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -983,6 +983,15 @@ static inline int h2s_may_append_to_rxbuf(const struct h2s *h2s) return 0; htx = htxbuf(rxbuf); + + /* Nothing must be added in a message already ended. For a tunneled + * stream, the end of the HTTP message is reported just after the + * headers. So tunneled data must be stored in a separate buffer to + * never mix HTTP data and tunneled data. + */ + if (htx_has_eom(htx)) + return 0; + return !!htx_free_data_space(htx); } @@ -8055,9 +8064,22 @@ static size_t h2_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, in htx_to_buf(h2s_htx, rxbuf); goto end; } - ret += h2s_htx->data; buf_htx = htx_from_buf(buf); + /* Nothing must be added in a message already ended. For a tunneled + * stream, the end of the HTTP message is reported just after the + * headers while tunneled data are stored in a separate buffer. So + * these data must be transferred only once the upper layer has + * consumed the HTTP part. + */ + if (htx_has_eom(buf_htx)) { + htx_to_buf(buf_htx, buf); + htx_to_buf(h2s_htx, rxbuf); + goto end; + } + + ret += h2s_htx->data; + /* is empty and the message is small enough, swap the * buffers. */ if (htx_is_empty_noerr(buf_htx) && htx_used_space(h2s_htx) <= count) {