rack-cache 1.13.0 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES +4 -0
- data/README.md +9 -9
- data/lib/rack/cache/cache_control.rb +12 -12
- data/lib/rack/cache/context.rb +9 -9
- data/lib/rack/cache/entity_store.rb +1 -1
- data/lib/rack/cache/headers.rb +21 -0
- data/lib/rack/cache/meta_store.rb +9 -10
- data/lib/rack/cache/options.rb +6 -6
- data/lib/rack/cache/request.rb +2 -2
- data/lib/rack/cache/response.rb +42 -42
- data/lib/rack/cache/version.rb +5 -0
- data/lib/rack/cache.rb +2 -2
- metadata +39 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e551d4e48499cda1a41809df4010eaf84bb5cf75edb113543a803cf4b7a5f2a6
|
4
|
+
data.tar.gz: 33d4f98db1ba1c858bbf0337e249c7d121e0f14f3705e00934f2adb29ddccddc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d068832ba4eb458626148d0ccd9d4485f82305934fa97201b8b4d2ffad975a50e2c8152129c2a0f95971ed172184246e9dcd12de308324dbdb7b04f4792d9537
|
7
|
+
data.tar.gz: 035b6979668d9315fb9a29f081df044c64f34380f54dd4c16b0b3a13534fe205fae9d2d30bcd8fe682f2747b5aa8ab40e736fea1774841364165da80065d0b66
|
data/CHANGES
CHANGED
data/README.md
CHANGED
@@ -2,21 +2,21 @@ Rack::Cache
|
|
2
2
|
===========
|
3
3
|
|
4
4
|
Rack::Cache is suitable as a quick drop-in component to enable HTTP caching for
|
5
|
-
Rack-based applications that produce freshness (
|
6
|
-
validation (
|
5
|
+
Rack-based applications that produce freshness (`expires`, `cache-control`)
|
6
|
+
and/or validation (`last-modified`, `etag`) information:
|
7
7
|
|
8
8
|
* Standards-based (RFC 2616)
|
9
9
|
* Freshness/expiration based caching
|
10
|
-
* Validation (
|
11
|
-
*
|
12
|
-
*
|
13
|
-
and proxy-revalidate
|
10
|
+
* Validation (`if-modified-since` / `if-none-match`)
|
11
|
+
* `vary` support
|
12
|
+
* `cache-control` `public`, `private`, `max-age`, `s-maxage`, `must-revalidate`,
|
13
|
+
and `proxy-revalidate`.
|
14
14
|
* Portable: 100% Ruby / works with any Rack-enabled framework
|
15
15
|
* Disk, memcached, and heap memory storage backends
|
16
16
|
|
17
17
|
For more information about Rack::Cache features and usage, see:
|
18
18
|
|
19
|
-
https://
|
19
|
+
https://rack.github.io/rack-cache/
|
20
20
|
|
21
21
|
Rack::Cache is not overly optimized for performance. The main goal of the
|
22
22
|
project is to provide a portable, easy-to-configure, and standards-based
|
@@ -95,7 +95,7 @@ Noop entity store
|
|
95
95
|
|
96
96
|
Does not persist response bodies (no disk/memory used).<br/>
|
97
97
|
Responses from the cache will have an empty body.<br/>
|
98
|
-
Clients must ignore these empty cached response (check for
|
98
|
+
Clients must ignore these empty cached response (check for `x-rack-cache` response header).<br/>
|
99
99
|
Atm cannot handle streamed responses, patch needed.
|
100
100
|
|
101
101
|
```Ruby
|
@@ -123,4 +123,4 @@ Rack::Cache::Key.query_string_ignore = proc { |k, v| k =~ /^(trk|utm)_/ }
|
|
123
123
|
```
|
124
124
|
|
125
125
|
License: MIT<br/>
|
126
|
-
[![
|
126
|
+
[![Development](https://github.com/rack/rack-cache/actions/workflows/development.yml/badge.svg)](https://github.com/rack/rack-cache/actions/workflows/development.yml)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Rack
|
2
2
|
module Cache
|
3
3
|
|
4
|
-
# Parses a
|
4
|
+
# Parses a cache-control header and exposes the directives as a Hash.
|
5
5
|
# Directives that do not have values are set to +true+.
|
6
6
|
class CacheControl < Hash
|
7
7
|
def initialize(value=nil)
|
@@ -80,7 +80,7 @@ module Rack
|
|
80
80
|
end
|
81
81
|
|
82
82
|
# The expiration time of an entity MAY be specified by the origin
|
83
|
-
# server using the
|
83
|
+
# server using the expires header (see section 14.21). Alternatively,
|
84
84
|
# it MAY be specified using the max-age directive in a response. When
|
85
85
|
# the max-age cache-control directive is present in a cached response,
|
86
86
|
# the response is stale if its current age is greater than the age
|
@@ -89,19 +89,19 @@ module Rack
|
|
89
89
|
# response is cacheable (i.e., "public") unless some other, more
|
90
90
|
# restrictive cache directive is also present.
|
91
91
|
#
|
92
|
-
# If a response includes both an
|
93
|
-
# directive, the max-age directive overrides the
|
94
|
-
# if the
|
92
|
+
# If a response includes both an expires header and a max-age
|
93
|
+
# directive, the max-age directive overrides the expires header, even
|
94
|
+
# if the expires header is more restrictive. This rule allows an origin
|
95
95
|
# server to provide, for a given response, a longer expiration time to
|
96
96
|
# an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
|
97
97
|
# useful if certain HTTP/1.0 caches improperly calculate ages or
|
98
98
|
# expiration times, perhaps due to desynchronized clocks.
|
99
99
|
#
|
100
|
-
# Many HTTP/1.0 cache implementations will treat an
|
100
|
+
# Many HTTP/1.0 cache implementations will treat an expires value that
|
101
101
|
# is less than or equal to the response Date value as being equivalent
|
102
|
-
# to the
|
102
|
+
# to the cache-control response directive "no-cache". If an HTTP/1.1
|
103
103
|
# cache receives such a response, and the response does not include a
|
104
|
-
#
|
104
|
+
# cache-control header field, it SHOULD consider the response to be
|
105
105
|
# non-cacheable in order to retain compatibility with HTTP/1.0 servers.
|
106
106
|
#
|
107
107
|
# When the max-age directive is included in the request, it indicates
|
@@ -114,7 +114,7 @@ module Rack
|
|
114
114
|
# If a response includes an s-maxage directive, then for a shared
|
115
115
|
# cache (but not for a private cache), the maximum age specified by
|
116
116
|
# this directive overrides the maximum age specified by either the
|
117
|
-
# max-age directive or the
|
117
|
+
# max-age directive or the expires header. The s-maxage directive
|
118
118
|
# also implies the semantics of the proxy-revalidate directive. i.e.,
|
119
119
|
# that the shared cache must not use the entry after it becomes stale
|
120
120
|
# to respond to a subsequent request without first revalidating it with
|
@@ -128,7 +128,7 @@ module Rack
|
|
128
128
|
# If a response includes a r-maxage directive, then for a reverse cache
|
129
129
|
# (but not for a private or proxy cache), the maximum age specified by
|
130
130
|
# this directive overrides the maximum age specified by either the max-age
|
131
|
-
# directive, the s-maxage directive, or the
|
131
|
+
# directive, the s-maxage directive, or the expires header. The r-maxage
|
132
132
|
# directive also implies the semantics of the proxy-revalidate directive.
|
133
133
|
# i.e., that the reverse cache must not use the entry after it becomes
|
134
134
|
# stale to respond to a subsequent request without first revalidating it
|
@@ -148,7 +148,7 @@ module Rack
|
|
148
148
|
# MUST NOT use the entry after it becomes stale to respond to a
|
149
149
|
# subsequent request without first revalidating it with the origin
|
150
150
|
# server. (I.e., the cache MUST do an end-to-end revalidation every
|
151
|
-
# time, if, based solely on the origin server's
|
151
|
+
# time, if, based solely on the origin server's expires or max-age
|
152
152
|
# value, the cached response is stale.)
|
153
153
|
#
|
154
154
|
# The must-revalidate directive is necessary to support reliable
|
@@ -196,7 +196,7 @@ module Rack
|
|
196
196
|
private
|
197
197
|
|
198
198
|
def parse(value)
|
199
|
-
return
|
199
|
+
return if value.nil? || value.empty?
|
200
200
|
value.delete(' ').split(',').each do |part|
|
201
201
|
next if part.empty?
|
202
202
|
name, value = part.split('=', 2)
|
data/lib/rack/cache/context.rb
CHANGED
@@ -76,9 +76,9 @@ module Rack::Cache
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
# log trace and set
|
79
|
+
# log trace and set x-rack-cache tracing header
|
80
80
|
trace = @trace.join(', ')
|
81
|
-
response.headers['
|
81
|
+
response.headers['x-rack-cache'] = trace
|
82
82
|
|
83
83
|
# write log message to rack.errors
|
84
84
|
if verbose?
|
@@ -113,7 +113,7 @@ module Rack::Cache
|
|
113
113
|
@private_header_keys.any? { |key| @env.key?(key) }
|
114
114
|
end
|
115
115
|
|
116
|
-
# Determine if the #response validators (
|
116
|
+
# Determine if the #response validators (etag, last-modified) matches
|
117
117
|
# a conditional value specified in #request.
|
118
118
|
def not_modified?(response)
|
119
119
|
last_modified = @request.env['HTTP_IF_MODIFIED_SINCE']
|
@@ -181,7 +181,7 @@ module Rack::Cache
|
|
181
181
|
if entry
|
182
182
|
if fresh_enough?(entry)
|
183
183
|
record :fresh
|
184
|
-
entry.headers['
|
184
|
+
entry.headers['age'] = entry.age.to_s
|
185
185
|
entry
|
186
186
|
else
|
187
187
|
record :stale
|
@@ -204,7 +204,7 @@ module Rack::Cache
|
|
204
204
|
rescue => e
|
205
205
|
record :connnection_failed
|
206
206
|
age = entry.age.to_s
|
207
|
-
entry.headers['
|
207
|
+
entry.headers['age'] = age
|
208
208
|
record "Fail-over to stale cache data with age #{age} due to #{e.class.name}: #{e}"
|
209
209
|
entry
|
210
210
|
end
|
@@ -232,12 +232,12 @@ module Rack::Cache
|
|
232
232
|
record :valid
|
233
233
|
|
234
234
|
# Check if the response validated which is not cached here
|
235
|
-
etag = response.headers['
|
235
|
+
etag = response.headers['etag']
|
236
236
|
return response if etag && request_etags.include?(etag) && !cached_etags.include?(etag)
|
237
237
|
|
238
238
|
entry = entry.dup
|
239
|
-
entry.headers.delete('
|
240
|
-
%w[Date
|
239
|
+
entry.headers.delete('date')
|
240
|
+
%w[Date expires cache-control etag last-modified].each do |name|
|
241
241
|
next unless value = response.headers[name]
|
242
242
|
entry.headers[name] = value
|
243
243
|
end
|
@@ -287,7 +287,7 @@ module Rack::Cache
|
|
287
287
|
def store(response)
|
288
288
|
strip_ignore_headers(response)
|
289
289
|
metastore.store(@request, response, entitystore)
|
290
|
-
response.headers['
|
290
|
+
response.headers['age'] = response.age.to_s
|
291
291
|
rescue => e
|
292
292
|
log_error(e)
|
293
293
|
nil
|
@@ -341,7 +341,7 @@ module Rack::Cache
|
|
341
341
|
# Set `entitystore` to 'noop:/'.
|
342
342
|
# Does not persist response bodies (no disk/memory used).
|
343
343
|
# Responses from the cache will have an empty body.
|
344
|
-
# Clients must ignore these empty cached response (check for
|
344
|
+
# Clients must ignore these empty cached response (check for x-rack-cache response header).
|
345
345
|
# Atm cannot handle streamed responses, patch needed.
|
346
346
|
#
|
347
347
|
class Noop < EntityStore
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Rack::Cache
|
2
|
+
begin
|
3
|
+
# For `Rack::Headers` (Rack 3+):
|
4
|
+
require "rack/headers"
|
5
|
+
Headers = ::Rack::Headers
|
6
|
+
def self.Headers(headers)
|
7
|
+
Headers[headers]
|
8
|
+
end
|
9
|
+
rescue LoadError
|
10
|
+
# For `Rack::Utils::HeaderHash`:
|
11
|
+
require "rack/utils"
|
12
|
+
Headers = ::Rack::Utils::HeaderHash
|
13
|
+
def self.Headers(headers)
|
14
|
+
if headers.is_a?(Headers) && !headers.frozen?
|
15
|
+
return headers
|
16
|
+
else
|
17
|
+
return Headers.new(headers)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -34,11 +34,11 @@ module Rack::Cache
|
|
34
34
|
|
35
35
|
# find a cached entry that matches the request.
|
36
36
|
env = request.env
|
37
|
-
match = entries.detect{ |req,res| requests_match?((res['
|
37
|
+
match = entries.detect{ |req,res| requests_match?((res['vary'] || res['vary']), env, req) }
|
38
38
|
return nil if match.nil?
|
39
39
|
|
40
40
|
_, res = match
|
41
|
-
if body = entity_store.open(res['
|
41
|
+
if body = entity_store.open(res['x-content-digest'])
|
42
42
|
restore_response(res, body)
|
43
43
|
else
|
44
44
|
# the metastore referenced an entity that doesn't exist in
|
@@ -64,14 +64,14 @@ module Rack::Cache
|
|
64
64
|
|
65
65
|
# write the response body to the entity store if this is the
|
66
66
|
# original response.
|
67
|
-
if response.headers['
|
67
|
+
if response.headers['x-content-digest'].nil?
|
68
68
|
if request.env['rack-cache.use_native_ttl'] && response.fresh?
|
69
69
|
digest, size = entity_store.write(response.body, response.ttl)
|
70
70
|
else
|
71
71
|
digest, size = entity_store.write(response.body)
|
72
72
|
end
|
73
|
-
response.headers['
|
74
|
-
response.headers['
|
73
|
+
response.headers['x-content-digest'] = digest
|
74
|
+
response.headers['content-length'] = size.to_s unless response.headers['Transfer-Encoding']
|
75
75
|
|
76
76
|
# If the entitystore backend is a Noop, do not try to read the body from the backend, it always returns an empty array
|
77
77
|
unless entity_store.is_a? Rack::Cache::EntityStore::Noop
|
@@ -91,12 +91,11 @@ module Rack::Cache
|
|
91
91
|
vary = response.vary
|
92
92
|
entries =
|
93
93
|
read(key).reject do |env, res|
|
94
|
-
(vary == (res['
|
94
|
+
(vary == (res['vary'])) &&
|
95
95
|
requests_match?(vary, env, stored_env)
|
96
96
|
end
|
97
97
|
|
98
98
|
headers = persist_response(response)
|
99
|
-
headers.delete('Age')
|
100
99
|
headers.delete('age')
|
101
100
|
|
102
101
|
entries.unshift [stored_env, headers]
|
@@ -146,13 +145,13 @@ module Rack::Cache
|
|
146
145
|
# Converts a stored response hash into a Response object. The caller
|
147
146
|
# is responsible for loading and passing the body if needed.
|
148
147
|
def restore_response(hash, body=[])
|
149
|
-
status = hash.delete('
|
148
|
+
status = hash.delete('x-status').to_i
|
150
149
|
Rack::Cache::Response.new(status, hash, body)
|
151
150
|
end
|
152
151
|
|
153
152
|
def persist_response(response)
|
154
|
-
hash = response.headers.
|
155
|
-
hash['
|
153
|
+
hash = response.headers.dup
|
154
|
+
hash['x-status'] = response.status.to_s
|
156
155
|
hash
|
157
156
|
end
|
158
157
|
|
data/lib/rack/cache/options.rb
CHANGED
@@ -72,7 +72,7 @@ module Rack::Cache
|
|
72
72
|
|
73
73
|
# The number of seconds that a cache entry should be considered
|
74
74
|
# "fresh" when no explicit freshness information is provided in
|
75
|
-
# a response. Explicit
|
75
|
+
# a response. Explicit cache-control or expires headers
|
76
76
|
# override this value.
|
77
77
|
#
|
78
78
|
# Default: 0
|
@@ -83,12 +83,12 @@ module Rack::Cache
|
|
83
83
|
# example, in most cases, it makes sense to prevent cookies from being
|
84
84
|
# stored in the cache.
|
85
85
|
#
|
86
|
-
# Default: ['
|
86
|
+
# Default: ['set-cookie']
|
87
87
|
option_accessor :ignore_headers
|
88
88
|
|
89
89
|
# Set of request headers that trigger "private" cache-control behavior
|
90
90
|
# on responses that don't explicitly state whether the response is
|
91
|
-
# public or private via a
|
91
|
+
# public or private via a cache-control directive. Applications that use
|
92
92
|
# cookies for authorization may need to add the 'Cookie' header to this
|
93
93
|
# list.
|
94
94
|
#
|
@@ -96,11 +96,11 @@ module Rack::Cache
|
|
96
96
|
option_accessor :private_headers
|
97
97
|
|
98
98
|
# Specifies whether a client can force cache reload by including a
|
99
|
-
#
|
99
|
+
# cache-control "no-cache" directive in the request. Disabled by default.
|
100
100
|
option_accessor :allow_reload
|
101
101
|
|
102
102
|
# Specifies whether a client can force cache revalidate by including a
|
103
|
-
#
|
103
|
+
# cache-control "max-age=0" directive in the request. Disabled by default.
|
104
104
|
option_accessor :allow_revalidate
|
105
105
|
|
106
106
|
# Specifies whether the underlying entity store's native expiration should
|
@@ -148,7 +148,7 @@ module Rack::Cache
|
|
148
148
|
'rack-cache.metastore' => 'heap:/',
|
149
149
|
'rack-cache.entitystore' => 'heap:/',
|
150
150
|
'rack-cache.default_ttl' => 0,
|
151
|
-
'rack-cache.ignore_headers' => ['
|
151
|
+
'rack-cache.ignore_headers' => ['set-cookie'],
|
152
152
|
'rack-cache.private_headers' => ['Authorization', 'Cookie'],
|
153
153
|
'rack-cache.allow_reload' => false,
|
154
154
|
'rack-cache.allow_revalidate' => false,
|
data/lib/rack/cache/request.rb
CHANGED
@@ -18,12 +18,12 @@ module Rack::Cache
|
|
18
18
|
@env['REQUEST_METHOD']
|
19
19
|
end
|
20
20
|
|
21
|
-
# A CacheControl instance based on the request's
|
21
|
+
# A CacheControl instance based on the request's cache-control header.
|
22
22
|
def cache_control
|
23
23
|
@cache_control ||= CacheControl.new(env['HTTP_CACHE_CONTROL'])
|
24
24
|
end
|
25
25
|
|
26
|
-
# True when the
|
26
|
+
# True when the cache-control/no-cache directive is present or the
|
27
27
|
# Pragma header is set to no-cache.
|
28
28
|
def no_cache?
|
29
29
|
cache_control['no-cache'] ||
|
data/lib/rack/cache/response.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'time'
|
2
2
|
require 'set'
|
3
3
|
require 'rack/response'
|
4
|
-
require 'rack/utils'
|
5
4
|
require 'rack/cache/cache_control'
|
6
5
|
|
7
|
-
|
6
|
+
require_relative 'headers'
|
8
7
|
|
8
|
+
module Rack::Cache
|
9
9
|
# Provides access to the response generated by the downstream application. The
|
10
10
|
# +response+, +original_response+, and +entry+ objects exposed by the Core
|
11
11
|
# caching engine are instances of this class.
|
@@ -31,10 +31,10 @@ module Rack::Cache
|
|
31
31
|
# and body.
|
32
32
|
def initialize(status, headers, body)
|
33
33
|
@status = status.to_i
|
34
|
-
@headers = Rack::
|
34
|
+
@headers = Rack::Cache::Headers(headers)
|
35
35
|
@body = body
|
36
36
|
@now = Time.now
|
37
|
-
@headers['
|
37
|
+
@headers['date'] ||= @now.httpdate
|
38
38
|
end
|
39
39
|
|
40
40
|
def initialize_copy(other)
|
@@ -62,15 +62,15 @@ module Rack::Cache
|
|
62
62
|
410 # Gone
|
63
63
|
].to_set
|
64
64
|
|
65
|
-
# A Hash of name=value pairs that correspond to the
|
65
|
+
# A Hash of name=value pairs that correspond to the cache-control header.
|
66
66
|
# Valueless parameters (e.g., must-revalidate, no-store) have a Hash value
|
67
|
-
# of true. This method always returns a Hash, empty if no
|
67
|
+
# of true. This method always returns a Hash, empty if no cache-control
|
68
68
|
# header is present.
|
69
69
|
def cache_control
|
70
|
-
@cache_control ||= CacheControl.new(headers['
|
70
|
+
@cache_control ||= CacheControl.new(headers['cache-control'])
|
71
71
|
end
|
72
72
|
|
73
|
-
# Set the
|
73
|
+
# Set the cache-control header to the values specified by the Hash. See
|
74
74
|
# the #cache_control method for information on expected Hash structure.
|
75
75
|
def cache_control=(value)
|
76
76
|
if value.respond_to? :to_hash
|
@@ -80,26 +80,26 @@ module Rack::Cache
|
|
80
80
|
end
|
81
81
|
|
82
82
|
if value.nil? || value.empty?
|
83
|
-
headers.delete('
|
83
|
+
headers.delete('cache-control')
|
84
84
|
else
|
85
|
-
headers['
|
85
|
+
headers['cache-control'] = value
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
# Determine if the response is "fresh". Fresh responses may be served from
|
90
90
|
# cache without any interaction with the origin. A response is considered
|
91
|
-
# fresh when it includes a
|
91
|
+
# fresh when it includes a cache-control/max-age indicator or Expiration
|
92
92
|
# header and the calculated age is less than the freshness lifetime.
|
93
93
|
def fresh?
|
94
94
|
ttl && ttl > 0
|
95
95
|
end
|
96
96
|
|
97
97
|
# Determine if the response is worth caching under any circumstance. Responses
|
98
|
-
# marked "private" with an explicit
|
98
|
+
# marked "private" with an explicit cache-control directive are considered
|
99
99
|
# uncacheable
|
100
100
|
#
|
101
|
-
# Responses with neither a freshness lifetime (
|
102
|
-
# validator (
|
101
|
+
# Responses with neither a freshness lifetime (expires, max-age) nor cache
|
102
|
+
# validator (last-modified, etag) are considered uncacheable.
|
103
103
|
def cacheable?
|
104
104
|
return false unless CACHEABLE_RESPONSE_CODES.include?(status)
|
105
105
|
return false if cache_control.no_store? || cache_control.private?
|
@@ -109,7 +109,7 @@ module Rack::Cache
|
|
109
109
|
# Determine if the response includes headers that can be used to validate
|
110
110
|
# the response with the origin using a conditional GET request.
|
111
111
|
def validateable?
|
112
|
-
headers.key?('
|
112
|
+
headers.key?('last-modified') || headers.key?('etag')
|
113
113
|
end
|
114
114
|
|
115
115
|
# Mark the response "private", making it ineligible for serving other
|
@@ -131,26 +131,26 @@ module Rack::Cache
|
|
131
131
|
# Mark the response stale by setting the Age header to be equal to the
|
132
132
|
# maximum age of the response.
|
133
133
|
def expire!
|
134
|
-
headers['
|
134
|
+
headers['age'] = max_age.to_s if fresh?
|
135
135
|
end
|
136
136
|
|
137
137
|
# The date, as specified by the Date header. When no Date header is present
|
138
138
|
# or is unparseable, set the Date header to Time.now and return.
|
139
139
|
def date
|
140
|
-
if date = headers['
|
140
|
+
if date = headers['date']
|
141
141
|
Time.httpdate(date)
|
142
142
|
else
|
143
|
-
headers['
|
143
|
+
headers['date'] = now.httpdate unless headers.frozen?
|
144
144
|
now
|
145
145
|
end
|
146
146
|
rescue ArgumentError
|
147
|
-
headers['
|
147
|
+
headers['date'] = now.httpdate unless headers.frozen?
|
148
148
|
now
|
149
149
|
end
|
150
150
|
|
151
151
|
# The age of the response.
|
152
152
|
def age
|
153
|
-
(headers['
|
153
|
+
(headers['age'] || [(now - date).to_i, 0].max).to_i
|
154
154
|
end
|
155
155
|
|
156
156
|
# The number of seconds after the time specified in the response's Date
|
@@ -165,15 +165,15 @@ module Rack::Cache
|
|
165
165
|
(expires && (expires - date))
|
166
166
|
end
|
167
167
|
|
168
|
-
# The value of the
|
168
|
+
# The value of the expires header as a Time object.
|
169
169
|
def expires
|
170
|
-
headers['
|
170
|
+
headers['expires'] && Time.httpdate(headers['expires'])
|
171
171
|
rescue ArgumentError
|
172
172
|
nil
|
173
173
|
end
|
174
174
|
|
175
175
|
# The number of seconds after which the response should no longer
|
176
|
-
# be considered fresh. Sets the
|
176
|
+
# be considered fresh. Sets the cache-control max-age directive.
|
177
177
|
def max_age=(value)
|
178
178
|
self.cache_control = cache_control.merge('max-age' => value.to_s)
|
179
179
|
end
|
@@ -199,39 +199,39 @@ module Rack::Cache
|
|
199
199
|
end
|
200
200
|
|
201
201
|
# Set the response's time-to-live for shared caches to the specified number
|
202
|
-
# of seconds. This adjusts the
|
202
|
+
# of seconds. This adjusts the cache-control/s-maxage directive.
|
203
203
|
def ttl=(seconds)
|
204
204
|
self.shared_max_age = age + seconds
|
205
205
|
end
|
206
206
|
|
207
207
|
# Set the response's time-to-live for private/client caches. This adjusts
|
208
|
-
# the
|
208
|
+
# the cache-control/max-age directive.
|
209
209
|
def client_ttl=(seconds)
|
210
210
|
self.max_age = age + seconds
|
211
211
|
end
|
212
212
|
|
213
|
-
# The String value of the
|
213
|
+
# The String value of the last-modified header exactly as it appears
|
214
214
|
# in the response (i.e., no date parsing / conversion is performed).
|
215
215
|
def last_modified
|
216
|
-
headers['
|
216
|
+
headers['last-modified']
|
217
217
|
end
|
218
218
|
|
219
|
-
# The literal value of
|
219
|
+
# The literal value of etag HTTP header or nil if no etag is specified.
|
220
220
|
def etag
|
221
|
-
headers['
|
221
|
+
headers['etag']
|
222
222
|
end
|
223
223
|
|
224
224
|
# Headers that MUST NOT be included with 304 Not Modified responses.
|
225
225
|
#
|
226
226
|
# http://tools.ietf.org/html/rfc2616#section-10.3.5
|
227
227
|
NOT_MODIFIED_OMIT_HEADERS = %w[
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
228
|
+
allow
|
229
|
+
content-encoding
|
230
|
+
content-language
|
231
|
+
content-length
|
232
|
+
content-md5
|
233
|
+
content-type
|
234
|
+
last-modified
|
235
235
|
].to_set
|
236
236
|
|
237
237
|
# Modify the response so that it conforms to the rules defined for
|
@@ -247,20 +247,20 @@ module Rack::Cache
|
|
247
247
|
nil
|
248
248
|
end
|
249
249
|
|
250
|
-
# The literal value of the
|
250
|
+
# The literal value of the vary header, or nil when no header is present.
|
251
251
|
def vary
|
252
|
-
headers['
|
252
|
+
headers['vary']
|
253
253
|
end
|
254
254
|
|
255
|
-
# Does the response include a
|
255
|
+
# Does the response include a vary header?
|
256
256
|
def vary?
|
257
257
|
! vary.nil?
|
258
258
|
end
|
259
259
|
|
260
|
-
# An array of header names given in the
|
261
|
-
# array when no
|
260
|
+
# An array of header names given in the vary header or an empty
|
261
|
+
# array when no vary header is present.
|
262
262
|
def vary_header_names
|
263
|
-
return [] unless vary = headers['
|
263
|
+
return [] unless vary = headers['vary']
|
264
264
|
vary.split(/[\s,]+/)
|
265
265
|
end
|
266
266
|
|
data/lib/rack/cache.rb
CHANGED
@@ -3,8 +3,8 @@ require 'rack'
|
|
3
3
|
# = HTTP Caching For Rack
|
4
4
|
#
|
5
5
|
# Rack::Cache is suitable as a quick, drop-in component to enable HTTP caching
|
6
|
-
# for Rack-enabled applications that produce freshness (+
|
7
|
-
# and/or validation (+
|
6
|
+
# for Rack-enabled applications that produce freshness (+expires+, +cache-control+)
|
7
|
+
# and/or validation (+last-modified+, +etag+) information.
|
8
8
|
#
|
9
9
|
# * Standards-based (RFC 2616 compliance)
|
10
10
|
# * Freshness/expiration based caching and validation
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Tomayko
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -108,9 +108,37 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rdiscount
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: hanna-nouveau
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
111
139
|
description: Rack::Cache is suitable as a quick drop-in component to enable HTTP caching
|
112
|
-
for Rack-based applications that produce freshness (
|
113
|
-
validation (
|
140
|
+
for Rack-based applications that produce freshness (expires, cache-control) and/or
|
141
|
+
validation (last-modified, etag) information.
|
114
142
|
email: r@tomayko.com
|
115
143
|
executables: []
|
116
144
|
extensions: []
|
@@ -131,6 +159,7 @@ files:
|
|
131
159
|
- lib/rack/cache/context.rb
|
132
160
|
- lib/rack/cache/entity_store.rb
|
133
161
|
- lib/rack/cache/entitystore.rb
|
162
|
+
- lib/rack/cache/headers.rb
|
134
163
|
- lib/rack/cache/key.rb
|
135
164
|
- lib/rack/cache/meta_store.rb
|
136
165
|
- lib/rack/cache/metastore.rb
|
@@ -138,11 +167,12 @@ files:
|
|
138
167
|
- lib/rack/cache/request.rb
|
139
168
|
- lib/rack/cache/response.rb
|
140
169
|
- lib/rack/cache/storage.rb
|
141
|
-
|
170
|
+
- lib/rack/cache/version.rb
|
171
|
+
homepage: https://github.com/rack/rack-cache
|
142
172
|
licenses:
|
143
173
|
- MIT
|
144
174
|
metadata: {}
|
145
|
-
post_install_message:
|
175
|
+
post_install_message:
|
146
176
|
rdoc_options:
|
147
177
|
- "--line-numbers"
|
148
178
|
- "--inline-source"
|
@@ -163,8 +193,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
163
193
|
- !ruby/object:Gem::Version
|
164
194
|
version: '0'
|
165
195
|
requirements: []
|
166
|
-
rubygems_version: 3.
|
167
|
-
signing_key:
|
196
|
+
rubygems_version: 3.4.22
|
197
|
+
signing_key:
|
168
198
|
specification_version: 4
|
169
199
|
summary: HTTP Caching for Rack
|
170
200
|
test_files: []
|