Skip to content

Commit 6c50b9a

Browse files
authored
cache-control: add must-revalidate, proxy-revalidate, s-maxage (#39)
1 parent 22ed925 commit 6c50b9a

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

lib/protocol/http/header/cache_control.rb

+36-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Released under the MIT License.
44
# Copyright, 2020-2023, by Samuel Williams.
5+
# Copyright, 2023, by Thomas Morgan.
56

67
require_relative 'split'
78

@@ -14,11 +15,15 @@ class CacheControl < Split
1415
NO_CACHE = 'no-cache'
1516
NO_STORE = 'no-store'
1617
MAX_AGE = 'max-age'
18+
S_MAXAGE = 's-maxage'
1719

1820
STATIC = 'static'
1921
DYNAMIC = 'dynamic'
2022
STREAMING = 'streaming'
2123

24+
MUST_REVALIDATE = 'must-revalidate'
25+
PROXY_REVALIDATE = 'proxy-revalidate'
26+
2227
def initialize(value = nil)
2328
super(value&.downcase)
2429
end
@@ -55,11 +60,40 @@ def no_store?
5560
self.include?(NO_STORE)
5661
end
5762

63+
# Indicates that a response must not be used once it is stale.
64+
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-must-revalidate
65+
def must_revalidate?
66+
self.include?(MUST_REVALIDATE)
67+
end
68+
69+
# Like must-revalidate, but for shared caches only.
70+
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-proxy-revalidate
71+
def proxy_revalidate?
72+
self.include?(PROXY_REVALIDATE)
73+
end
74+
75+
# The maximum time, in seconds, a response should be considered fresh.
76+
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-max-age-2
5877
def max_age
59-
if value = self.find{|value| value.start_with?(MAX_AGE)}
78+
find_integer_value(MAX_AGE)
79+
end
80+
81+
# Like max-age, but for shared caches only, which should use it before
82+
# max-age when present.
83+
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-s-maxage
84+
def s_maxage
85+
find_integer_value(S_MAXAGE)
86+
end
87+
88+
private
89+
90+
def find_integer_value(value_name)
91+
if value = self.find{|value| value.start_with?(value_name)}
6092
_, age = value.split('=', 2)
6193

62-
return Integer(age)
94+
if age =~ /\A[0-9]+\z/
95+
return Integer(age)
96+
end
6397
end
6498
end
6599
end

test/protocol/http/header/cache_control.rb

+28-1
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,29 @@
22

33
# Released under the MIT License.
44
# Copyright, 2023, by Samuel Williams.
5+
# Copyright, 2023, by Thomas Morgan.
56

67
require 'protocol/http/header/cache_control'
78

89
describe Protocol::HTTP::Header::CacheControl do
910
let(:header) {subject.new(description)}
1011

11-
with "max-age=60, public" do
12+
with "max-age=60, s-maxage=30, public" do
1213
it "correctly parses cache header" do
1314
expect(header).to have_attributes(
1415
public?: be == true,
1516
private?: be == false,
1617
max_age: be == 60,
18+
s_maxage: be == 30,
19+
)
20+
end
21+
end
22+
23+
with "max-age=-10, s-maxage=0x22" do
24+
it "gracefully handles invalid values" do
25+
expect(header).to have_attributes(
26+
max_age: be == nil,
27+
s_maxage: be == nil,
1728
)
1829
end
1930
end
@@ -51,6 +62,22 @@
5162
end
5263
end
5364

65+
with "must-revalidate" do
66+
it "correctly parses cache header" do
67+
expect(header).to have_attributes(
68+
must_revalidate?: be == true,
69+
)
70+
end
71+
end
72+
73+
with "proxy-revalidate" do
74+
it "correctly parses cache header" do
75+
expect(header).to have_attributes(
76+
proxy_revalidate?: be == true,
77+
)
78+
end
79+
end
80+
5481
with "#<<" do
5582
let(:header) {subject.new}
5683

0 commit comments

Comments
 (0)