rtomayko-rack-cache 0.3.0 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +41 -0
- data/README +0 -1
- data/TODO +14 -10
- data/doc/configuration.markdown +7 -153
- data/doc/index.markdown +1 -3
- data/example/sinatra/app.rb +25 -0
- data/example/sinatra/views/index.erb +44 -0
- data/lib/rack/cache.rb +5 -11
- data/lib/rack/cache/cachecontrol.rb +193 -0
- data/lib/rack/cache/context.rb +188 -51
- data/lib/rack/cache/entitystore.rb +10 -4
- data/lib/rack/cache/key.rb +52 -0
- data/lib/rack/cache/metastore.rb +52 -16
- data/lib/rack/cache/options.rb +29 -13
- data/lib/rack/cache/request.rb +11 -15
- data/lib/rack/cache/response.rb +221 -30
- data/lib/rack/cache/storage.rb +1 -2
- data/rack-cache.gemspec +9 -14
- data/test/cache_test.rb +4 -1
- data/test/cachecontrol_test.rb +139 -0
- data/test/context_test.rb +198 -169
- data/test/entitystore_test.rb +12 -11
- data/test/key_test.rb +50 -0
- data/test/metastore_test.rb +57 -14
- data/test/options_test.rb +11 -0
- data/test/request_test.rb +19 -0
- data/test/response_test.rb +164 -23
- data/test/spec_setup.rb +6 -0
- metadata +13 -19
- data/lib/rack/cache/config.rb +0 -65
- data/lib/rack/cache/config/busters.rb +0 -16
- data/lib/rack/cache/config/default.rb +0 -133
- data/lib/rack/cache/config/no-cache.rb +0 -13
- data/lib/rack/cache/core.rb +0 -299
- data/lib/rack/cache/headers.rb +0 -325
- data/lib/rack/utils/environment_headers.rb +0 -78
- data/test/config_test.rb +0 -66
- data/test/core_test.rb +0 -84
- data/test/environment_headers_test.rb +0 -69
- data/test/headers_test.rb +0 -298
- data/test/logging_test.rb +0 -45
data/CHANGES
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
## 0.4.0 / Unreleased
|
2
|
+
|
3
|
+
* Ruby 1.9.1 / Rack 1.0 compatible.
|
4
|
+
|
5
|
+
* Invalidate cache entries that match the request URL on non-GET/HEAD
|
6
|
+
requests. i.e., POST, PUT, DELETE cause matching cache entries to
|
7
|
+
be invalidated. The cache entry is validated with the backend using
|
8
|
+
a conditional GET the next time it's requested.
|
9
|
+
|
10
|
+
* Implement "Cache-Control: max-age=N" request directive by forcing
|
11
|
+
validation when the max-age provided exceeds the age of the cache
|
12
|
+
entry.
|
13
|
+
|
14
|
+
* Properly implement "Cache-Control: no-cache" request directive by
|
15
|
+
performing a full reload. RFC 2616 states that when "no-cache" is
|
16
|
+
present in the request, the cache MUST NOT serve a stored response even
|
17
|
+
after successful validation. This is slightly different from the
|
18
|
+
"no-cache" directive in responses, which indicates that the cache must
|
19
|
+
first validate its entry with the origin. Previously, we implemented
|
20
|
+
"no-cache" on requests by passing so no new cache entry would be stored
|
21
|
+
based on the response. Now we treat it as a forced miss and enter the
|
22
|
+
response into the cache if it's cacheable.
|
23
|
+
|
24
|
+
* Assume identical semantics for the "Pragma: no-cache" request header
|
25
|
+
as the "Cache-Control: no-cache" directive described above.
|
26
|
+
|
27
|
+
* Less crazy logging. When the verbose option is set, a single log entry
|
28
|
+
is written with a comma separated list of trace events. For example, if
|
29
|
+
the cache was stale but validated, the following log entry would be
|
30
|
+
written: "cache: stale, valid, store". When the verbose option is false,
|
31
|
+
no logging occurs.
|
32
|
+
|
33
|
+
* Added "X-Rack-Cache" response header with the same comma separated trace
|
34
|
+
value as described above. This gives some visibility into how the cache
|
35
|
+
processed the request.
|
36
|
+
|
37
|
+
* Add support for canonicalized cache keys, as well as custom cache key
|
38
|
+
generators, which are specified in the options as :cache_key as either
|
39
|
+
any object that has a call() or as a block. Cache key generators get
|
40
|
+
passed a request object and return a cache key string.
|
41
|
+
|
1
42
|
## 0.3.0 / December 2008
|
2
43
|
|
3
44
|
* Add support for public and private cache control directives. Responses
|
data/README
CHANGED
@@ -12,7 +12,6 @@ validation (Last-Modified, ETag) information:
|
|
12
12
|
* Cache-Control: public, private, max-age, s-maxage, must-revalidate,
|
13
13
|
and proxy-revalidate.
|
14
14
|
* Portable: 100% Ruby / works with any Rack-enabled framework
|
15
|
-
* Configuration language for advanced caching policies
|
16
15
|
* Disk, memcached, and heap memory storage backends
|
17
16
|
|
18
17
|
For more information about Rack::Cache features and usage, see:
|
data/TODO
CHANGED
@@ -1,21 +1,25 @@
|
|
1
1
|
## 0.4
|
2
2
|
|
3
|
-
-
|
3
|
+
- Move breakers.rb configuration file into rack-contrib as a middleware
|
4
|
+
component.
|
5
|
+
- Add docs on using Rack::Cache with Rails 2.3 or link to one of the
|
6
|
+
existing tutorials on this.
|
4
7
|
- Sample apps: Rack, Rails, Sinatra, Merb, etc.
|
5
|
-
- busters.rb and no-cache.rb doc and tests
|
6
|
-
- Canonicalized URL for cache key:
|
7
|
-
- sorts params by key, then value
|
8
|
-
- urlencodes /[^ A-Za-z0-9_.-]/ host, path, and param key/value
|
9
|
-
- Custom cache keys
|
10
|
-
- Cache invalidation on PUT, POST, DELETE.
|
11
|
-
- Invalidate at the request URI; or, anything that's "near" the request URI.
|
12
|
-
- Invalidate at the URI of the Location or Content-Location response header.
|
13
8
|
|
14
9
|
## Backlog
|
15
10
|
|
11
|
+
- Use Bacon instead of test/spec
|
12
|
+
- Work with both memcache and memcached gems (memcached hasn't built on MacOS
|
13
|
+
for some time now).
|
14
|
+
- Fast path pass processing. We do a lot more than necessary just to determine
|
15
|
+
that the response should be passed through untouched.
|
16
|
+
- Don't purge/remove cache entries when invalidating. The entries should be
|
17
|
+
marked as stale and be forced revalidated on the next request instead of
|
18
|
+
being removed entirely.
|
16
19
|
- Add missing Expires header if we have a max-age.
|
17
|
-
- Purge/invalidate specific cache entries
|
18
20
|
- Purge/invalidate everything
|
21
|
+
- Invalidate at the URI of the Location or Content-Location response header
|
22
|
+
on POST, PUT, or DELETE that results in a redirect.
|
19
23
|
- Maximum size of cached entity
|
20
24
|
- Last-Modified factor: requests that have a Last-Modified header but no Expires
|
21
25
|
header have a TTL assigned based on the last modified age of the response:
|
data/doc/configuration.markdown
CHANGED
@@ -1,51 +1,17 @@
|
|
1
|
-
Configuration
|
2
|
-
|
1
|
+
Configuration
|
2
|
+
=============
|
3
3
|
|
4
4
|
__Rack::Cache__ includes a configuration system that can be used to specify
|
5
5
|
fairly sophisticated cache policy on a global or per-request basis.
|
6
6
|
|
7
|
-
- [Synopsis](#synopsis)
|
8
|
-
- [Setting Cache Options](#setopt)
|
9
|
-
- [Cache Option Reference](#options)
|
10
|
-
- [Configuration Machinery - Events and Transitions](#machinery)
|
11
|
-
- [Importing Configuration](#import)
|
12
|
-
- [Default Configuration Machinery](#default)
|
13
|
-
- [Notes](#notes)
|
14
|
-
|
15
|
-
<a id='synopsis'></a>
|
16
|
-
|
17
|
-
Synopsis
|
18
|
-
--------
|
19
|
-
|
20
|
-
use Rack::Cache do
|
21
|
-
# set cache related options
|
22
|
-
set :verbose, true
|
23
|
-
set :metastore, 'memcached://localhost:11211'
|
24
|
-
set :entitystore, 'file:/var/cache/rack/body'
|
25
|
-
|
26
|
-
# override events / transitions
|
27
|
-
on :receive do
|
28
|
-
pass! if request.url =~ %r|/dontcache/|
|
29
|
-
error! 402 if request.referrer =~ /digg.com/
|
30
|
-
end
|
31
|
-
|
32
|
-
on :miss do
|
33
|
-
trace 'missed: %s', request.url
|
34
|
-
end
|
35
|
-
|
36
|
-
# bring in other configuration machinery
|
37
|
-
import 'rack/cache/config/breakers'
|
38
|
-
import 'mycacheconfig'
|
39
|
-
end
|
40
|
-
|
41
7
|
<a id='setopt'></a>
|
42
8
|
|
43
9
|
Setting Cache Options
|
44
10
|
---------------------
|
45
11
|
|
46
|
-
Cache options can be set when the __Rack::Cache__ object is created
|
47
|
-
|
48
|
-
|
12
|
+
Cache options can be set when the __Rack::Cache__ object is created,
|
13
|
+
or by setting a `rack-cache.<option>` variable in __Rack__'s
|
14
|
+
__Environment__.
|
49
15
|
|
50
16
|
When the __Rack::Cache__ object is instantiated:
|
51
17
|
|
@@ -54,14 +20,6 @@ When the __Rack::Cache__ object is instantiated:
|
|
54
20
|
:metastore => 'memcached://localhost:11211/',
|
55
21
|
:entitystore => 'file:/var/cache/rack'
|
56
22
|
|
57
|
-
Using the `set` method within __Rack::Cache__'s configuration context:
|
58
|
-
|
59
|
-
use Rack::Cache do
|
60
|
-
set :verbose, true
|
61
|
-
set :metastore, 'memcached://localhost:11211/'
|
62
|
-
set :entitystore, 'file:/var/cache/rack'
|
63
|
-
end
|
64
|
-
|
65
23
|
Using __Rack__'s __Environment__:
|
66
24
|
|
67
25
|
env.merge!(
|
@@ -123,110 +81,6 @@ If any of these headers are present in the request, the response is considered
|
|
123
81
|
private and will not be cached _unless_ the response is explicitly marked public
|
124
82
|
(e.g., `Cache-Control: public`).
|
125
83
|
|
126
|
-
|
127
|
-
|
128
|
-
Configuration Machinery - Events and Transitions
|
129
|
-
------------------------------------------------
|
130
|
-
|
131
|
-
The configuration machinery is built around a series of interceptable events and
|
132
|
-
transitions controlled by a simple configuration language. The following diagram
|
133
|
-
shows each state (interceptable event) along with their possible transitions:
|
134
|
-
|
135
|
-
<p class='center'>
|
136
|
-
<img src='events.png' alt='Events and Transitions Diagram' />
|
137
|
-
</p>
|
138
|
-
|
139
|
-
Custom logic can be layered onto the `receive`, `hit`, `miss`, `fetch`, `store`,
|
140
|
-
`deliver`, and `pass` events by passing a block to the `on` method:
|
141
|
-
|
142
|
-
on :fetch do
|
143
|
-
trace 'fetched %p from backend application', request.url
|
144
|
-
end
|
145
|
-
|
146
|
-
Here, the `trace` method writes a message to the `rack.errors` stream when a
|
147
|
-
response is fetched from the backend application. The `request` object is a
|
148
|
-
[__Rack::Cache::Request__](./api/classes/Rack/Cache/Request) that can be
|
149
|
-
inspected (and modified) to determine what action should be taken next.
|
150
|
-
|
151
|
-
Event blocks are capable of performing more interesting operations:
|
152
|
-
|
153
|
-
* Transition to a different event or override default caching logic.
|
154
|
-
* Modify the request, response, cache entry, or Rack environment options.
|
155
|
-
* Set the `metastore` or `entitystore` options to select a different storage
|
156
|
-
mechanism / location dynamically.
|
157
|
-
* Collect statistics or log request/response/cache information.
|
158
|
-
|
159
|
-
When an event is triggered, the blocks associated with the event are executed in
|
160
|
-
reverse/FILO order (i.e., the block declared last runs first) until a
|
161
|
-
_transitioning statement_ is encountered. Transitioning statements are suffixed
|
162
|
-
with a bang character (e.g, `pass!`, `store!`, `error!`) and cause the current
|
163
|
-
event to halt and the machine to transition to the subsequent event; control is
|
164
|
-
not returned to the original event. The [default configuration](#default)
|
165
|
-
includes documentation on available transitions for each event.
|
166
|
-
|
167
|
-
The `next` statement can be used to exit an event block without transitioning
|
168
|
-
to another event. Subsequent event blocks are executed until a transitioning
|
169
|
-
statement is encountered:
|
170
|
-
|
171
|
-
on :fetch do
|
172
|
-
next if response.freshness_information?
|
173
|
-
|
174
|
-
if request.url =~ /\/feed$/
|
175
|
-
trace 'feed will expire in fifteen minutes'
|
176
|
-
response.ttl = 15 * 60
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
<a id='import'></a>
|
181
|
-
|
182
|
-
Importing Configuration
|
183
|
-
-----------------------
|
184
|
-
|
185
|
-
Since caching logic can be layered, it's possible to separate various bits of
|
186
|
-
cache policy into files for organization and reuse.
|
187
|
-
|
188
|
-
use Rack::Cache do
|
189
|
-
import 'rack/cache/config/busters'
|
190
|
-
import 'mycacheconfig'
|
191
|
-
|
192
|
-
# more stuff here
|
193
|
-
end
|
194
|
-
|
195
|
-
The `busters` and `mycacheconfig` configuration files are normal Ruby source
|
196
|
-
files (i.e., they have a `.rb` extension) situated on the `$LOAD_PATH` - the
|
197
|
-
`import` statement works like Ruby's `require` statement but the contents of the
|
198
|
-
files are evaluated in the context of the configuration machinery, as if
|
199
|
-
specified directly in the configuration block.
|
200
|
-
|
201
|
-
The `rack/cache/config/busters.rb` file makes a good example. It hooks into the
|
202
|
-
`fetch` event and adds an impractically long expiration lifetime to any response
|
203
|
-
that includes a cache busting query string:
|
204
|
-
|
205
|
-
<%= File.read('lib/rack/cache/config/busters.rb').gsub(/^/, ' ') %>
|
206
|
-
|
207
|
-
|
208
|
-
<a id='default'></a>
|
209
|
-
|
210
|
-
Default Configuration Machinery
|
211
|
-
-------------------------------
|
212
|
-
|
213
|
-
The `rack/cache/config/default.rb` file is imported when the __Rack::Cache__
|
214
|
-
object is instantiated and before any custom configuration code is executed.
|
215
|
-
It's useful to understand this configuration because it drives the default
|
216
|
-
transitioning logic.
|
217
|
-
|
218
|
-
<%= File.read('lib/rack/cache/config/default.rb').gsub(/^/, ' ') %>
|
219
|
-
|
220
|
-
<a id='notes'></a>
|
221
|
-
|
222
|
-
Notes
|
223
|
-
-----
|
224
|
-
|
225
|
-
The configuration language was inspired by [Varnish][var]'s
|
226
|
-
[VCL configuration language][vcl].
|
227
|
-
|
228
|
-
[var]: http://varnish.projects.linpro.no/
|
229
|
-
"Varnish HTTP accelerator"
|
84
|
+
### `cache_key`
|
230
85
|
|
231
|
-
|
232
|
-
"VCL(7) -- Varnish Configuration Language Manual Page"
|
86
|
+
TODO: Document custom cache keys
|
data/doc/index.markdown
CHANGED
@@ -7,7 +7,6 @@ for [Rack][]-based applications that produce freshness (`Expires`,
|
|
7
7
|
* Validation
|
8
8
|
* Vary support
|
9
9
|
* Portable: 100% Ruby / works with any [Rack][]-enabled framework.
|
10
|
-
* [Configuration language][config] for advanced caching policies.
|
11
10
|
* Disk, memcached, and heap memory [storage backends][storage].
|
12
11
|
|
13
12
|
Status
|
@@ -52,8 +51,7 @@ caching.
|
|
52
51
|
More
|
53
52
|
----
|
54
53
|
|
55
|
-
* [Configuration
|
56
|
-
policy using the simple event-based configuration system.
|
54
|
+
* [Configuration and Options][config] - how to set cache options.
|
57
55
|
|
58
56
|
* [Cache Storage Documentation][storage] - detailed information on the various
|
59
57
|
storage implementations available in __Rack::Cache__ and how to choose the one
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'rack/cache'
|
3
|
+
|
4
|
+
use Rack::Cache do
|
5
|
+
set :verbose, true
|
6
|
+
set :metastore, 'heap:/'
|
7
|
+
set :entitystore, 'heap:/'
|
8
|
+
|
9
|
+
on :receive do
|
10
|
+
pass! if request.url =~ /favicon/
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
last_modified $updated_at ||= Time.now
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/' do
|
19
|
+
erb :index
|
20
|
+
end
|
21
|
+
|
22
|
+
put '/' do
|
23
|
+
$updated_at = nil
|
24
|
+
redirect '/'
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Sample Rack::Cache Sinatra app</title>
|
4
|
+
<style type="text/css" media="screen">
|
5
|
+
body {
|
6
|
+
font-family: Georgia;
|
7
|
+
font-size: 24px;
|
8
|
+
text-align: center;
|
9
|
+
}
|
10
|
+
|
11
|
+
#headers {
|
12
|
+
font-size: 16px;
|
13
|
+
}
|
14
|
+
|
15
|
+
input {
|
16
|
+
font-size: 24px;
|
17
|
+
cursor: pointer;
|
18
|
+
}
|
19
|
+
</style>
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
<h1>Last updated at: <%= $updated_at.strftime('%l:%m:%S%P') %></h1>
|
23
|
+
|
24
|
+
<p>
|
25
|
+
<form action="/" method="post">
|
26
|
+
<input type="hidden" name="_method" value="PUT">
|
27
|
+
<input type="submit" value="Expire the cache.">
|
28
|
+
</form>
|
29
|
+
</p>
|
30
|
+
|
31
|
+
<div id="headers">
|
32
|
+
<h3>Headers:</h3>
|
33
|
+
|
34
|
+
<% response.headers.each do |key, value| %>
|
35
|
+
<p><%= key %>: <%= value %></p>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<h3>Params:</h3>
|
39
|
+
<% params.each do |key, value| %>
|
40
|
+
<p><%= key %>: <%= value || '(blank)' %></p>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</body>
|
44
|
+
</html>
|
data/lib/rack/cache.rb
CHANGED
@@ -1,10 +1,5 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'time'
|
3
1
|
require 'rack'
|
4
2
|
|
5
|
-
module Rack #:nodoc:
|
6
|
-
end
|
7
|
-
|
8
3
|
# = HTTP Caching For Rack
|
9
4
|
#
|
10
5
|
# Rack::Cache is suitable as a quick, drop-in component to enable HTTP caching
|
@@ -15,7 +10,6 @@ end
|
|
15
10
|
# * Freshness/expiration based caching and validation
|
16
11
|
# * Supports HTTP Vary
|
17
12
|
# * Portable: 100% Ruby / works with any Rack-enabled framework
|
18
|
-
# * VCL-like configuration language for advanced caching policies
|
19
13
|
# * Disk, memcached, and heap memory storage backends
|
20
14
|
#
|
21
15
|
# === Usage
|
@@ -32,12 +26,12 @@ end
|
|
32
26
|
# set :entitystore, 'file:/var/cache/rack'
|
33
27
|
# end
|
34
28
|
# run app
|
35
|
-
#
|
36
29
|
module Rack::Cache
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
autoload :Request, 'rack/cache/request'
|
31
|
+
autoload :Response, 'rack/cache/response'
|
32
|
+
autoload :Context, 'rack/cache/context'
|
33
|
+
autoload :Storage, 'rack/cache/storage'
|
34
|
+
autoload :CacheControl, 'rack/cache/cachecontrol'
|
41
35
|
|
42
36
|
# Create a new Rack::Cache middleware component that fetches resources from
|
43
37
|
# the specified backend application. The +options+ Hash can be used to
|
@@ -0,0 +1,193 @@
|
|
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
|
+
# Because a cache MAY be configured to ignore a server's specified
|
129
|
+
# expiration time, and because a client request MAY include a max-
|
130
|
+
# stale directive (which has a similar effect), the protocol also
|
131
|
+
# includes a mechanism for the origin server to require revalidation
|
132
|
+
# of a cache entry on any subsequent use. When the must-revalidate
|
133
|
+
# directive is present in a response received by a cache, that cache
|
134
|
+
# MUST NOT use the entry after it becomes stale to respond to a
|
135
|
+
# subsequent request without first revalidating it with the origin
|
136
|
+
# server. (I.e., the cache MUST do an end-to-end revalidation every
|
137
|
+
# time, if, based solely on the origin server's Expires or max-age
|
138
|
+
# value, the cached response is stale.)
|
139
|
+
#
|
140
|
+
# The must-revalidate directive is necessary to support reliable
|
141
|
+
# operation for certain protocol features. In all circumstances an
|
142
|
+
# HTTP/1.1 cache MUST obey the must-revalidate directive; in
|
143
|
+
# particular, if the cache cannot reach the origin server for any
|
144
|
+
# reason, it MUST generate a 504 (Gateway Timeout) response.
|
145
|
+
#
|
146
|
+
# Servers SHOULD send the must-revalidate directive if and only if
|
147
|
+
# failure to revalidate a request on the entity could result in
|
148
|
+
# incorrect operation, such as a silently unexecuted financial
|
149
|
+
# transaction. Recipients MUST NOT take any automated action that
|
150
|
+
# violates this directive, and MUST NOT automatically provide an
|
151
|
+
# unvalidated copy of the entity if revalidation fails.
|
152
|
+
def must_revalidate?
|
153
|
+
self['must-revalidate']
|
154
|
+
end
|
155
|
+
|
156
|
+
# The proxy-revalidate directive has the same meaning as the must-
|
157
|
+
# revalidate directive, except that it does not apply to non-shared
|
158
|
+
# user agent caches. It can be used on a response to an
|
159
|
+
# authenticated request to permit the user's cache to store and
|
160
|
+
# later return the response without needing to revalidate it (since
|
161
|
+
# it has already been authenticated once by that user), while still
|
162
|
+
# requiring proxies that service many users to revalidate each time
|
163
|
+
# (in order to make sure that each user has been authenticated).
|
164
|
+
# Note that such authenticated responses also need the public cache
|
165
|
+
# control directive in order to allow them to be cached at all.
|
166
|
+
def proxy_revalidate?
|
167
|
+
self['proxy-revalidate']
|
168
|
+
end
|
169
|
+
|
170
|
+
def to_s
|
171
|
+
bools, vals = [], []
|
172
|
+
each do |key,value|
|
173
|
+
if value == true
|
174
|
+
bools << key
|
175
|
+
elsif value
|
176
|
+
vals << "#{key}=#{value}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
(bools.sort + vals.sort).join(', ')
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
def parse(value)
|
184
|
+
return if value.nil? || value.empty?
|
185
|
+
value.delete(' ').split(',').inject(self) do |hash,part|
|
186
|
+
name, value = part.split('=', 2)
|
187
|
+
hash[name.downcase] = (value || true) unless name.empty?
|
188
|
+
hash
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|