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
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);
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);
static void ngx_http_proxy_v2_cleanup(void *data);
static void ngx_http_proxy_v2_abort_request(ngx_http_request_t *r);
- 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);
if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
rc = ngx_http_proxy_v2_parse_rst_stream(r, ctx, b);
ngx_connection_t *c;
ngx_pool_cleanup_t *cln;
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;
ctx->connection = ngx_palloc(r->pool, sizeof(ngx_http_proxy_v2_conn_t));
if (ctx->connection == NULL) {
return NGX_ERROR;
+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)
{
static void
ngx_http_proxy_v2_cleanup(void *data)
{