]> git.kaiwu.me - nginx.git/commitdiff
Proxy: fixed HTTP/2 upstream with revalidated cache send master
authorZhidao HONG <z.hong@f5.com>
Tue, 19 May 2026 07:59:56 +0000 (07:59 +0000)
committerhongzhidao <hongzhidao@gmail.com>
Tue, 14 Jul 2026 12:38:57 +0000 (20:38 +0800)
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
src/http/modules/ngx_http_proxy_v2_module.c

index 2a1ff74fbfa79ac7cf70aac4db49014e101cfc5d..cecc56ba841aba15664f4031cb28d9f7bf0d27f1 100644 (file)
@@ -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)
 {