rack-cache 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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"