From: Zhidao HONG Date: Tue, 19 May 2026 07:59:56 +0000 (+0000) Subject: Proxy: fixed HTTP/2 upstream with revalidated cache send X-Git-Url: http://git.kaiwu.me/http/doc/static/$%7BGITURL%7D/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;ds=inline;p=nginx.git 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 --- diff --git a/src/http/modules/ngx_http_proxy_v2_module.c b/src/http/modules/ngx_http_proxy_v2_module.c index 2a1ff74fb..cecc56ba8 100644 --- a/src/http/modules/ngx_http_proxy_v2_module.c +++ b/src/http/modules/ngx_http_proxy_v2_module.c @@ -161,6 +161,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); @@ -1451,7 +1452,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); @@ -4141,9 +4142,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; @@ -4154,6 +4153,8 @@ ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r, goto done; } + c = pc->connection; + if (pc->cached) { /* @@ -4209,6 +4210,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) {