rack-cache 1.5.1 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES +10 -0
- data/README.md +28 -9
- data/lib/rack/cache.rb +1 -1
- data/lib/rack/cache/app_engine.rb +48 -0
- data/lib/rack/cache/appengine.rb +2 -52
- data/lib/rack/cache/cache_control.rb +209 -0
- data/lib/rack/cache/cachecontrol.rb +2 -208
- data/lib/rack/cache/entity_store.rb +377 -0
- data/lib/rack/cache/entitystore.rb +2 -341
- data/lib/rack/cache/meta_store.rb +429 -0
- data/lib/rack/cache/metastore.rb +2 -418
- data/lib/rack/cache/request.rb +1 -1
- data/lib/rack/cache/response.rb +1 -1
- data/lib/rack/cache/storage.rb +4 -2
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad5318e23250e33645116d216dc29c802474689c
|
4
|
+
data.tar.gz: 80b52176a3aa9229f4fc4178e3123e973e10001e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58e6d9f8cd0cae110dc4fa923d0383973f085fa4e33f416318c7b48783a2d746278ec0e50b98a20dda55d669ef4016c10fe36693d49733f457fa630461cedea8
|
7
|
+
data.tar.gz: f30d08c7334ea19d00550d389e98940f62353fd93d15a65c3fd431c93a6c3b0ea23fc7e748bc51bc7646fa33f47c33061a55e03878368367ca743da762eea0a8
|
data/CHANGES
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 1.6.0
|
2
|
+
|
3
|
+
* Noop backend
|
4
|
+
* No longer read responses from cache when we already have them
|
5
|
+
* renamed files from entitystore -> entity_store (metastore/cachecontrol/appengine) and added warns for old ones
|
6
|
+
|
7
|
+
## 1.5.1
|
8
|
+
|
9
|
+
* fix key generation for query strings that include encoded equals
|
10
|
+
|
1
11
|
## 1.5.0
|
2
12
|
|
3
13
|
* only catch StandardError and not Exception
|
data/README.md
CHANGED
@@ -41,9 +41,9 @@ and use as follows:
|
|
41
41
|
require 'rack/cache'
|
42
42
|
|
43
43
|
use Rack::Cache,
|
44
|
-
:
|
45
|
-
:
|
46
|
-
:
|
44
|
+
metastore: 'file:/var/cache/rack/meta',
|
45
|
+
entitystore: 'file:/var/cache/rack/body',
|
46
|
+
verbose: true
|
47
47
|
|
48
48
|
run app
|
49
49
|
```
|
@@ -59,9 +59,9 @@ Add this to your `config/environment.rb`:
|
|
59
59
|
|
60
60
|
```Ruby
|
61
61
|
config.middleware.use Rack::Cache,
|
62
|
-
:
|
63
|
-
:
|
64
|
-
:
|
62
|
+
verbose: true,
|
63
|
+
metastore: 'file:/var/cache/rack/meta',
|
64
|
+
entitystore: 'file:/var/cache/rack/body'
|
65
65
|
```
|
66
66
|
|
67
67
|
You should now see `Rack::Cache` listed in the middleware pipeline:
|
@@ -83,9 +83,28 @@ require 'dalli'
|
|
83
83
|
require 'rack/cache'
|
84
84
|
|
85
85
|
use Rack::Cache,
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
86
|
+
verbose: true,
|
87
|
+
metastore: "memcached://localhost:11211/meta",
|
88
|
+
entitystore: "memcached://localhost:11211/body"
|
89
|
+
|
90
|
+
run app
|
91
|
+
```
|
92
|
+
|
93
|
+
Noop entity store
|
94
|
+
-----------------
|
95
|
+
|
96
|
+
Does not persist response bodies (no disk/memory used).<br/>
|
97
|
+
Responses from the cache will have an empty body.<br/>
|
98
|
+
Clients must ignore these empty cached response (check for X-Rack-Cache response header).<br/>
|
99
|
+
Atm cannot handle streamed responses, patch needed.
|
100
|
+
|
101
|
+
```Ruby
|
102
|
+
require 'rack/cache'
|
103
|
+
|
104
|
+
use Rack::Cache,
|
105
|
+
verbose: true,
|
106
|
+
metastore: <any backend>
|
107
|
+
entitystore: "noop:/"
|
89
108
|
|
90
109
|
run app
|
91
110
|
```
|
data/lib/rack/cache.rb
CHANGED
@@ -31,7 +31,7 @@ module Rack::Cache
|
|
31
31
|
autoload :Response, 'rack/cache/response'
|
32
32
|
autoload :Context, 'rack/cache/context'
|
33
33
|
autoload :Storage, 'rack/cache/storage'
|
34
|
-
autoload :CacheControl, 'rack/cache/
|
34
|
+
autoload :CacheControl, 'rack/cache/cache_control'
|
35
35
|
|
36
36
|
# Create a new Rack::Cache middleware component that fetches resources from
|
37
37
|
# the specified backend application. The +options+ Hash can be used to
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Rack::Cache::AppEngine
|
4
|
+
module MC
|
5
|
+
require 'java'
|
6
|
+
|
7
|
+
import com.google.appengine.api.memcache.Expiration;
|
8
|
+
import com.google.appengine.api.memcache.MemcacheService;
|
9
|
+
import com.google.appengine.api.memcache.MemcacheServiceFactory;
|
10
|
+
import com.google.appengine.api.memcache.Stats;
|
11
|
+
|
12
|
+
Service = MemcacheServiceFactory.getMemcacheService
|
13
|
+
end unless defined?(Rack::Cache::AppEngine::MC)
|
14
|
+
|
15
|
+
class MemCache
|
16
|
+
def initialize(options = {})
|
17
|
+
@cache = MC::Service
|
18
|
+
@cache.namespace = options[:namespace] if options[:namespace]
|
19
|
+
end
|
20
|
+
|
21
|
+
def contains?(key)
|
22
|
+
MC::Service.contains(key)
|
23
|
+
end
|
24
|
+
|
25
|
+
def get(key)
|
26
|
+
value = MC::Service.get(key)
|
27
|
+
Marshal.load(Base64.decode64(value)) if value
|
28
|
+
end
|
29
|
+
|
30
|
+
def put(key, value, ttl = nil)
|
31
|
+
expiration = ttl ? MC::Expiration.byDeltaSeconds(ttl) : nil
|
32
|
+
value = Base64.encode64(Marshal.dump(value)).gsub(/\n/, '')
|
33
|
+
MC::Service.put(key, value, expiration)
|
34
|
+
end
|
35
|
+
|
36
|
+
def namespace
|
37
|
+
MC::Service.getNamespace
|
38
|
+
end
|
39
|
+
|
40
|
+
def namespace=(value)
|
41
|
+
MC::Service.setNamespace(value.to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete(key)
|
45
|
+
MC::Service.delete(key)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/rack/cache/appengine.rb
CHANGED
@@ -1,52 +1,2 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
module Rack::Cache::AppEngine
|
4
|
-
|
5
|
-
module MC
|
6
|
-
require 'java'
|
7
|
-
|
8
|
-
import com.google.appengine.api.memcache.Expiration;
|
9
|
-
import com.google.appengine.api.memcache.MemcacheService;
|
10
|
-
import com.google.appengine.api.memcache.MemcacheServiceFactory;
|
11
|
-
import com.google.appengine.api.memcache.Stats;
|
12
|
-
|
13
|
-
Service = MemcacheServiceFactory.getMemcacheService
|
14
|
-
end unless defined?(Rack::Cache::AppEngine::MC)
|
15
|
-
|
16
|
-
class MemCache
|
17
|
-
|
18
|
-
def initialize(options = {})
|
19
|
-
@cache = MC::Service
|
20
|
-
@cache.namespace = options[:namespace] if options[:namespace]
|
21
|
-
end
|
22
|
-
|
23
|
-
def contains?(key)
|
24
|
-
MC::Service.contains(key)
|
25
|
-
end
|
26
|
-
|
27
|
-
def get(key)
|
28
|
-
value = MC::Service.get(key)
|
29
|
-
Marshal.load(Base64.decode64(value)) if value
|
30
|
-
end
|
31
|
-
|
32
|
-
def put(key, value, ttl = nil)
|
33
|
-
expiration = ttl ? MC::Expiration.byDeltaSeconds(ttl) : nil
|
34
|
-
value = Base64.encode64(Marshal.dump(value)).gsub(/\n/, '')
|
35
|
-
MC::Service.put(key, value, expiration)
|
36
|
-
end
|
37
|
-
|
38
|
-
def namespace
|
39
|
-
MC::Service.getNamespace
|
40
|
-
end
|
41
|
-
|
42
|
-
def namespace=(value)
|
43
|
-
MC::Service.setNamespace(value.to_s)
|
44
|
-
end
|
45
|
-
|
46
|
-
def delete(key)
|
47
|
-
MC::Service.delete(key)
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
1
|
+
warn "use require 'rack/cache/app_engine'"
|
2
|
+
require 'rack/cache/app_engine'
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module Rack
|
2
|
+
module Cache
|
3
|
+
|
4
|
+
# Parses a Cache-Control header and exposes the directives as a Hash.
|
5
|
+
# Directives that do not have values are set to +true+.
|
6
|
+
class CacheControl < Hash
|
7
|
+
def initialize(value=nil)
|
8
|
+
parse(value)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Indicates that the response MAY be cached by any cache, even if it
|
12
|
+
# would normally be non-cacheable or cacheable only within a non-
|
13
|
+
# shared cache.
|
14
|
+
#
|
15
|
+
# A response may be considered public without this directive if the
|
16
|
+
# private directive is not set and the request does not include an
|
17
|
+
# Authorization header.
|
18
|
+
def public?
|
19
|
+
self['public']
|
20
|
+
end
|
21
|
+
|
22
|
+
# Indicates that all or part of the response message is intended for
|
23
|
+
# a single user and MUST NOT be cached by a shared cache. This
|
24
|
+
# allows an origin server to state that the specified parts of the
|
25
|
+
# response are intended for only one user and are not a valid
|
26
|
+
# response for requests by other users. A private (non-shared) cache
|
27
|
+
# MAY cache the response.
|
28
|
+
#
|
29
|
+
# Note: This usage of the word private only controls where the
|
30
|
+
# response may be cached, and cannot ensure the privacy of the
|
31
|
+
# message content.
|
32
|
+
def private?
|
33
|
+
self['private']
|
34
|
+
end
|
35
|
+
|
36
|
+
# When set in a response, a cache MUST NOT use the response to satisfy a
|
37
|
+
# subsequent request without successful revalidation with the origin
|
38
|
+
# server. This allows an origin server to prevent caching even by caches
|
39
|
+
# that have been configured to return stale responses to client requests.
|
40
|
+
#
|
41
|
+
# Note that this does not necessary imply that the response may not be
|
42
|
+
# stored by the cache, only that the cache cannot serve it without first
|
43
|
+
# making a conditional GET request with the origin server.
|
44
|
+
#
|
45
|
+
# When set in a request, the server MUST NOT use a cached copy for its
|
46
|
+
# response. This has quite different semantics compared to the no-cache
|
47
|
+
# directive on responses. When the client specifies no-cache, it causes
|
48
|
+
# an end-to-end reload, forcing each cache to update their cached copies.
|
49
|
+
def no_cache?
|
50
|
+
self['no-cache']
|
51
|
+
end
|
52
|
+
|
53
|
+
# Indicates that the response MUST NOT be stored under any circumstances.
|
54
|
+
#
|
55
|
+
# The purpose of the no-store directive is to prevent the
|
56
|
+
# inadvertent release or retention of sensitive information (for
|
57
|
+
# example, on backup tapes). The no-store directive applies to the
|
58
|
+
# entire message, and MAY be sent either in a response or in a
|
59
|
+
# request. If sent in a request, a cache MUST NOT store any part of
|
60
|
+
# either this request or any response to it. If sent in a response,
|
61
|
+
# a cache MUST NOT store any part of either this response or the
|
62
|
+
# request that elicited it. This directive applies to both non-
|
63
|
+
# shared and shared caches. "MUST NOT store" in this context means
|
64
|
+
# that the cache MUST NOT intentionally store the information in
|
65
|
+
# non-volatile storage, and MUST make a best-effort attempt to
|
66
|
+
# remove the information from volatile storage as promptly as
|
67
|
+
# possible after forwarding it.
|
68
|
+
#
|
69
|
+
# The purpose of this directive is to meet the stated requirements
|
70
|
+
# of certain users and service authors who are concerned about
|
71
|
+
# accidental releases of information via unanticipated accesses to
|
72
|
+
# cache data structures. While the use of this directive might
|
73
|
+
# improve privacy in some cases, we caution that it is NOT in any
|
74
|
+
# way a reliable or sufficient mechanism for ensuring privacy. In
|
75
|
+
# particular, malicious or compromised caches might not recognize or
|
76
|
+
# obey this directive, and communications networks might be
|
77
|
+
# vulnerable to eavesdropping.
|
78
|
+
def no_store?
|
79
|
+
self['no-store']
|
80
|
+
end
|
81
|
+
|
82
|
+
# The expiration time of an entity MAY be specified by the origin
|
83
|
+
# server using the Expires header (see section 14.21). Alternatively,
|
84
|
+
# it MAY be specified using the max-age directive in a response. When
|
85
|
+
# the max-age cache-control directive is present in a cached response,
|
86
|
+
# the response is stale if its current age is greater than the age
|
87
|
+
# value given (in seconds) at the time of a new request for that
|
88
|
+
# resource. The max-age directive on a response implies that the
|
89
|
+
# response is cacheable (i.e., "public") unless some other, more
|
90
|
+
# restrictive cache directive is also present.
|
91
|
+
#
|
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
|
+
# server to provide, for a given response, a longer expiration time to
|
96
|
+
# an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
|
97
|
+
# useful if certain HTTP/1.0 caches improperly calculate ages or
|
98
|
+
# expiration times, perhaps due to desynchronized clocks.
|
99
|
+
#
|
100
|
+
# Many HTTP/1.0 cache implementations will treat an Expires value that
|
101
|
+
# is less than or equal to the response Date value as being equivalent
|
102
|
+
# to the Cache-Control response directive "no-cache". If an HTTP/1.1
|
103
|
+
# cache receives such a response, and the response does not include a
|
104
|
+
# Cache-Control header field, it SHOULD consider the response to be
|
105
|
+
# non-cacheable in order to retain compatibility with HTTP/1.0 servers.
|
106
|
+
#
|
107
|
+
# When the max-age directive is included in the request, it indicates
|
108
|
+
# that the client is willing to accept a response whose age is no
|
109
|
+
# greater than the specified time in seconds.
|
110
|
+
def max_age
|
111
|
+
self['max-age'].to_i if key?('max-age')
|
112
|
+
end
|
113
|
+
|
114
|
+
# If a response includes an s-maxage directive, then for a shared
|
115
|
+
# cache (but not for a private cache), the maximum age specified by
|
116
|
+
# this directive overrides the maximum age specified by either the
|
117
|
+
# max-age directive or the Expires header. The s-maxage directive
|
118
|
+
# also implies the semantics of the proxy-revalidate directive. i.e.,
|
119
|
+
# that the shared cache must not use the entry after it becomes stale
|
120
|
+
# to respond to a subsequent request without first revalidating it with
|
121
|
+
# the origin server. The s-maxage directive is always ignored by a
|
122
|
+
# private cache.
|
123
|
+
def shared_max_age
|
124
|
+
self['s-maxage'].to_i if key?('s-maxage')
|
125
|
+
end
|
126
|
+
alias_method :s_maxage, :shared_max_age
|
127
|
+
|
128
|
+
# If a response includes a r-maxage directive, then for a reverse cache
|
129
|
+
# (but not for a private or proxy cache), the maximum age specified by
|
130
|
+
# this directive overrides the maximum age specified by either the max-age
|
131
|
+
# directive, the s-maxage directive, or the Expires header. The r-maxage
|
132
|
+
# directive also implies the semantics of the proxy-revalidate directive.
|
133
|
+
# i.e., that the reverse cache must not use the entry after it becomes
|
134
|
+
# stale to respond to a subsequent request without first revalidating it
|
135
|
+
# with the origin server. The r-maxage directive is always ignored by
|
136
|
+
# private and proxy caches.
|
137
|
+
def reverse_max_age
|
138
|
+
self['r-maxage'].to_i if key?('r-maxage')
|
139
|
+
end
|
140
|
+
alias_method :r_maxage, :reverse_max_age
|
141
|
+
|
142
|
+
# Because a cache MAY be configured to ignore a server's specified
|
143
|
+
# expiration time, and because a client request MAY include a max-
|
144
|
+
# stale directive (which has a similar effect), the protocol also
|
145
|
+
# includes a mechanism for the origin server to require revalidation
|
146
|
+
# of a cache entry on any subsequent use. When the must-revalidate
|
147
|
+
# directive is present in a response received by a cache, that cache
|
148
|
+
# MUST NOT use the entry after it becomes stale to respond to a
|
149
|
+
# subsequent request without first revalidating it with the origin
|
150
|
+
# server. (I.e., the cache MUST do an end-to-end revalidation every
|
151
|
+
# time, if, based solely on the origin server's Expires or max-age
|
152
|
+
# value, the cached response is stale.)
|
153
|
+
#
|
154
|
+
# The must-revalidate directive is necessary to support reliable
|
155
|
+
# operation for certain protocol features. In all circumstances an
|
156
|
+
# HTTP/1.1 cache MUST obey the must-revalidate directive; in
|
157
|
+
# particular, if the cache cannot reach the origin server for any
|
158
|
+
# reason, it MUST generate a 504 (Gateway Timeout) response.
|
159
|
+
#
|
160
|
+
# Servers SHOULD send the must-revalidate directive if and only if
|
161
|
+
# failure to revalidate a request on the entity could result in
|
162
|
+
# incorrect operation, such as a silently unexecuted financial
|
163
|
+
# transaction. Recipients MUST NOT take any automated action that
|
164
|
+
# violates this directive, and MUST NOT automatically provide an
|
165
|
+
# unvalidated copy of the entity if revalidation fails.
|
166
|
+
def must_revalidate?
|
167
|
+
self['must-revalidate']
|
168
|
+
end
|
169
|
+
|
170
|
+
# The proxy-revalidate directive has the same meaning as the must-
|
171
|
+
# revalidate directive, except that it does not apply to non-shared
|
172
|
+
# user agent caches. It can be used on a response to an
|
173
|
+
# authenticated request to permit the user's cache to store and
|
174
|
+
# later return the response without needing to revalidate it (since
|
175
|
+
# it has already been authenticated once by that user), while still
|
176
|
+
# requiring proxies that service many users to revalidate each time
|
177
|
+
# (in order to make sure that each user has been authenticated).
|
178
|
+
# Note that such authenticated responses also need the public cache
|
179
|
+
# control directive in order to allow them to be cached at all.
|
180
|
+
def proxy_revalidate?
|
181
|
+
self['proxy-revalidate']
|
182
|
+
end
|
183
|
+
|
184
|
+
def to_s
|
185
|
+
bools, vals = [], []
|
186
|
+
each do |key,value|
|
187
|
+
if value == true
|
188
|
+
bools << key
|
189
|
+
elsif value
|
190
|
+
vals << "#{key}=#{value}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
(bools.sort + vals.sort).join(', ')
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def parse(value)
|
199
|
+
return if value.nil? || value.empty?
|
200
|
+
value.delete(' ').split(',').each do |part|
|
201
|
+
next if part.empty?
|
202
|
+
name, value = part.split('=', 2)
|
203
|
+
self[name.downcase] = (value || true) unless name.empty?
|
204
|
+
end
|
205
|
+
self
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -1,208 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# Parses a Cache-Control header and exposes the directives as a Hash.
|
5
|
-
# Directives that do not have values are set to +true+.
|
6
|
-
class CacheControl < Hash
|
7
|
-
def initialize(value=nil)
|
8
|
-
parse(value)
|
9
|
-
end
|
10
|
-
|
11
|
-
# Indicates that the response MAY be cached by any cache, even if it
|
12
|
-
# would normally be non-cacheable or cacheable only within a non-
|
13
|
-
# shared cache.
|
14
|
-
#
|
15
|
-
# A response may be considered public without this directive if the
|
16
|
-
# private directive is not set and the request does not include an
|
17
|
-
# Authorization header.
|
18
|
-
def public?
|
19
|
-
self['public']
|
20
|
-
end
|
21
|
-
|
22
|
-
# Indicates that all or part of the response message is intended for
|
23
|
-
# a single user and MUST NOT be cached by a shared cache. This
|
24
|
-
# allows an origin server to state that the specified parts of the
|
25
|
-
# response are intended for only one user and are not a valid
|
26
|
-
# response for requests by other users. A private (non-shared) cache
|
27
|
-
# MAY cache the response.
|
28
|
-
#
|
29
|
-
# Note: This usage of the word private only controls where the
|
30
|
-
# response may be cached, and cannot ensure the privacy of the
|
31
|
-
# message content.
|
32
|
-
def private?
|
33
|
-
self['private']
|
34
|
-
end
|
35
|
-
|
36
|
-
# When set in a response, a cache MUST NOT use the response to satisfy a
|
37
|
-
# subsequent request without successful revalidation with the origin
|
38
|
-
# server. This allows an origin server to prevent caching even by caches
|
39
|
-
# that have been configured to return stale responses to client requests.
|
40
|
-
#
|
41
|
-
# Note that this does not necessary imply that the response may not be
|
42
|
-
# stored by the cache, only that the cache cannot serve it without first
|
43
|
-
# making a conditional GET request with the origin server.
|
44
|
-
#
|
45
|
-
# When set in a request, the server MUST NOT use a cached copy for its
|
46
|
-
# response. This has quite different semantics compared to the no-cache
|
47
|
-
# directive on responses. When the client specifies no-cache, it causes
|
48
|
-
# an end-to-end reload, forcing each cache to update their cached copies.
|
49
|
-
def no_cache?
|
50
|
-
self['no-cache']
|
51
|
-
end
|
52
|
-
|
53
|
-
# Indicates that the response MUST NOT be stored under any circumstances.
|
54
|
-
#
|
55
|
-
# The purpose of the no-store directive is to prevent the
|
56
|
-
# inadvertent release or retention of sensitive information (for
|
57
|
-
# example, on backup tapes). The no-store directive applies to the
|
58
|
-
# entire message, and MAY be sent either in a response or in a
|
59
|
-
# request. If sent in a request, a cache MUST NOT store any part of
|
60
|
-
# either this request or any response to it. If sent in a response,
|
61
|
-
# a cache MUST NOT store any part of either this response or the
|
62
|
-
# request that elicited it. This directive applies to both non-
|
63
|
-
# shared and shared caches. "MUST NOT store" in this context means
|
64
|
-
# that the cache MUST NOT intentionally store the information in
|
65
|
-
# non-volatile storage, and MUST make a best-effort attempt to
|
66
|
-
# remove the information from volatile storage as promptly as
|
67
|
-
# possible after forwarding it.
|
68
|
-
#
|
69
|
-
# The purpose of this directive is to meet the stated requirements
|
70
|
-
# of certain users and service authors who are concerned about
|
71
|
-
# accidental releases of information via unanticipated accesses to
|
72
|
-
# cache data structures. While the use of this directive might
|
73
|
-
# improve privacy in some cases, we caution that it is NOT in any
|
74
|
-
# way a reliable or sufficient mechanism for ensuring privacy. In
|
75
|
-
# particular, malicious or compromised caches might not recognize or
|
76
|
-
# obey this directive, and communications networks might be
|
77
|
-
# vulnerable to eavesdropping.
|
78
|
-
def no_store?
|
79
|
-
self['no-store']
|
80
|
-
end
|
81
|
-
|
82
|
-
# The expiration time of an entity MAY be specified by the origin
|
83
|
-
# server using the Expires header (see section 14.21). Alternatively,
|
84
|
-
# it MAY be specified using the max-age directive in a response. When
|
85
|
-
# the max-age cache-control directive is present in a cached response,
|
86
|
-
# the response is stale if its current age is greater than the age
|
87
|
-
# value given (in seconds) at the time of a new request for that
|
88
|
-
# resource. The max-age directive on a response implies that the
|
89
|
-
# response is cacheable (i.e., "public") unless some other, more
|
90
|
-
# restrictive cache directive is also present.
|
91
|
-
#
|
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
|
-
# server to provide, for a given response, a longer expiration time to
|
96
|
-
# an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
|
97
|
-
# useful if certain HTTP/1.0 caches improperly calculate ages or
|
98
|
-
# expiration times, perhaps due to desynchronized clocks.
|
99
|
-
#
|
100
|
-
# Many HTTP/1.0 cache implementations will treat an Expires value that
|
101
|
-
# is less than or equal to the response Date value as being equivalent
|
102
|
-
# to the Cache-Control response directive "no-cache". If an HTTP/1.1
|
103
|
-
# cache receives such a response, and the response does not include a
|
104
|
-
# Cache-Control header field, it SHOULD consider the response to be
|
105
|
-
# non-cacheable in order to retain compatibility with HTTP/1.0 servers.
|
106
|
-
#
|
107
|
-
# When the max-age directive is included in the request, it indicates
|
108
|
-
# that the client is willing to accept a response whose age is no
|
109
|
-
# greater than the specified time in seconds.
|
110
|
-
def max_age
|
111
|
-
self['max-age'].to_i if key?('max-age')
|
112
|
-
end
|
113
|
-
|
114
|
-
# If a response includes an s-maxage directive, then for a shared
|
115
|
-
# cache (but not for a private cache), the maximum age specified by
|
116
|
-
# this directive overrides the maximum age specified by either the
|
117
|
-
# max-age directive or the Expires header. The s-maxage directive
|
118
|
-
# also implies the semantics of the proxy-revalidate directive. i.e.,
|
119
|
-
# that the shared cache must not use the entry after it becomes stale
|
120
|
-
# to respond to a subsequent request without first revalidating it with
|
121
|
-
# the origin server. The s-maxage directive is always ignored by a
|
122
|
-
# private cache.
|
123
|
-
def shared_max_age
|
124
|
-
self['s-maxage'].to_i if key?('s-maxage')
|
125
|
-
end
|
126
|
-
alias_method :s_maxage, :shared_max_age
|
127
|
-
|
128
|
-
# If a response includes a r-maxage directive, then for a reverse cache
|
129
|
-
# (but not for a private or proxy cache), the maximum age specified by
|
130
|
-
# this directive overrides the maximum age specified by either the max-age
|
131
|
-
# directive, the s-maxage directive, or the Expires header. The r-maxage
|
132
|
-
# directive also implies the semantics of the proxy-revalidate directive.
|
133
|
-
# i.e., that the reverse cache must not use the entry after it becomes
|
134
|
-
# stale to respond to a subsequent request without first revalidating it
|
135
|
-
# with the origin server. The r-maxage directive is always ignored by
|
136
|
-
# private and proxy caches.
|
137
|
-
def reverse_max_age
|
138
|
-
self['r-maxage'].to_i if key?('r-maxage')
|
139
|
-
end
|
140
|
-
alias_method :r_maxage, :reverse_max_age
|
141
|
-
|
142
|
-
# Because a cache MAY be configured to ignore a server's specified
|
143
|
-
# expiration time, and because a client request MAY include a max-
|
144
|
-
# stale directive (which has a similar effect), the protocol also
|
145
|
-
# includes a mechanism for the origin server to require revalidation
|
146
|
-
# of a cache entry on any subsequent use. When the must-revalidate
|
147
|
-
# directive is present in a response received by a cache, that cache
|
148
|
-
# MUST NOT use the entry after it becomes stale to respond to a
|
149
|
-
# subsequent request without first revalidating it with the origin
|
150
|
-
# server. (I.e., the cache MUST do an end-to-end revalidation every
|
151
|
-
# time, if, based solely on the origin server's Expires or max-age
|
152
|
-
# value, the cached response is stale.)
|
153
|
-
#
|
154
|
-
# The must-revalidate directive is necessary to support reliable
|
155
|
-
# operation for certain protocol features. In all circumstances an
|
156
|
-
# HTTP/1.1 cache MUST obey the must-revalidate directive; in
|
157
|
-
# particular, if the cache cannot reach the origin server for any
|
158
|
-
# reason, it MUST generate a 504 (Gateway Timeout) response.
|
159
|
-
#
|
160
|
-
# Servers SHOULD send the must-revalidate directive if and only if
|
161
|
-
# failure to revalidate a request on the entity could result in
|
162
|
-
# incorrect operation, such as a silently unexecuted financial
|
163
|
-
# transaction. Recipients MUST NOT take any automated action that
|
164
|
-
# violates this directive, and MUST NOT automatically provide an
|
165
|
-
# unvalidated copy of the entity if revalidation fails.
|
166
|
-
def must_revalidate?
|
167
|
-
self['must-revalidate']
|
168
|
-
end
|
169
|
-
|
170
|
-
# The proxy-revalidate directive has the same meaning as the must-
|
171
|
-
# revalidate directive, except that it does not apply to non-shared
|
172
|
-
# user agent caches. It can be used on a response to an
|
173
|
-
# authenticated request to permit the user's cache to store and
|
174
|
-
# later return the response without needing to revalidate it (since
|
175
|
-
# it has already been authenticated once by that user), while still
|
176
|
-
# requiring proxies that service many users to revalidate each time
|
177
|
-
# (in order to make sure that each user has been authenticated).
|
178
|
-
# Note that such authenticated responses also need the public cache
|
179
|
-
# control directive in order to allow them to be cached at all.
|
180
|
-
def proxy_revalidate?
|
181
|
-
self['proxy-revalidate']
|
182
|
-
end
|
183
|
-
|
184
|
-
def to_s
|
185
|
-
bools, vals = [], []
|
186
|
-
each do |key,value|
|
187
|
-
if value == true
|
188
|
-
bools << key
|
189
|
-
elsif value
|
190
|
-
vals << "#{key}=#{value}"
|
191
|
-
end
|
192
|
-
end
|
193
|
-
(bools.sort + vals.sort).join(', ')
|
194
|
-
end
|
195
|
-
|
196
|
-
private
|
197
|
-
def parse(value)
|
198
|
-
return if value.nil? || value.empty?
|
199
|
-
value.delete(' ').split(',').each do |part|
|
200
|
-
next if part.empty?
|
201
|
-
name, value = part.split('=', 2)
|
202
|
-
self[name.downcase] = (value || true) unless name.empty?
|
203
|
-
end
|
204
|
-
self
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
1
|
+
warn "use require 'rack/cache/cache_control'"
|
2
|
+
require 'rack/cache/cache_control'
|