This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 1796051ca3 Fix s-maxage not respected with Authorization headers
(#12668)
1796051ca3 is described below
commit 1796051ca30386eccd676009209ac88ec9ebc498
Author: Brian Neradt <[email protected]>
AuthorDate: Mon Feb 2 12:16:58 2026 -0600
Fix s-maxage not respected with Authorization headers (#12668)
According to RFC 7234 section 3.2, a shared cache can serve cached
responses to requests with Authorization headers if the response contains
one of the following Cache-Control directives: must-revalidate,
proxy-revalidate, public, or s-maxage. The implementation was missing the
check for s-maxage, causing requests with Authorization headers to always
bypass the cache even when s-maxage was present in the cached response.
This commit adds the missing check for s-maxage in the
AuthenticationNeeded()
function and includes comprehensive tests to verify the fix and prevent
regression.
Fixes #7227
---
src/proxy/http/HttpTransact.cc | 12 +-
tests/gold_tests/cache/cache-auth.test.py | 4 +
.../cache/replay/auth-s-maxage.replay.yaml | 204 +++++++++++++++++++++
3 files changed, 215 insertions(+), 5 deletions(-)
diff --git a/src/proxy/http/HttpTransact.cc b/src/proxy/http/HttpTransact.cc
index 4c2e67cd9d..0f5e689222 100644
--- a/src/proxy/http/HttpTransact.cc
+++ b/src/proxy/http/HttpTransact.cc
@@ -7512,11 +7512,11 @@ HttpTransact::what_is_document_freshness(State *s,
HTTPHdr *client_request, HTTP
HttpTransact::Authentication_t
HttpTransact::AuthenticationNeeded(const OverridableHttpConfigParams *p,
HTTPHdr *client_request, HTTPHdr *obj_response)
{
- ///////////////////////////////////////////////////////////////////////
- // from RFC2068, sec 14.8, if a client request has the Authorization //
- // header set, we can't serve it unless the response is public, or //
- // if it has a Cache-Control revalidate flag, and we do revalidate. //
- ///////////////////////////////////////////////////////////////////////
+
///////////////////////////////////////////////////////////////////////////////
+ // Per RFC 7234 section 3.2, if a client request has the Authorization
//
+ // header set, we can't serve a cached response unless the response has one
//
+ // of: must-revalidate, proxy-revalidate, public, or s-maxage directives.
//
+
///////////////////////////////////////////////////////////////////////////////
if ((p->cache_ignore_auth == 0) &&
client_request->presence(MIME_PRESENCE_AUTHORIZATION)) {
if (obj_response->is_cache_control_set(HTTP_VALUE_MUST_REVALIDATE.c_str())
||
@@ -7526,6 +7526,8 @@ HttpTransact::AuthenticationNeeded(const
OverridableHttpConfigParams *p, HTTPHdr
return Authentication_t::MUST_REVALIDATE;
} else if (obj_response->is_cache_control_set(HTTP_VALUE_PUBLIC.c_str())) {
return Authentication_t::SUCCESS;
+ } else if
(obj_response->is_cache_control_set(HTTP_VALUE_S_MAXAGE.c_str())) {
+ return Authentication_t::SUCCESS;
} else {
if (obj_response->field_find("@WWW-Auth"sv) &&
client_request->method_get_wksidx() == HTTP_WKSIDX_GET) {
return Authentication_t::CACHE_AUTH;
diff --git a/tests/gold_tests/cache/cache-auth.test.py
b/tests/gold_tests/cache/cache-auth.test.py
index 0861355464..e60064c3a4 100644
--- a/tests/gold_tests/cache/cache-auth.test.py
+++ b/tests/gold_tests/cache/cache-auth.test.py
@@ -23,3 +23,7 @@ Test authorization-related caching behaviors
# Verify proxy.config.http.cache.ignore_authentication behavior.
Test.ATSReplayTest(replay_file="replay/ignore_authentication.replay.yaml")
+
+# Verify that s-maxage allows serving cached responses to requests with
+# Authorization headers per RFC 7234 section 3.2
+Test.ATSReplayTest(replay_file="replay/auth-s-maxage.replay.yaml")
diff --git a/tests/gold_tests/cache/replay/auth-s-maxage.replay.yaml
b/tests/gold_tests/cache/replay/auth-s-maxage.replay.yaml
new file mode 100644
index 0000000000..2cf1d36431
--- /dev/null
+++ b/tests/gold_tests/cache/replay/auth-s-maxage.replay.yaml
@@ -0,0 +1,204 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This replay file tests RFC 7234 section 3.2:
+# A shared cache can serve cached responses to requests with Authorization
+# headers if the response has s-maxage directive (along with must-revalidate
+# and public).
+#
+# This replay file assumes that caching is enabled and
+# proxy.config.http.cache.ignore_authentication is set to 0 (current default).
+#
+meta:
+ version: "1.0"
+
+# Configuration section for autest integration
+autest:
+ description: 'Test s-maxage allows serving cached responses to requests with
Authorization headers per RFC 7234 section 3.2'
+
+ # Server configuration
+ server:
+ name: 'server-s-maxage'
+
+ # Client configuration
+ client:
+ name: 'client-s-maxage'
+
+ # ATS configuration
+ ats:
+ name: 'ts-auth-s-maxage'
+
+ # ATS process configuration
+ process_config:
+ enable_cache: true
+
+ # ATS records.config settings
+ records_config:
+ proxy.config.diags.debug.enabled: 1
+ proxy.config.diags.debug.tags: 'http'
+
+ # Remap configuration
+ remap_config:
+ - from: "/"
+ to: "http://127.0.0.1:{SERVER_HTTP_PORT}/"
+
+sessions:
+ - transactions:
+ # First request: Cache a 200 response with s-maxage.
+ - client-request:
+ method: "GET"
+ version: "1.1"
+ url: /auth/s-maxage-test
+ headers:
+ fields:
+ - [uuid, s-maxage-cache-fill]
+ - [Host, example.com]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [Content-Length, 16]
+ - [Cache-Control, "s-maxage=300"]
+
+ proxy-response:
+ status: 200
+
+ # Second request: Request with Authorization header should be served
from cache
+ # because response has s-maxage per RFC 7234 section 3.2.
+ - client-request:
+ # Add a delay so ATS has time to finish any caching IO for the
+ # previous transaction.
+ delay: 100ms
+ method: "GET"
+ version: "1.1"
+ url: /auth/s-maxage-test
+ headers:
+ fields:
+ - [uuid, s-maxage-with-auth]
+ - [Host, example.com]
+ - [Authorization, "Basic ZGVtbzphdHNAc3Ryb25ncHc="]
+
+ # The server should NOT be reached because the cached response
+ # with s-maxage should be served. Return 400 to verify caching.
+ server-response:
+ status: 400
+ reason: "Bad Request"
+ headers:
+ fields:
+ - [Content-Length, 0]
+
+ # Expect the cached 200 response per RFC 7234 section 3.2
+ proxy-response:
+ status: 200
+
+ - transactions:
+ # Test 2: Verify that public also works.
+ - client-request:
+ method: "GET"
+ version: "1.1"
+ url: /auth/public-test
+ headers:
+ fields:
+ - [uuid, public-cache-fill]
+ - [Host, example.com]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [Content-Length, 16]
+ - [Cache-Control, "public, max-age=300"]
+
+ proxy-response:
+ status: 200
+
+ # Request with Authorization header should be served from cache with
public
+ - client-request:
+ delay: 100ms
+ method: "GET"
+ version: "1.1"
+ url: /auth/public-test
+ headers:
+ fields:
+ - [uuid, public-with-auth]
+ - [Host, example.com]
+ - [Authorization, "Basic ZGVtbzphdHNAc3Ryb25ncHc="]
+
+ # The server should NOT be reached because the cached response
+ # with public should be served. Return 400 to verify caching.
+ server-response:
+ status: 400
+ reason: "Bad Request"
+ headers:
+ fields:
+ - [Content-Length, 0]
+
+ # Expect cached 200 response
+ proxy-response:
+ status: 200
+
+ - transactions:
+ # Test 3: Without s-maxage or public, Authorization should require
revalidation
+ - client-request:
+ method: "GET"
+ version: "1.1"
+ url: /auth/no-directive-test
+ headers:
+ fields:
+ - [uuid, no-directive-cache-fill]
+ - [Host, example.com]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [Content-Length, 16]
+ - [Cache-Control, "max-age=300"]
+
+ proxy-response:
+ status: 200
+
+ # Request with Authorization header should NOT be served from cache
+ - client-request:
+ delay: 100ms
+ method: "GET"
+ version: "1.1"
+ url: /auth/no-directive-test
+ headers:
+ fields:
+ - [uuid, no-directive-with-auth]
+ - [Host, example.com]
+ - [Authorization, "Basic ZGVtbzphdHNAc3Ryb25ncHc="]
+
+ # The request should be forwarded to the server and a 404 response
+ # should be returned.
+ server-response:
+ status: 404
+ reason: "Not Found"
+ headers:
+ fields:
+ - [Content-Length, 20]
+
+ # Expect the new 404 response from server rather than the previous 200
+ # response.
+ proxy-response:
+ status: 404
+