josh-rack-cache 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,167 @@
1
+ ## 0.6.0 / Unreleased
2
+
3
+ * Added support for memcached clusters and other advanced
4
+ configuration provided by the memcache-client and memcached
5
+ libraries. The "metastore" and "entitystore" options can now be
6
+ set to a MemCache object or Memcached object:
7
+
8
+ memcache = MemCache.new(['127.1.1.1', '127.1.1.2'], :namespace => "/foo")
9
+ use Rack::Cache,
10
+ :metastore => memcache,
11
+ :entitystore => memcache
12
+
13
+ * Fix "memcached://" metastore URL handling. The "memcached" variation
14
+ blew up, the "memcache" version was fine.
15
+
16
+ ## 0.5.0 / May 2009
17
+
18
+ * Added meta and entity store implementations based on the
19
+ memcache-client library. These are the default unless the memcached
20
+ library has already been required.
21
+
22
+ * The "allow_reload" and "allow_revalidate" options now default to
23
+ false instead of true. This means we break with RFC 2616 out of
24
+ the box but this is the expected configuration in a huge majority
25
+ of gateway cache scenarios. See the docs on configuration
26
+ options for more information on these options:
27
+ http://tomayko.com/src/rack-cache/configuration
28
+
29
+ * Added Google AppEngine memcache entity store and metastore
30
+ implementations. To use GAE's memcache with rack-cache, set the
31
+ "metastore" and "entitystore" options as follows:
32
+
33
+ use Rack::Cache,
34
+ :metastore => 'gae://cache-meta',
35
+ :entitystore => 'gae://cache-body'
36
+
37
+ The 'cache-meta' and 'cache-body' parts are memcache namespace
38
+ prefixes and should be set to different values.
39
+
40
+ ## 0.4.0 / March 2009
41
+
42
+ * Ruby 1.9.1 / Rack 1.0 compatible.
43
+
44
+ * Invalidate cache entries that match the request URL on non-GET/HEAD
45
+ requests. i.e., POST, PUT, DELETE cause matching cache entries to
46
+ be invalidated. The cache entry is validated with the backend using
47
+ a conditional GET the next time it's requested.
48
+
49
+ * Implement "Cache-Control: max-age=N" request directive by forcing
50
+ validation when the max-age provided exceeds the age of the cache
51
+ entry. This can be disabled by setting the "allow_revalidate" option to
52
+ false.
53
+
54
+ * Properly implement "Cache-Control: no-cache" request directive by
55
+ performing a full reload. RFC 2616 states that when "no-cache" is
56
+ present in the request, the cache MUST NOT serve a stored response even
57
+ after successful validation. This is slightly different from the
58
+ "no-cache" directive in responses, which indicates that the cache must
59
+ first validate its entry with the origin. Previously, we implemented
60
+ "no-cache" on requests by passing so no new cache entry would be stored
61
+ based on the response. Now we treat it as a forced miss and enter the
62
+ response into the cache if it's cacheable. This can be disabled by
63
+ setting the "allow_reload" option to false.
64
+
65
+ * Assume identical semantics for the "Pragma: no-cache" request header
66
+ as the "Cache-Control: no-cache" directive described above.
67
+
68
+ * Less crazy logging. When the verbose option is set, a single log entry
69
+ is written with a comma separated list of trace events. For example, if
70
+ the cache was stale but validated, the following log entry would be
71
+ written: "cache: stale, valid, store". When the verbose option is false,
72
+ no logging occurs.
73
+
74
+ * Added "X-Rack-Cache" response header with the same comma separated trace
75
+ value as described above. This gives some visibility into how the cache
76
+ processed the request.
77
+
78
+ * Add support for canonicalized cache keys, as well as custom cache key
79
+ generators, which are specified in the options as :cache_key as either
80
+ any object that has a call() or as a block. Cache key generators get
81
+ passed a request object and return a cache key string.
82
+
83
+ ## 0.3.0 / December 2008
84
+
85
+ * Add support for public and private cache control directives. Responses
86
+ marked as explicitly public are cached even when the request includes
87
+ an Authorization or Cookie header. Responses marked as explicitly private
88
+ are considered uncacheable.
89
+
90
+ * Added a "private_headers" option that dictates which request headers
91
+ trigger default "private" cache control processing. By default, the
92
+ Cookie and Authorization headers are included. Headers may be added or
93
+ removed as necessary to change the default private logic.
94
+
95
+ * Adhere to must-revalidate/proxy-revalidate cache control directives by
96
+ not assigning the default_ttl to responses that don't include freshness
97
+ information. This should let us begin using default_ttl more liberally
98
+ since we can control it using the must-revalidate/proxy-revalidate directives.
99
+
100
+ * Use the s-maxage Cache-Control value in preference to max-age when
101
+ present. The ttl= method now sets the s-maxage value instead of max-age.
102
+ Code that used ttl= to control freshness at the client needs to change
103
+ to set the max-age directive explicitly.
104
+
105
+ * Enable support for X-Sendfile middleware by responding to #to_path on
106
+ bodies served from disk storage. Adding the Rack::Sendfile component
107
+ upstream from Rack::Cache will result in cached bodies being served
108
+ directly by the web server (instead of being read in Ruby).
109
+
110
+ * BUG: MetaStore hits but EntityStore misses. This would 500 previously; now
111
+ we detect it and act as if the MetaStore missed as well.
112
+
113
+ * Implement low level #purge method on all concrete entity store
114
+ classes -- removes the entity body corresponding to the SHA1 key
115
+ provided and returns nil.
116
+
117
+ * Basically sane handling of HEAD requests. A HEAD request is never passed
118
+ through to the backend except when transitioning with pass!. This means
119
+ that the cache responds to HEAD requests without invoking the backend at
120
+ all when the cached entry is fresh. When no cache entry exists, or the
121
+ cached entry is stale and can be validated, the backend is invoked with
122
+ a GET request and the HEAD is handled right before the response
123
+ is delivered upstream.
124
+
125
+ * BUG: The Age response header was not being set properly when a stale
126
+ entry was validated. This would result in Age values that exceeded
127
+ the freshness lifetime in responses.
128
+
129
+ * BUG: A cached entry in a heap meta store could be unintentionally
130
+ modified by request processing since the cached objects were being
131
+ returned directly. The result was typically missing/incorrect header
132
+ values (e.g., missing Content-Type header). [dkubb]
133
+
134
+ * BUG: 304 responses should not include entity headers (especially
135
+ Content-Length). This is causing Safari/WebKit weirdness on 304
136
+ responses.
137
+
138
+ * BUG: The If-None-Match header was being ignored, causing the cache
139
+ to send 200 responses to matching conditional GET requests.
140
+
141
+ ## 0.2.0 / 2008-10-24 / Initial Release
142
+
143
+ * Document events and transitions in `rack/cache/config/default.rb`
144
+ * Basic logging support (`trace`, `warn`, `info`, `error` from within Context)
145
+ * EntityStore: store entity bodies keyed by SHA
146
+ * MetaStore: store response headers keyed by URL
147
+ * Last-Modified/ETag validation
148
+ * Vary support
149
+ * Implement error! transition
150
+ * New Rack::Cache::Core
151
+ * memcached meta and entity store implementations
152
+ * URI based storage configuration
153
+ * Read options from Rack env if present (rack-cache.XXX keys)
154
+ * `object` is now `entry`
155
+ * Documentation framework and website
156
+ * Document storage areas and implementations
157
+ * Document configuration/events
158
+
159
+ ## 0.1.0 / 2008-07-21 / Proof of concept (unreleased)
160
+
161
+ * Basic core with event support
162
+ * `#import` method for bringing in config files
163
+ * Freshness based expiration
164
+ * RFC 2616 If-Modified-Since based validation
165
+ * A horribly shitty storage back-end (Hash in mem)
166
+ * Don't cache hop-by-hop headers: Connection, Keep-Alive, Proxy-Authenticate,
167
+ 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,110 @@
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
+ * Standards-based (RFC 2616)
9
+ * Freshness/expiration based caching
10
+ * Validation (If-Modified-Since / If-None-Match)
11
+ * Vary support
12
+ * Cache-Control: public, private, max-age, s-maxage, must-revalidate,
13
+ and proxy-revalidate.
14
+ * Portable: 100% Ruby / works with any Rack-enabled framework
15
+ * Disk, memcached, and heap memory storage backends
16
+
17
+ For more information about Rack::Cache features and usage, see:
18
+
19
+ http://tomayko.com/src/rack-cache/
20
+
21
+ Rack::Cache is not overly optimized for performance. The main goal of the
22
+ project is to provide a portable, easy-to-configure, and standards-based
23
+ caching solution for small to medium sized deployments. More sophisticated /
24
+ high-performance caching systems (e.g., Varnish, Squid, httpd/mod-cache) may be
25
+ more appropriate for large deployments with significant throughput requirements.
26
+
27
+ Installation
28
+ ------------
29
+
30
+ From Gem:
31
+
32
+ $ sudo gem install rack-cache
33
+
34
+ With a local working copy:
35
+
36
+ $ git clone git://github.com/rtomayko/rack-cache.git
37
+ $ rake package && sudo rake install
38
+
39
+ Basic Usage
40
+ -----------
41
+
42
+ Rack::Cache is implemented as a piece of Rack middleware and can be used with
43
+ any Rack-based application. If your application includes a rackup (`.ru`) file
44
+ or uses Rack::Builder to construct the application pipeline, simply require
45
+ and use as follows:
46
+
47
+ require 'rack/cache'
48
+
49
+ use Rack::Cache,
50
+ :metastore => 'file:/var/cache/rack/meta',
51
+ :entitystore => 'file:/var/cache/rack/body',
52
+ :verbose => true
53
+
54
+ run app
55
+
56
+ Assuming you've designed your backend application to take advantage of HTTP's
57
+ caching features, no further code or configuration is required for basic
58
+ caching.
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
+
78
+ Links
79
+ -----
80
+
81
+ Documentation:
82
+ http://tomayko.com/src/rack-cache/
83
+
84
+ Mailing List:
85
+ http://groups.google.com/group/rack-cache
86
+
87
+ GitHub:
88
+ http://github.com/rtomayko/rack-cache/
89
+
90
+ License
91
+ -------
92
+
93
+ Copyright (c) 2008 Ryan Tomayko <http://tomayko.com/about>
94
+
95
+ Permission is hereby granted, free of charge, to any person obtaining a copy
96
+ of this software and associated documentation files (the "Software"), to
97
+ deal in the Software without restriction, including without limitation the
98
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
99
+ sell copies of the Software, and to permit persons to whom the Software is
100
+ furnished to do so, subject to the following conditions:
101
+
102
+ The above copyright notice and this permission notice shall be included in
103
+ all copies or substantial portions of the Software.
104
+
105
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
106
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
107
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
108
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
109
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
110
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,137 @@
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 "specrb -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: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 markdown documentation files'
59
+ task 'doc:markdown'
60
+ FileList['doc/*.markdown'].each do |source|
61
+ dest = "doc/#{File.basename(source, '.markdown')}.html"
62
+ file dest => [source, 'doc/layout.html.erb'] do |f|
63
+ puts "markdown: #{source} -> #{dest}" if verbose
64
+ require 'erb' unless defined? ERB
65
+ require 'rdiscount' unless defined? RDiscount
66
+ template = File.read(source)
67
+ content = Markdown.new(ERB.new(template, 0, "%<>").result(binding), :smart).to_html
68
+ title = content.match("<h1>(.*)</h1>")[1] rescue ''
69
+ layout = ERB.new(File.read("doc/layout.html.erb"), 0, "%<>")
70
+ output = layout.result(binding)
71
+ File.open(dest, 'w') { |io| io.write(output) }
72
+ end
73
+ task 'doc:markdown' => dest
74
+ CLEAN.include dest
75
+ end
76
+
77
+ desc 'Publish documentation'
78
+ task 'doc:publish' => :doc do
79
+ sh 'rsync -avz doc/ gus@tomayko.com:/src/rack-cache'
80
+ end
81
+
82
+ desc 'Start the documentation development server (requires thin)'
83
+ task 'doc:server' do
84
+ sh 'cd doc && thin --rackup server.ru --port 3035 start'
85
+ end
86
+
87
+ # PACKAGING =================================================================
88
+
89
+ def package(ext='')
90
+ "dist/rack-cache-#{$spec.version}" + ext
91
+ end
92
+
93
+ desc 'Build packages'
94
+ task :package => %w[.gem .tar.gz].map {|e| package(e)}
95
+
96
+ desc 'Build and install as local gem'
97
+ task :install => package('.gem') do
98
+ sh "gem install #{package('.gem')}"
99
+ end
100
+
101
+ directory 'dist/'
102
+
103
+ file package('.gem') => %w[dist/ rack-cache.gemspec] + $spec.files do |f|
104
+ sh "gem build rack-cache.gemspec"
105
+ mv File.basename(f.name), f.name
106
+ end
107
+
108
+ file package('.tar.gz') => %w[dist/] + $spec.files do |f|
109
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
110
+ end
111
+
112
+ desc 'Upload gem and tar.gz distributables to rubyforge'
113
+ task :release => [package('.gem'), package('.tar.gz')] do |t|
114
+ sh <<-SH
115
+ rubyforge add_release wink rack-cache #{$spec.version} #{package('.gem')} &&
116
+ rubyforge add_file wink rack-cache #{$spec.version} #{package('.tar.gz')}
117
+ SH
118
+ end
119
+
120
+ # GEMSPEC ===================================================================
121
+
122
+ file 'rack-cache.gemspec' => FileList['{lib,test}/**','Rakefile'] do |f|
123
+ # read spec file and split out manifest section
124
+ spec = File.read(f.name)
125
+ parts = spec.split(" # = MANIFEST =\n")
126
+ fail 'bad spec' if parts.length != 3
127
+ # determine file list from git ls-files
128
+ files = `git ls-files`.
129
+ split("\n").sort.reject{ |file| file =~ /^\./ }.
130
+ map{ |file| " #{file}" }.join("\n")
131
+ # piece file back together and write...
132
+ parts[1] = " s.files = %w[\n#{files}\n ]\n"
133
+ spec = parts.join(" # = MANIFEST =\n")
134
+ spec.sub!(/s.date = '.*'/, "s.date = '#{Time.now.strftime("%Y-%m-%d")}'")
135
+ File.open(f.name, 'w') { |io| io.write(spec) }
136
+ puts "updated #{f.name}"
137
+ end
data/TODO ADDED
@@ -0,0 +1,27 @@
1
+ ## 0.5
2
+
3
+ - Document allow_revalidate and allow_reload options.
4
+ - Support multiple memcache servers.
5
+ - Purge/invalidate everything
6
+ - Explicit expiration/invalidation based on response headers or via an
7
+ object interface passed in the rack env.
8
+ - Sample apps: Rack, Rails, Sinatra, Merb, etc.
9
+ - Move old breakers.rb configuration file into rack-contrib as a
10
+ middleware component.
11
+
12
+ ## Backlog
13
+
14
+ - Use Bacon instead of test/spec
15
+ - Fast path pass processing. We do a lot more than necessary just to determine
16
+ that the response should be passed through untouched.
17
+ - Invalidate at the URI of the Location or Content-Location response header
18
+ on POST, PUT, or DELETE that results in a redirect.
19
+ - Maximum size of cached entity
20
+ - Last-Modified factor: requests that have a Last-Modified header but no Expires
21
+ header have a TTL assigned based on the last modified age of the response:
22
+ TTL = (Age * Factor), or, 1h = (10h * 0.1)
23
+ - Consider implementing ESI (http://www.w3.org/TR/esi-lang). This should
24
+ probably be implemented as a separate middleware component.
25
+ - stale-while-revalidate
26
+ - Serve cached copies when down (see: stale-if-error) - e.g., database
27
+ connection drops and the cache takes over what it can.