From b2d7dac56f0f67f2279bcb4abc68a1d3da335df3 Mon Sep 17 00:00:00 2001 From: jake champion Date: Wed, 29 Oct 2025 16:40:45 +0000 Subject: [PATCH] Fixes Accept-Encoding cache variance behavior Changes the condition to only ignore Accept-Encoding variance when explicitly set to 1, preserving proper Vary header semantics for the default value of 2. Updates test expectations to reflect correct cache miss behavior when different Accept-Encoding variants are requested, ensuring each encoding type gets its own cache entry with appropriate Content-Encoding headers. --- src/iocore/cache/HttpTransactCache.cc | 6 +- .../normalized_ae_match_vary_cache.test.py | 31 ++++++++++ ...malized_ae_varied_transactions.replay.yaml | 59 ++++++++++--------- 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/iocore/cache/HttpTransactCache.cc b/src/iocore/cache/HttpTransactCache.cc index 021985fff47..47117ad90ee 100644 --- a/src/iocore/cache/HttpTransactCache.cc +++ b/src/iocore/cache/HttpTransactCache.cc @@ -1244,7 +1244,11 @@ HttpTransactCache::CalcVariability(const HttpConfigAccessor *http_config_params, // Disable Vary mismatch checking for Accept-Encoding. This is only safe to // set if you are promising to fix any Accept-Encoding/Content-Encoding mismatches. - if (http_config_params->get_ignore_accept_encoding_mismatch() && + // Only suppress variability checks when the operator explicitly set + // proxy.config.http.cache.ignore_accept_encoding_mismatch to 1. The + // documented default value of 2 should continue to enforce Vary header + // semantics whenever the origin sends one. + if ((http_config_params->get_ignore_accept_encoding_mismatch() == 1) && !strcasecmp(const_cast(field->str), "Accept-Encoding")) { continue; } diff --git a/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py b/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py index 991d2fda32b..f8a70b6cc32 100644 --- a/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py +++ b/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py @@ -31,6 +31,37 @@ replay_file = "replays/normalized_ae_varied_transactions.replay.yaml" server = Test.MakeVerifierServerProcess("server", replay_file) +# Verify that cache hit requests never reach the server +# Case 2 (normalize_ae:1) cache hits +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 12", "Verify empty Accept-Encoding (uuid 12) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 13", "Verify deflate request (uuid 13) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 14", "Verify br,compress request (uuid 14) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 16", "Verify br,compress,gzip request (uuid 16) is a cache hit and doesn't reach the server.") +# Case 3 (normalize_ae:2) cache hits +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 22", "Verify empty Accept-Encoding (uuid 22) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 23", "Verify deflate request (uuid 23) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 26", "Verify br,compress,gzip request (uuid 26) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 27", "Verify compress,gzip request (uuid 27) is a cache hit and doesn't reach the server.") +# Case 4 (normalize_ae:3) cache hits +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 32", "Verify empty Accept-Encoding (uuid 32) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 33", "Verify deflate request (uuid 33) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 37", "Verify compress,gzip request (uuid 37) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 38", "Verify br;q=1.1 request (uuid 38) is a cache hit and doesn't reach the server.") +server.Streams.stdout += Testers.ExcludesExpression( + "uuid: 39", "Verify br,gzip;q=0.8 request (uuid 39) is a cache hit and doesn't reach the server.") + ts = Test.MakeATSProcess("ts", enable_cache=True) ts.Disk.remap_config.AddLine( f"map http://www.ae-0.com http://127.0.0.1:{server.Variables.http_port}" + diff --git a/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml b/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml index 57842341a59..8582152b7fa 100644 --- a/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml +++ b/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml @@ -96,7 +96,7 @@ sessions: - [ X-Response-Identifier, { value: Empty-Accept-Encoding, as: equal } ] - [ X-Cache, { value: miss, as: equal } ] - # Accept-Encoding header deflate would match the alternate of empty Accept-Encoding header + # request deflate Accept-Encoding when origin lacks that variant - client-request: method: "GET" version: "1.1" @@ -113,13 +113,12 @@ sessions: <<: *404_response proxy-response: - status: 200 + status: 404 headers: fields: - - [ X-Response-Identifier, { value: Empty-Accept-Encoding, as: equal } ] - - [ X-Cache, { value: hit-fresh, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] - # Accept-Encoding header br, compress would match the alternate of empty Accept-Encoding header + # load an alternate of br Accept-Encoding header - client-request: method: "GET" version: "1.1" @@ -133,14 +132,23 @@ sessions: delay: 100ms server-response: - <<: *404_response + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Content-Encoding, br ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Br-Accept-Encoding ] proxy-response: status: 200 headers: fields: - - [ X-Response-Identifier, { value: Empty-Accept-Encoding, as: equal } ] - - [ X-Cache, { value: hit-fresh, as: equal } ] + - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] # load an alternate of gzip Accept-Encoding header - client-request: @@ -176,7 +184,7 @@ sessions: - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] - [ X-Cache, { value: miss, as: equal } ] - # Accept-Encoding header br, compress, gzip would match the alternate of gzip Accept-Encoding header + # load an alternate of br Accept-Encoding header - client-request: method: "GET" version: "1.1" @@ -190,14 +198,23 @@ sessions: delay: 100ms server-response: - <<: *404_response + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Content-Encoding, br ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Br-Accept-Encoding ] proxy-response: status: 200 headers: fields: - - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] - - [ X-Cache, { value: hit-fresh, as: equal } ] + - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] # Case 2 proxy.config.http.normalize_ae:1 @@ -699,10 +716,6 @@ sessions: - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] - [ X-Cache, { value: miss, as: equal } ] - # NOTICE: This case should load an alternate of br, gzip Accept-Encoding header. - # However, due to the implementation of calculate_quality_of_match(), - # ATS matches the alternate of gzip Accept-Encoding header. - # The result is DIFFERENT from the description of proxy.config.http.normalize_ae: 3 - client-request: method: "GET" version: "1.1" @@ -733,10 +746,8 @@ sessions: status: 200 headers: fields: - # - [ X-Response-Identifier, { value: Br-Gzip-Accept-Encoding, as: equal } ] - # - [ X-Cache, { value: miss, as: equal } ] - - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] - - [ X-Cache, { value: hit-fresh, as: equal } ] + - [ X-Response-Identifier, { value: Br-Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] # Accept-Encoding header compress, gzip would match the alternate of gzip Accept-Encoding header - client-request: @@ -784,11 +795,6 @@ sessions: - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] - [ X-Cache, { value: hit-fresh, as: equal } ] - # NOTICE: This case should make Accept-Encoding header br, gzip;q=0.8 match - # the alternate of br, gzip Accept-Encoding header. - # However, due to the implementation of calculate_quality_of_match(), - # ATS matches the alternate of gzip Accept-Encoding header. - # The result is DIFFERENT from the description of proxy.config.http.normalize_ae: 3 - client-request: method: "GET" version: "1.1" @@ -808,6 +814,5 @@ sessions: status: 200 headers: fields: - # - [ X-Response-Identifier, { value: Br-Gzip-Accept-Encoding, as: equal } ] - - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Response-Identifier, { value: Br-Gzip-Accept-Encoding, as: equal } ] - [ X-Cache, { value: hit-fresh, as: equal } ]