From ad7f1852477aa898d0c7f7551189c3a0377894b1 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Wed, 24 Dec 2025 22:59:40 +0400 Subject: [PATCH 1/3] Proxy: fixed sending HTTP/2 request body on next upstream. If request body wasn't fully sent, such as limited by flow control, unsent buffers part could remain sitting in chain prepending new input buffers when switching to the next upstream server, which resulted in an invalid request sent. The fix is to ensure there's no pending chain on the first request. --- src/http/modules/ngx_http_proxy_v2_module.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/http/modules/ngx_http_proxy_v2_module.c b/src/http/modules/ngx_http_proxy_v2_module.c index 17983a29d..6b58aacca 100644 --- a/src/http/modules/ngx_http_proxy_v2_module.c +++ b/src/http/modules/ngx_http_proxy_v2_module.c @@ -974,6 +974,17 @@ ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in) return NGX_ERROR; } + if (!ctx->header_sent) { + /* cleanup after previously unsent request body */ + + while (ctx->in) { + ln = ctx->in; + ctx->in = ctx->in->next; + + ngx_free_chain(r->pool, ln); + } + } + if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { return NGX_ERROR; From 828d5b517826c5d742786daaa646fa2553db957c Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 25 Dec 2025 01:21:52 +0400 Subject: [PATCH 2/3] Proxy: fixed sending HTTP/2 buffered request body on next upstream. The last_buf flag is set on the last body buffer when creating an HTTP/2 request and is used to indicate when the output is closed. When reading the last portion of buffered request body from a file as part of ngx_output_chain(), last_buf is propagated to a destination buffer. In the proxy output filter this buffer is then used as input buffer, for which the last_buf flag marks the last data frame to send with the HTTP/2 END_STREAM flag. The problem is that this request body buffer can be later reused from the free chain, as part of re-reading buffered body on next upstream, with the last_buf flag not cleared. This results in an invalid request sent to the next upstream server due to END_STREAM set prematurely. The fix is to clear the last_buf flag once we don't need it anymore. Special care is given for request body sent with sendfile, in which case the input buffer contains the whole request body. --- src/http/modules/ngx_http_proxy_v2_module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http/modules/ngx_http_proxy_v2_module.c b/src/http/modules/ngx_http_proxy_v2_module.c index 6b58aacca..762c1889b 100644 --- a/src/http/modules/ngx_http_proxy_v2_module.c +++ b/src/http/modules/ngx_http_proxy_v2_module.c @@ -1199,6 +1199,10 @@ ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in) last = 1; } + if (!ngx_buf_special(in->buf) && !in->buf->in_file) { + in->buf->last_buf = 0; + } + ln = in; in = in->next; From 784244e188ff93fc0d8bfb0c4d389253c8ef904e Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 25 Dec 2025 02:38:37 +0400 Subject: [PATCH 3/3] Proxy: unbusy stale HTTP/2 request body buffers on next upstream. Similarly to previous changes, if a buffered request body wasn't fully sent, a partially sent buffer was sitting in the busy chain and not recycled when switching to the next upstream server. This resulted in a stalled connection because ngx_output_chain() could not get a free buffer to read the next portion of request body. --- src/http/modules/ngx_http_proxy_v2_module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http/modules/ngx_http_proxy_v2_module.c b/src/http/modules/ngx_http_proxy_v2_module.c index 762c1889b..e30a9da7b 100644 --- a/src/http/modules/ngx_http_proxy_v2_module.c +++ b/src/http/modules/ngx_http_proxy_v2_module.c @@ -983,6 +983,10 @@ ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in) ngx_free_chain(r->pool, ln); } + + for (ln = ctx->busy; ln; ln = ln->next) { + ln->buf->pos = ln->buf->last; + } } if (in) {