josh-rack-cache 0.5.1

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.
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.