|
9 | 9 | module Protocol
|
10 | 10 | module HTTP
|
11 | 11 | module Header
|
| 12 | + # Represents the `cache-control` header, which is a list of cache directives. |
12 | 13 | class CacheControl < Split
|
| 14 | + # The `private` directive indicates that the response is intended for a single user and must not be stored by shared caches. |
13 | 15 | PRIVATE = "private"
|
| 16 | + |
| 17 | + # The `public` directive indicates that the response may be stored by any cache, even if it would normally be considered non-cacheable. |
14 | 18 | PUBLIC = "public"
|
| 19 | + |
| 20 | + # The `no-cache` directive indicates that caches must revalidate the response with the origin server before serving it to clients. |
15 | 21 | NO_CACHE = "no-cache"
|
| 22 | + |
| 23 | + # The `no-store` directive indicates that caches must not store the response under any circumstances. |
16 | 24 | NO_STORE = "no-store"
|
| 25 | + |
| 26 | + # The `max-age` directive indicates the maximum amount of time, in seconds, that a response is considered fresh. |
17 | 27 | MAX_AGE = "max-age"
|
| 28 | + |
| 29 | + # The `s-maxage` directive is similar to `max-age` but applies only to shared caches. If both `s-maxage` and `max-age` are present, `s-maxage` takes precedence in shared caches. |
18 | 30 | S_MAXAGE = "s-maxage"
|
19 | 31 |
|
| 32 | + # The `static` directive is a custom directive often used to indicate that the resource is immutable or rarely changes, allowing longer caching periods. |
20 | 33 | STATIC = "static"
|
| 34 | + |
| 35 | + # The `dynamic` directive is a custom directive used to indicate that the resource is generated dynamically and may change frequently, requiring shorter caching periods. |
21 | 36 | DYNAMIC = "dynamic"
|
| 37 | + |
| 38 | + # The `streaming` directive is a custom directive used to indicate that the resource is intended for progressive or chunked delivery, such as live video streams. |
22 | 39 | STREAMING = "streaming"
|
23 | 40 |
|
| 41 | + # The `must-revalidate` directive indicates that once a response becomes stale, caches must not use it to satisfy subsequent requests without revalidating it with the origin server. |
24 | 42 | MUST_REVALIDATE = "must-revalidate"
|
| 43 | + |
| 44 | + # The `proxy-revalidate` directive is similar to `must-revalidate` but applies only to shared caches. |
25 | 45 | PROXY_REVALIDATE = "proxy-revalidate"
|
26 | 46 |
|
| 47 | + # Initializes the cache control header with the given value. The value is expected to be a comma-separated string of cache directives. |
| 48 | + # |
| 49 | + # @parameter value [String | Nil] the raw Cache-Control header value. |
27 | 50 | def initialize(value = nil)
|
28 | 51 | super(value&.downcase)
|
29 | 52 | end
|
30 | 53 |
|
| 54 | + # Adds a directive to the Cache-Control header. The value will be normalized to lowercase before being added. |
| 55 | + # |
| 56 | + # @parameter value [String] the directive to add. |
31 | 57 | def << value
|
32 | 58 | super(value.downcase)
|
33 | 59 | end
|
34 | 60 |
|
| 61 | + # @returns [Boolean] whether the `static` directive is present. |
35 | 62 | def static?
|
36 | 63 | self.include?(STATIC)
|
37 | 64 | end
|
38 | 65 |
|
| 66 | + # @returns [Boolean] whether the `dynamic` directive is present. |
39 | 67 | def dynamic?
|
40 | 68 | self.include?(DYNAMIC)
|
41 | 69 | end
|
42 | 70 |
|
| 71 | + # @returns [Boolean] whether the `streaming` directive is present. |
43 | 72 | def streaming?
|
44 | 73 | self.include?(STREAMING)
|
45 | 74 | end
|
46 | 75 |
|
| 76 | + # @returns [Boolean] whether the `private` directive is present. |
47 | 77 | def private?
|
48 | 78 | self.include?(PRIVATE)
|
49 | 79 | end
|
50 | 80 |
|
| 81 | + # @returns [Boolean] whether the `public` directive is present. |
51 | 82 | def public?
|
52 | 83 | self.include?(PUBLIC)
|
53 | 84 | end
|
54 | 85 |
|
| 86 | + # @returns [Boolean] whether the `no-cache` directive is present. |
55 | 87 | def no_cache?
|
56 | 88 | self.include?(NO_CACHE)
|
57 | 89 | end
|
58 | 90 |
|
| 91 | + # @returns [Boolean] whether the `no-store` directive is present. |
59 | 92 | def no_store?
|
60 | 93 | self.include?(NO_STORE)
|
61 | 94 | end
|
62 | 95 |
|
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 |
| 96 | + # @returns [Boolean] whether the `must-revalidate` directive is present. |
65 | 97 | def must_revalidate?
|
66 | 98 | self.include?(MUST_REVALIDATE)
|
67 | 99 | end
|
68 | 100 |
|
69 |
| - # Like must-revalidate, but for shared caches only. |
70 |
| - # See https://www.rfc-editor.org/rfc/rfc9111.html#name-proxy-revalidate |
| 101 | + # @returns [Boolean] whether the `proxy-revalidate` directive is present. |
71 | 102 | def proxy_revalidate?
|
72 | 103 | self.include?(PROXY_REVALIDATE)
|
73 | 104 | end
|
74 | 105 |
|
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 |
| 106 | + # @returns [Integer | Nil] the value of the `max-age` directive in seconds, or `nil` if the directive is not present or invalid. |
77 | 107 | def max_age
|
78 | 108 | find_integer_value(MAX_AGE)
|
79 | 109 | end
|
80 | 110 |
|
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 |
| 111 | + # @returns [Integer | Nil] the value of the `s-maxage` directive in seconds, or `nil` if the directive is not present or invalid. |
84 | 112 | def s_maxage
|
85 | 113 | find_integer_value(S_MAXAGE)
|
86 | 114 | end
|
87 | 115 |
|
88 | 116 | private
|
89 | 117 |
|
| 118 | + # Finds and parses an integer value from a directive. |
| 119 | + # |
| 120 | + # @parameter value_name [String] the directive name to search for (e.g., "max-age"). |
| 121 | + # @returns [Integer | Nil] the parsed integer value, or `nil` if not found or invalid. |
90 | 122 | def find_integer_value(value_name)
|
91 |
| - if value = self.find{|value| value.start_with?(value_name)} |
| 123 | + if value = self.find { |value| value.start_with?(value_name) } |
92 | 124 | _, age = value.split("=", 2)
|
93 | 125 |
|
94 | 126 | if age =~ /\A[0-9]+\z/
|
|
0 commit comments