rack-cache 0.2.0

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 +27 -0
  2. data/COPYING +18 -0
  3. data/README +96 -0
  4. data/Rakefile +144 -0
  5. data/TODO +40 -0
  6. data/doc/configuration.markdown +224 -0
  7. data/doc/events.dot +27 -0
  8. data/doc/faq.markdown +133 -0
  9. data/doc/index.markdown +113 -0
  10. data/doc/layout.html.erb +33 -0
  11. data/doc/license.markdown +24 -0
  12. data/doc/rack-cache.css +362 -0
  13. data/doc/storage.markdown +162 -0
  14. data/lib/rack/cache.rb +51 -0
  15. data/lib/rack/cache/config.rb +65 -0
  16. data/lib/rack/cache/config/busters.rb +16 -0
  17. data/lib/rack/cache/config/default.rb +134 -0
  18. data/lib/rack/cache/config/no-cache.rb +13 -0
  19. data/lib/rack/cache/context.rb +95 -0
  20. data/lib/rack/cache/core.rb +271 -0
  21. data/lib/rack/cache/entitystore.rb +224 -0
  22. data/lib/rack/cache/headers.rb +237 -0
  23. data/lib/rack/cache/metastore.rb +309 -0
  24. data/lib/rack/cache/options.rb +119 -0
  25. data/lib/rack/cache/request.rb +37 -0
  26. data/lib/rack/cache/response.rb +76 -0
  27. data/lib/rack/cache/storage.rb +50 -0
  28. data/lib/rack/utils/environment_headers.rb +78 -0
  29. data/rack-cache.gemspec +74 -0
  30. data/test/cache_test.rb +35 -0
  31. data/test/config_test.rb +66 -0
  32. data/test/context_test.rb +465 -0
  33. data/test/core_test.rb +84 -0
  34. data/test/entitystore_test.rb +176 -0
  35. data/test/environment_headers_test.rb +71 -0
  36. data/test/headers_test.rb +215 -0
  37. data/test/logging_test.rb +45 -0
  38. data/test/metastore_test.rb +210 -0
  39. data/test/options_test.rb +64 -0
  40. data/test/pony.jpg +0 -0
  41. data/test/response_test.rb +37 -0
  42. data/test/spec_setup.rb +189 -0
  43. data/test/storage_test.rb +94 -0
  44. metadata +120 -0
data/CHANGES ADDED
@@ -0,0 +1,27 @@
1
+ ## 0.2.0 / 2008-10-24 / Initial Release
2
+
3
+ * Document events and transitions in `rack/cache/config/default.rb`
4
+ * Basic logging support (`trace`, `warn`, `info`, `error` from within Context)
5
+ * EntityStore: store entity bodies keyed by SHA
6
+ * MetaStore: store response headers keyed by URL
7
+ * Last-Modified/ETag validation
8
+ * Vary support
9
+ * Implement error! transition
10
+ * New Rack::Cache::Core
11
+ * memcached meta and entity store implementations
12
+ * URI based storage configuration
13
+ * Read options from Rack env if present (rack-cache.XXX keys)
14
+ * `object` is now `entry`
15
+ * Documentation framework and website
16
+ * Document storage areas and implementations
17
+ * Document configuration/events
18
+
19
+ ## 0.1.0 / 2008-07-21 / Proof of concept (unreleased)
20
+
21
+ * Basic core with event support
22
+ * `#import` method for bringing in config files
23
+ * Freshness based expiration
24
+ * RFC 2616 If-Modified-Since based validation
25
+ * A horribly shitty storage back-end (Hash in mem)
26
+ * Don't cache hop-by-hop headers: Connection, Keep-Alive, Proxy-Authenticate,
27
+ Proxy-Authorization, TE, Trailers, Transfer-Encoding, Upgrade
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2008 Ryan Tomayko <http://tomayko.com/about>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,96 @@
1
+ Rack::Cache
2
+ ===========
3
+
4
+ Rack::Cache is suitable as a quick drop-in component to enable HTTP caching for
5
+ Rack-based applications that produce freshness (Expires, Cache-Control) and/or
6
+ validation (Last-Modified, ETag) information.
7
+
8
+ We strive to implement those portions of RFC 2616 Section 13 relevant to gateway
9
+ (i.e., "reverse proxy") cache scenarios with a system for specifying cache
10
+ policy:
11
+
12
+ * Standards-based (RFC 2616)
13
+ * Freshness/expiration based caching
14
+ * Validation
15
+ * Vary support
16
+ * Portable: 100% Ruby / works with any Rack-enabled framework
17
+ * Configuration language for advanced caching policies
18
+ * Disk, memcached, and heap memory storage backends
19
+
20
+ For more information about Rack::Cache features and usage, see:
21
+
22
+ http://tomayko.com/src/rack-cache/
23
+
24
+ Rack::Cache is not overly optimized for performance. The main goal of the
25
+ project is to provide a portable, easy-to-configure, and standards-based
26
+ caching solution for small to medium sized deployments. More sophisticated /
27
+ high-performance caching systems (e.g., Varnish, Squid, httpd/mod-cache) may be
28
+ more appropriate for large deployments with significant throughput requirements.
29
+
30
+ Status
31
+ ------
32
+
33
+ Rack::Cache is a young and experimental project that is likely to change
34
+ substantially and may not be wholly functional, consistent, fast, or correct.
35
+ The current focus is on reaching basic compliance with RFC 2616 and providing
36
+ good documentation.
37
+
38
+ Installation
39
+ ------------
40
+
41
+ From Gem:
42
+
43
+ $ sudo gem install rack-cache
44
+
45
+ With a local working copy:
46
+
47
+ $ git clone git://github.com/rtomayko/rack-cache.git
48
+ $ rake package && sudo rake install
49
+
50
+ Basic Usage
51
+ -----------
52
+
53
+ Rack::Cache is implemented as a piece of Rack middleware and can be used with
54
+ any Rack-based application. If your application includes a rackup (`.ru`) file
55
+ or uses Rack::Builder to construct the application pipeline, simply require
56
+ and use as follows:
57
+
58
+ require 'rack/cache'
59
+
60
+ use Rack::Cache,
61
+ :metastore => 'file:/var/cache/rack/meta',
62
+ :entitystore => 'file:/var/cache/rack/body',
63
+ :verbose => true
64
+
65
+ run app
66
+
67
+ Assuming you've designed your backend application to take advantage of HTTP's
68
+ caching features, no further code or configuration is required for basic
69
+ caching.
70
+
71
+ Documentation
72
+ -------------
73
+
74
+ http://tomayko.com/src/rack-cache/
75
+
76
+ License
77
+ -------
78
+
79
+ Copyright (c) 2008 Ryan Tomayko <http://tomayko.com/about>
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining a copy
82
+ of this software and associated documentation files (the "Software"), to
83
+ deal in the Software without restriction, including without limitation the
84
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
85
+ sell copies of the Software, and to permit persons to whom the Software is
86
+ furnished to do so, subject to the following conditions:
87
+
88
+ The above copyright notice and this permission notice shall be included in
89
+ all copies or substantial portions of the Software.
90
+
91
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
92
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
94
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
95
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
96
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,144 @@
1
+ require 'rake/clean'
2
+
3
+ task :default => :test
4
+
5
+ CLEAN.include %w[coverage/ doc/api tags]
6
+ CLOBBER.include %w[dist]
7
+
8
+ # load gemspec like github's gem builder to surface any SAFE issues.
9
+ Thread.new do
10
+ require 'rubygems/specification'
11
+ $spec = eval("$SAFE=3\n#{File.read('rack-cache.gemspec')}")
12
+ end.join
13
+
14
+ # SPECS =====================================================================
15
+
16
+ desc 'Run specs with story style output'
17
+ task :spec do
18
+ sh 'specrb --specdox -Ilib:test test/*_test.rb'
19
+ end
20
+
21
+ desc 'Run specs with unit test style output'
22
+ task :test => FileList['test/*_test.rb'] do |t|
23
+ suite = t.prerequisites
24
+ sh "testrb -Ilib:test #{suite.join(' ')}", :verbose => false
25
+ end
26
+
27
+ desc 'Generate test coverage report'
28
+ task :rcov do
29
+ sh "rcov -Ilib:test test/*_test.rb"
30
+ end
31
+
32
+ # DOC =======================================================================
33
+ desc 'Build all documentation'
34
+ task :doc => %w[doc:api doc:graphs doc:markdown]
35
+
36
+ # requires the hanna gem:
37
+ # gem install mislav-hanna --source=http://gems.github.com
38
+ desc 'Build API documentation (doc/api)'
39
+ task 'doc:api' => 'doc/api/index.html'
40
+ file 'doc/api/index.html' => FileList['lib/**/*.rb'] do |f|
41
+ rm_rf 'doc/api'
42
+ sh((<<-SH).gsub(/[\s\n]+/, ' ').strip)
43
+ hanna
44
+ --op doc/api
45
+ --promiscuous
46
+ --charset utf8
47
+ --fmt html
48
+ --inline-source
49
+ --line-numbers
50
+ --accessor option_accessor=RW
51
+ --main Rack::Cache
52
+ --title 'Rack::Cache API Documentation'
53
+ #{f.prerequisites.join(' ')}
54
+ SH
55
+ end
56
+ CLEAN.include 'doc/api'
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
+ desc 'Build markdown documentation files'
72
+ task 'doc:markdown'
73
+ FileList['doc/*.markdown'].each do |source|
74
+ dest = "doc/#{File.basename(source, '.markdown')}.html"
75
+ file dest => source do |f|
76
+ puts "markdown: #{source} -> #{dest}" if verbose
77
+ require 'erb'
78
+ require 'rdiscount'
79
+ template = File.read(source)
80
+ content = Markdown.new(ERB.new(template, 0, "%<>").result(binding)).to_html
81
+ title = content.match("<h1>(.*)</h1>")[1] rescue ''
82
+ layout = ERB.new(File.read("doc/layout.html.erb"), 0, "%<>")
83
+ output = layout.result(binding)
84
+ File.open(dest, 'w') { |io| io.write(output) }
85
+ end
86
+ task 'doc:markdown' => dest
87
+ CLEAN.include dest
88
+ end
89
+
90
+ task 'doc:publish' => :doc do
91
+ sh 'rsync -avz doc/ gus@tomayko.com:/src/rack-cache'
92
+ end
93
+
94
+ # PACKAGING =================================================================
95
+
96
+ def package(ext='')
97
+ "dist/rack-cache-#{$spec.version}" + ext
98
+ end
99
+
100
+ desc 'Build packages'
101
+ task :package => %w[.gem .tar.gz].map {|e| package(e)}
102
+
103
+ desc 'Build and install as local gem'
104
+ task :install => package('.gem') do
105
+ sh "gem install #{package('.gem')}"
106
+ end
107
+
108
+ directory 'dist/'
109
+
110
+ file package('.gem') => %w[dist/ rack-cache.gemspec] + $spec.files do |f|
111
+ sh "gem build rack-cache.gemspec"
112
+ mv File.basename(f.name), f.name
113
+ end
114
+
115
+ file package('.tar.gz') => %w[dist/] + $spec.files do |f|
116
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
117
+ end
118
+
119
+ desc 'Upload gem and tar.gz distributables to rubyforge'
120
+ task :release => [package('.gem'), package('.tar.gz')] do |t|
121
+ sh <<-SH
122
+ rubyforge add_release wink rack-cache #{$spec.version} #{package('.gem')} &&
123
+ rubyforge add_file wink rack-cache #{$spec.version} #{package('.tar.gz')}
124
+ SH
125
+ end
126
+
127
+ # GEMSPEC ===================================================================
128
+
129
+ file 'rack-cache.gemspec' => FileList['{lib,test}/**','Rakefile'] do |f|
130
+ # read spec file and split out manifest section
131
+ spec = File.read(f.name)
132
+ parts = spec.split(" # = MANIFEST =\n")
133
+ fail 'bad spec' if parts.length != 3
134
+ # determine file list from git ls-files
135
+ files = `git ls-files`.
136
+ split("\n").sort.reject{ |file| file =~ /^\./ }.
137
+ map{ |file| " #{file}" }.join("\n")
138
+ # piece file back together and write...
139
+ parts[1] = " s.files = %w[\n#{files}\n ]\n"
140
+ spec = parts.join(" # = MANIFEST =\n")
141
+ spec.sub!(/s.date = '.*'/, "s.date = '#{Time.now.strftime("%Y-%m-%d")}'")
142
+ File.open(f.name, 'w') { |io| io.write(spec) }
143
+ puts "updated #{f.name}"
144
+ end
data/TODO ADDED
@@ -0,0 +1,40 @@
1
+ ## 0.3
2
+
3
+ - BUG: meta store hits but entity misses
4
+ - BUG: HEAD request on invalid entry caches zero-length response
5
+ - BUG: Response body written to cache each time validation succeeds
6
+ - Are we doing HEAD properly?
7
+ - liberal, conservative, sane caching configs
8
+ - Sample app
9
+ - busters.rb doc and tests
10
+ - no-cache.rb doc and tests
11
+ - Canonicalized URL for cache key:
12
+ - sorts params by key, then value
13
+ - urlencodes /[^ A-Za-z0-9_.-]/ host, path, and param key/value
14
+ - Support server-specific X-Sendfile (or similar) for delivering cached
15
+ bodies (file entity stores only).
16
+ - Sqlite3 (meta store)
17
+ - Cache invalidation on PUT, POST, DELETE.
18
+ - Invalidate at the request URI; or, anything that's "near" the request URI.
19
+ - Invalidate at the URI of the Location or Content-Location response header.
20
+
21
+ ## Backlog
22
+
23
+ - Purge/invalidate specific cache entries
24
+ - Purge/invalidate everything
25
+ - Maximum size of cached entity
26
+ - Last-Modified factor: requests that have a Last-Modified header but no Expires
27
+ header have a TTL assigned based on the last modified age of the response:
28
+ TTL = (Age * Factor), or, 1h = (10h * 0.1)
29
+ - I wonder if it would be possible to run in threaded mode but with an
30
+ option to lock before making requests to the backend. The idea is to be
31
+ able to serve requests from cache in separate threads. This should
32
+ probably be implemented as a separate middleware component.
33
+ - stale-while-revalidate
34
+ - Serve cached copies when down (see: stale-if-error) - e.g., database
35
+ connection drops and the cache takes over what it can.
36
+ - When a cache misses due to Vary, try to validate using the best match. Note
37
+ that you can't do this with a weak validator, so only strong etags can be
38
+ used.
39
+ - Consider implementing ESI (http://www.w3.org/TR/esi-lang). This should
40
+ probably be implemented as a separate middleware component.
@@ -0,0 +1,224 @@
1
+ Configuration Language
2
+ ======================
3
+
4
+ __Rack::Cache__ includes a configuration system that can be used to specify
5
+ fairly sophisticated cache policy on a global or per-request basis.
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
+ <a id='setopt'></a>
42
+
43
+ Setting Cache Options
44
+ ---------------------
45
+
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__.
49
+
50
+ When the __Rack::Cache__ object is instantiated:
51
+
52
+ use Rack::Cache,
53
+ :verbose => true,
54
+ :metastore => 'memcached://localhost:11211/',
55
+ :entitystore => 'file:/var/cache/rack'
56
+
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
+ Using __Rack__'s __Environment__:
66
+
67
+ env.merge!(
68
+ 'rack-cache.verbose' => true,
69
+ 'rack-cache.metastore' => 'memcached://localhost:11211/',
70
+ 'rack-cache.entitystore' => 'file:/var/cache/rack'
71
+ )
72
+
73
+ <a id='options'></a>
74
+
75
+ Cache Option Reference
76
+ ----------------------
77
+
78
+ Use the following options to customize __Rack::Cache__:
79
+
80
+ ### `verbose`
81
+
82
+ Boolean specifying whether verbose trace logging is enabled. This option is
83
+ currently enabled (`true`) by default but is likely to be disabled (`false`) in
84
+ a future release. All log output is written to the `rack.errors` stream, which
85
+ is typically set to `STDERR`.
86
+
87
+ The `trace`, `info`, `warn`, and `error` methods can be used within the
88
+ configuration context to write messages to the errors stream.
89
+
90
+ ### `default_ttl`
91
+
92
+ An integer specifying the number of seconds a cached object should be considered
93
+ "fresh" when no explicit freshness information is provided in a response.
94
+ Explicit `Cache-Control` or `Expires` response headers always override this
95
+ value. The `default_ttl` option defaults to `0`, meaning responses without
96
+ explicit freshness information are considered immediately "stale" and will not
97
+ be served from cache without validation.
98
+
99
+ ### `metastore`
100
+
101
+ A URI specifying the __MetaStore__ implementation used to store request/response
102
+ meta information. See the [Rack::Cache Storage Documentation](storage.html)
103
+ for detailed information on different storage implementations.
104
+
105
+ If no metastore is specified, the `heap:/` store is assumed. This implementation
106
+ has significant draw-backs so explicit configuration is recommended.
107
+
108
+ ### `entitystore`
109
+
110
+ A URI specifying the __EntityStore__ implementation used to store
111
+ response bodies. See the [Rack::Cache Storage Documentation](storage.html)
112
+ for detailed information on different storage implementations.
113
+
114
+ If no entitystore is specified, the `heap:/` store is assumed. This
115
+ implementation has significant draw-backs so explicit configuration is
116
+ recommended.
117
+
118
+ <a id='machinery'></a>
119
+
120
+ Configuration Machinery - Events and Transitions
121
+ ------------------------------------------------
122
+
123
+ The configuration machinery is built around a series of interceptable events and
124
+ transitions controlled by a simple configuration language. The following diagram
125
+ shows each state (interceptable event) along with their possible transitions:
126
+
127
+ <p class='center'>
128
+ <img src='events.png' alt='Events and Transitions Diagram' />
129
+ </p>
130
+
131
+ Custom logic can be layered onto the `receive`, `hit`, `miss`, `fetch`, `store`,
132
+ `deliver`, and `pass` events by passing a block to the `on` method:
133
+
134
+ on :fetch do
135
+ trace 'fetched %p from backend application', request.url
136
+ end
137
+
138
+ Here, the `trace` method writes a message to the `rack.errors` stream when a
139
+ response is fetched from the backend application. The `request` object is a
140
+ [__Rack::Cache::Request__](./api/classes/Rack/Cache/Request) that can be
141
+ inspected (and modified) to determine what action should be taken next.
142
+
143
+ Event blocks are capable of performing more interesting operations:
144
+
145
+ * Transition to a different event or override default caching logic.
146
+ * Modify the request, response, cache entry, or Rack environment options.
147
+ * Set the `metastore` or `entitystore` options to select a different storage
148
+ mechanism / location dynamically.
149
+ * Collect statistics or log request/response/cache information.
150
+
151
+ When an event is triggered, the blocks associated with the event are executed in
152
+ reverse/FILO order (i.e., the block declared last runs first) until a
153
+ _transitioning statement_ is encountered. Transitioning statements are suffixed
154
+ with a bang character (e.g, `pass!`, `store!`, `error!`) and cause the current
155
+ event to halt and the machine to transition to the subsequent event; control is
156
+ not returned to the original event. The [default configuration](#default)
157
+ includes documentation on available transitions for each event.
158
+
159
+ The `next` statement can be used to exit an event block without transitioning
160
+ to another event. Subsequent event blocks are executed until a transitioning
161
+ statement is encountered:
162
+
163
+ on :fetch do
164
+ next if response.freshness_information?
165
+
166
+ if request.url =~ /\/feed$/
167
+ trace 'feed will expire in fifteen minutes'
168
+ response.ttl = 15 * 60
169
+ end
170
+ end
171
+
172
+ <a id='import'></a>
173
+
174
+ Importing Configuration
175
+ -----------------------
176
+
177
+ Since caching logic can be layered, it's possible to separate various bits of
178
+ cache policy into files for organization and reuse.
179
+
180
+ use Rack::Cache do
181
+ import 'rack/cache/config/busters'
182
+ import 'mycacheconfig'
183
+
184
+ # more stuff here
185
+ end
186
+
187
+ The `breakers` and `mycacheconfig` configuration files are normal Ruby source
188
+ files (i.e., they have a `.rb` extension) situated on the `$LOAD_PATH` - the
189
+ `import` statement works like Ruby's `require` statement but the contents of the
190
+ files are evaluated in the context of the configuration machinery, as if
191
+ specified directly in the configuration block.
192
+
193
+ The `rack/cache/config/busters.rb` file makes a good example. It hooks into the
194
+ `fetch` event and adds an impractically long expiration lifetime to any response
195
+ that includes a cache busting query string:
196
+
197
+ <%= File.read('lib/rack/cache/config/busters.rb').gsub(/^/, ' ') %>
198
+
199
+
200
+ <a id='default'></a>
201
+
202
+ Default Configuration Machinery
203
+ -------------------------------
204
+
205
+ The `rack/cache/config/default.rb` file is imported when the __Rack::Cache__
206
+ object is instantiated and before any custom configuration code is executed.
207
+ It's useful to understand this configuration because it drives the default
208
+ transitioning logic.
209
+
210
+ <%= File.read('lib/rack/cache/config/default.rb').gsub(/^/, ' ') %>
211
+
212
+ <a id='notes'></a>
213
+
214
+ Notes
215
+ -----
216
+
217
+ The configuration language was inspired by [Varnish][var]'s
218
+ [VCL configuration language][vcl].
219
+
220
+ [var]: http://varnish.projects.linpro.no/
221
+ "Varnish HTTP accelerator"
222
+
223
+ [vcl]: http://tomayko.com/man/vcl
224
+ "VCL(7) -- Varnish Configuration Language Manual Page"