Proxy: fixed HTTP/2 upstream with revalidated cache send

Previously, a revalidated cached response could fail on a cached
keepalive connection with "upstream sent frame for unknown stream"
error followed by "cache file contains invalid header".

This happened because after a 304 response, nginx parsed the cached
response while the upstream peer connection was still attached to the
request.  The HTTP/2 proxy code treated cached frames as frames from
that live connection, and could assign a real stream id instead of
treating the cached response as having no real stream.

The fix is to treat cached response parsing as cache-only regardless
of the current upstream peer connection: set the stream id to 0 and
skip live upstream control-frame handling while r->cached is set.

Closes: https://github.com/nginx/nginx/issues/1318
This commit is contained in:
Zhidao HONG authored and Sergey Kandaurov committed 2026-10-02 18:33:28 +04:00
1 parent 201c4d9c3c
commit 760240a10d
1 file changed
+16 -4
+16 -4
View File
@@ -160,6 +160,7 @@ static ngx_http_proxy_v2_ctx_t *
ngx_http_proxy_v2_get_ctx(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
ngx_http_proxy_v2_ctx_t *ctx, ngx_peer_connection_t *pc);
static ngx_inline ngx_int_t ngx_http_proxy_v2_cached(ngx_http_request_t *r);
static void ngx_http_proxy_v2_cleanup(void *data);
static void ngx_http_proxy_v2_abort_request(ngx_http_request_t *r);
@@ -1499,7 +1500,7 @@ ngx_http_proxy_v2_process_header(ngx_http_request_t *r)
/* frame payload */
if (u->peer.connection) {
if (!ngx_http_proxy_v2_cached(r)) {
if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
rc = ngx_http_proxy_v2_parse_rst_stream(r, ctx, b);
@@ -4162,9 +4163,7 @@ ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
ngx_connection_t *c;
ngx_pool_cleanup_t *cln;
c = pc->connection;
if (c == NULL) {
if (ngx_http_proxy_v2_cached(r)) {
ctx->connection = ngx_palloc(r->pool, sizeof(ngx_http_proxy_v2_conn_t));
if (ctx->connection == NULL) {
return NGX_ERROR;
@@ -4175,6 +4174,8 @@ ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
goto done;
}
c = pc->connection;
if (pc->cached) {
/*
@@ -4230,6 +4231,17 @@ done:
}
static ngx_inline ngx_int_t
ngx_http_proxy_v2_cached(ngx_http_request_t *r)
{
#if (NGX_HTTP_CACHE)
return r->cached;
#else
return 0;
#endif
}
static void
ngx_http_proxy_v2_cleanup(void *data)
{