Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/proxy/hdrs/MIME.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3812,9 +3812,13 @@ MIMEHdrImpl::recompute_cooked_stuff(MIMEField *changing_field_or_null, const std
csv_value_mask = 0;
m_cooked_stuff.m_cache_control.m_mask &= ~mask;
}
} else if (token_wks == MIME_VALUE_MAX_STALE.c_str()) {
// RFC 9111, Section 5.2.1.2: a valueless max-stale request
// directive permits a stale response of any age.
m_cooked_stuff.m_cache_control.m_secs_max_stale = INT_MAX;
} else {
// No '=' found, or whitespace before '='. This is malformed.
// For directives that require values, this is an error.
// No '=' found, or whitespace before '='. This is malformed
// for directives that require values.
// Clear the mask for this directive.
csv_value_mask = 0;
m_cooked_stuff.m_cache_control.m_mask &= ~mask;
Expand Down
6 changes: 6 additions & 0 deletions src/proxy/hdrs/unit_tests/test_HdrUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <cstring>
#include <cctype>
#include <bitset>
#include <climits>
#include <initializer_list>
#include <new>
#include <vector>
Expand Down Expand Up @@ -426,6 +427,11 @@ TEST_CASE("Cache-Control Valid Cooking", "[proxy][hdrutils]")
MIME_COOKED_MASK_CC_MAX_STALE,
0, 0, 100, 0},

{"max-stale without a value",
"Cache-Control: max-stale\r\n\r\n",
MIME_COOKED_MASK_CC_MAX_STALE,
0, 0, INT_MAX, 0},

{"min-fresh=60",
"Cache-Control: min-fresh=60\r\n\r\n",
MIME_COOKED_MASK_CC_MIN_FRESH,
Expand Down
73 changes: 72 additions & 1 deletion tests/gold_tests/cache/replay/cache-control-basic.replay.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ meta:

# Configuration section for autest integration
autest:
description: 'Test basic cache operations: miss, hit, no-cache-control, stale, and only-if-cached'
description: 'Test basic cache operations: miss, hit, no-cache-control, stale, only-if-cached, and max-stale'

dns:
name: 'dns-cache-basic'
Expand Down Expand Up @@ -221,3 +221,74 @@ sessions:
fields:
- [X-Cache, { value: "miss", as: equal }]
- [Cache-Control, { value: "no-store", as: equal }]

#############################################################################
# Test 6: Populate an entry for a valueless max-stale request
#############################################################################
- client-request:
method: GET
url: /max-stale
version: '1.1'
headers:
fields:
- [Host, www.example.com]
- [x-debug, "x-cache,x-cache-key,via"]
- [uuid, max-stale-populate]

server-response:
status: 200
reason: OK
headers:
fields:
- [Content-Type, text/plain]
- [Content-Length, "5"]
# max-age=0 makes the cached response stale immediately.
- [Cache-Control, "max-age=0"]
content:
encoding: plain
data: stale

proxy-response:
status: 200
headers:
fields:
- [X-Cache, { value: "miss", as: equal }]
content:
encoding: plain
data: stale
verify: { as: equal }

#############################################################################
# Test 7: Valueless max-stale permits serving a stale response of any age
#############################################################################
- client-request:
# Allow the cache write from the preceding transaction to finish.
delay: 100ms
method: GET
url: /max-stale
version: '1.1'
headers:
fields:
- [Host, www.example.com]
- [Cache-Control, "max-stale"]
- [x-debug, "x-cache,x-cache-key,via"]
- [uuid, max-stale-serve]

proxy-request:
expect: absent

# The server response is a sentinel and must not be used.
server-response:
status: 502
reason: Bad Gateway

proxy-response:
status: 200
headers:
fields:
# ATS reports an acceptable-stale lookup as a fresh cache hit.
- [X-Cache, { value: "hit-fresh", as: equal }]
content:
encoding: plain
data: stale
verify: { as: equal }