rack-cache 0.3.0 → 0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack-cache might be problematic. Click here for more details.

Files changed (44) hide show
  1. data/CHANGES +43 -0
  2. data/README +18 -9
  3. data/Rakefile +1 -14
  4. data/TODO +13 -14
  5. data/doc/configuration.markdown +7 -153
  6. data/doc/faq.markdown +8 -0
  7. data/doc/index.markdown +7 -9
  8. data/example/sinatra/app.rb +25 -0
  9. data/example/sinatra/views/index.erb +44 -0
  10. data/lib/rack/cache.rb +5 -11
  11. data/lib/rack/cache/cachecontrol.rb +193 -0
  12. data/lib/rack/cache/context.rb +190 -52
  13. data/lib/rack/cache/entitystore.rb +10 -4
  14. data/lib/rack/cache/key.rb +52 -0
  15. data/lib/rack/cache/metastore.rb +52 -16
  16. data/lib/rack/cache/options.rb +60 -39
  17. data/lib/rack/cache/request.rb +11 -15
  18. data/lib/rack/cache/response.rb +221 -30
  19. data/lib/rack/cache/storage.rb +1 -2
  20. data/rack-cache.gemspec +9 -15
  21. data/test/cache_test.rb +9 -6
  22. data/test/cachecontrol_test.rb +139 -0
  23. data/test/context_test.rb +251 -169
  24. data/test/entitystore_test.rb +12 -11
  25. data/test/key_test.rb +50 -0
  26. data/test/metastore_test.rb +57 -14
  27. data/test/options_test.rb +11 -0
  28. data/test/request_test.rb +19 -0
  29. data/test/response_test.rb +164 -23
  30. data/test/spec_setup.rb +7 -0
  31. metadata +12 -20
  32. data/doc/events.dot +0 -27
  33. data/lib/rack/cache/config.rb +0 -65
  34. data/lib/rack/cache/config/busters.rb +0 -16
  35. data/lib/rack/cache/config/default.rb +0 -133
  36. data/lib/rack/cache/config/no-cache.rb +0 -13
  37. data/lib/rack/cache/core.rb +0 -299
  38. data/lib/rack/cache/headers.rb +0 -325
  39. data/lib/rack/utils/environment_headers.rb +0 -78
  40. data/test/config_test.rb +0 -66
  41. data/test/core_test.rb +0 -84
  42. data/test/environment_headers_test.rb +0 -69
  43. data/test/headers_test.rb +0 -298
  44. data/test/logging_test.rb +0 -45
data/CHANGES CHANGED
@@ -1,3 +1,46 @@
1
+ ## 0.4.0 / March 2009
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. This can be disabled by setting the "allow_revalidate" option to
13
+ false.
14
+
15
+ * Properly implement "Cache-Control: no-cache" request directive by
16
+ performing a full reload. RFC 2616 states that when "no-cache" is
17
+ present in the request, the cache MUST NOT serve a stored response even
18
+ after successful validation. This is slightly different from the
19
+ "no-cache" directive in responses, which indicates that the cache must
20
+ first validate its entry with the origin. Previously, we implemented
21
+ "no-cache" on requests by passing so no new cache entry would be stored
22
+ based on the response. Now we treat it as a forced miss and enter the
23
+ response into the cache if it's cacheable. This can be disabled by
24
+ setting the "allow_reload" option to false.
25
+
26
+ * Assume identical semantics for the "Pragma: no-cache" request header
27
+ as the "Cache-Control: no-cache" directive described above.
28
+
29
+ * Less crazy logging. When the verbose option is set, a single log entry
30
+ is written with a comma separated list of trace events. For example, if
31
+ the cache was stale but validated, the following log entry would be
32
+ written: "cache: stale, valid, store". When the verbose option is false,
33
+ no logging occurs.
34
+
35
+ * Added "X-Rack-Cache" response header with the same comma separated trace
36
+ value as described above. This gives some visibility into how the cache
37
+ processed the request.
38
+
39
+ * Add support for canonicalized cache keys, as well as custom cache key
40
+ generators, which are specified in the options as :cache_key as either
41
+ any object that has a call() or as a block. Cache key generators get
42
+ passed a request object and return a cache key string.
43
+
1
44
  ## 0.3.0 / December 2008
2
45
 
3
46
  * 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:
@@ -25,14 +24,6 @@ caching solution for small to medium sized deployments. More sophisticated /
25
24
  high-performance caching systems (e.g., Varnish, Squid, httpd/mod-cache) may be
26
25
  more appropriate for large deployments with significant throughput requirements.
27
26
 
28
- Status
29
- ------
30
-
31
- Rack::Cache is a young and experimental project that is likely to change
32
- substantially and may not be wholly functional, consistent, fast, or correct.
33
- The current focus is on reaching basic compliance with RFC 2616 and providing
34
- good documentation.
35
-
36
27
  Installation
37
28
  ------------
38
29
 
@@ -66,6 +57,24 @@ Assuming you've designed your backend application to take advantage of HTTP's
66
57
  caching features, no further code or configuration is required for basic
67
58
  caching.
68
59
 
60
+ Using with Rails
61
+ ----------------
62
+
63
+ Add this to your `config/environment.rb`:
64
+
65
+ config.middleware.use Rack::Cache,
66
+ :verbose => true,
67
+ :metastore => 'file:/var/cache/rack/meta',
68
+ :entitystore => 'file:/var/cache/rack/body'
69
+
70
+ You should now see `Rack::Cache` listed in the middleware pipeline:
71
+
72
+ rake middleware
73
+
74
+ See the following for more information:
75
+
76
+ http://snippets.aktagon.com/snippets/302
77
+
69
78
  Links
70
79
  -----
71
80
 
data/Rakefile CHANGED
@@ -31,7 +31,7 @@ end
31
31
 
32
32
  # DOC =======================================================================
33
33
  desc 'Build all documentation'
34
- task :doc => %w[doc:api doc:graphs doc:markdown]
34
+ task :doc => %w[doc:api doc:markdown]
35
35
 
36
36
  # requires the hanna gem:
37
37
  # gem install mislav-hanna --source=http://gems.github.com
@@ -55,19 +55,6 @@ file 'doc/api/index.html' => FileList['lib/**/*.rb'] do |f|
55
55
  end
56
56
  CLEAN.include 'doc/api'
57
57
 
58
- desc 'Build graphviz graphs'
59
- task 'doc:graphs'
60
- %w[pdf png svg].each do |filetype|
61
- FileList["doc/*.dot"].each do |source|
62
- dest = source.sub(/dot$/, filetype)
63
- file dest => source do |f|
64
- sh "dot -T#{filetype} #{source} -o #{f.name}"
65
- end
66
- task 'doc:graphs' => dest
67
- CLEAN.include dest
68
- end
69
- end
70
-
71
58
  desc 'Build markdown documentation files'
72
59
  task 'doc:markdown'
73
60
  FileList['doc/*.markdown'].each do |source|
data/TODO CHANGED
@@ -1,21 +1,20 @@
1
- ## 0.4
2
-
3
- - liberal, conservative, sane caching configs
4
- - 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
-
14
1
  ## Backlog
15
2
 
3
+ - Move breakers.rb configuration file into rack-contrib as a middleware
4
+ component.
5
+ - Sample apps: Rack, Rails, Sinatra, Merb, etc.
6
+ - Use Bacon instead of test/spec
7
+ - Work with both memcache and memcached gems (memcached hasn't built on MacOS
8
+ for some time now).
9
+ - Fast path pass processing. We do a lot more than necessary just to determine
10
+ that the response should be passed through untouched.
11
+ - Don't purge/remove cache entries when invalidating. The entries should be
12
+ marked as stale and be forced revalidated on the next request instead of
13
+ being removed entirely.
16
14
  - Add missing Expires header if we have a max-age.
17
- - Purge/invalidate specific cache entries
18
15
  - Purge/invalidate everything
16
+ - Invalidate at the URI of the Location or Content-Location response header
17
+ on POST, PUT, or DELETE that results in a redirect.
19
18
  - Maximum size of cached entity
20
19
  - Last-Modified factor: requests that have a Last-Modified header but no Expires
21
20
  header have a TTL assigned based on the last modified age of the response:
@@ -1,51 +1,17 @@
1
- Configuration Language
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; or by using
47
- the `set` method within a configuration block; or by setting a
48
- `rack-cache.<option>` variable in __Rack__'s __Environment__.
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
- <a id='machinery'></a>
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
- [vcl]: http://tomayko.com/man/vcl
232
- "VCL(7) -- Varnish Configuration Language Manual Page"
86
+ TODO: Document custom cache keys
data/doc/faq.markdown CHANGED
@@ -10,6 +10,14 @@ General
10
10
  -------
11
11
 
12
12
 
13
+ <a class='hash' id='rails' href='#rails'>#</a>
14
+
15
+ ### Q: Can I use Rack::Cache with Rails?
16
+
17
+ Rack::Cache can be used with Rails 2.3 or above. Documentation and a
18
+ sample application is forthcoming; in the mean time, see
19
+ [this example of using Rack::Cache with Rails 2.3](http://snippets.aktagon.com/snippets/302-How-to-setup-and-use-Rack-Cache-with-Rails-2-3-0-RC-1).
20
+
13
21
  <a class='hash' id='why-not-squid' href='#why-not-squid'>#</a>
14
22
 
15
23
  ### Q: Why Rack::Cache? Why not Squid, Varnish, Perlbol, etc.?
data/doc/index.markdown CHANGED
@@ -7,16 +7,15 @@ 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
- Status
14
- ------
12
+ News
13
+ ----
15
14
 
16
- __Rack::Cache__ is a young and experimental project that is likely to
17
- change substantially and may not be wholly functional, consistent,
18
- fast, or correct. The current focus is on reaching basic compliance
19
- with RFC 2616 and providing good documentation.
15
+ * [How to use Rack::Cache with Rails 2.3](http://snippets.aktagon.com/snippets/302-How-to-setup-and-use-Rack-Cache-with-Rails-2-3-0-RC-1) - it's really easy.
16
+ * [RailsLab's Advanced HTTP Caching Screencast](http://railslab.newrelic.com/2009/02/26/episode-11-advanced-http-caching)
17
+ is a really great review of HTTP caching concepts and shows how to
18
+ use Rack::Cache with Rails.
20
19
 
21
20
  Installation
22
21
  ------------
@@ -52,8 +51,7 @@ caching.
52
51
  More
53
52
  ----
54
53
 
55
- * [Configuration Language Documentation][config] - how to customize cache
56
- policy using the simple event-based configuration system.
54
+ * [Configuration 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>