rack-cache 1.1 → 1.2
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 +9 -0
- data/Rakefile +2 -2
- data/lib/rack/cache/context.rb +12 -1
- data/lib/rack/cache/metastore.rb +1 -1
- data/lib/rack/cache/options.rb +9 -0
- data/rack-cache.gemspec +3 -4
- data/test/context_test.rb +35 -0
- metadata +57 -84
- data/Gemfile.lock +0 -22
data/CHANGES
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 1.2 / March 2012
|
2
|
+
|
3
|
+
* Fix a cookie leak vulnerability effecting large numbers of Rails 3.x installs:
|
4
|
+
https://github.com/rtomayko/rack-cache/pull/52
|
5
|
+
|
6
|
+
* Never 304 on PUT or POST requests.
|
7
|
+
|
8
|
+
* Misc bundler and test tooling fixes.
|
9
|
+
|
1
10
|
## 1.1 / September 2011
|
2
11
|
|
3
12
|
* Allow (INM/IMS) validation requests through to backend on miss. Makes it
|
data/Rakefile
CHANGED
@@ -15,13 +15,13 @@ end
|
|
15
15
|
desc 'Run specs with unit test style output'
|
16
16
|
task :test => FileList['test/*_test.rb'] do |t|
|
17
17
|
suite = t.prerequisites
|
18
|
-
sh "bacon -q -I.:lib:test #{suite.join(' ')}", :verbose => false
|
18
|
+
sh "bundle exec bacon -q -I.:lib:test #{suite.join(' ')}", :verbose => false
|
19
19
|
end
|
20
20
|
|
21
21
|
desc 'Run specs with story style output'
|
22
22
|
task :spec => FileList['test/*_test.rb'] do |t|
|
23
23
|
suite = t.prerequisites
|
24
|
-
sh "bacon -I.:lib:test #{suite.join(' ')}", :verbose => false
|
24
|
+
sh "bundle exec bacon -I.:lib:test #{suite.join(' ')}", :verbose => false
|
25
25
|
end
|
26
26
|
|
27
27
|
desc 'Generate test coverage report'
|
data/lib/rack/cache/context.rb
CHANGED
@@ -18,6 +18,7 @@ module Rack::Cache
|
|
18
18
|
def initialize(backend, options={})
|
19
19
|
@backend = backend
|
20
20
|
@trace = []
|
21
|
+
@env = nil
|
21
22
|
|
22
23
|
initialize_options options
|
23
24
|
yield self if block_given?
|
@@ -82,7 +83,10 @@ module Rack::Cache
|
|
82
83
|
end
|
83
84
|
|
84
85
|
# tidy up response a bit
|
85
|
-
|
86
|
+
if (@request.get? || @request.head?) && not_modified?(response)
|
87
|
+
response.not_modified!
|
88
|
+
end
|
89
|
+
|
86
90
|
if @request.head?
|
87
91
|
response.body.close if response.body.respond_to?(:close)
|
88
92
|
response.body = []
|
@@ -259,6 +263,7 @@ module Rack::Cache
|
|
259
263
|
|
260
264
|
# Write the response to the cache.
|
261
265
|
def store(response)
|
266
|
+
strip_ignore_headers(response)
|
262
267
|
metastore.store(@request, response, entitystore)
|
263
268
|
response.headers['Age'] = response.age.to_s
|
264
269
|
rescue Exception => e
|
@@ -268,6 +273,12 @@ module Rack::Cache
|
|
268
273
|
record :store
|
269
274
|
end
|
270
275
|
|
276
|
+
# Remove all ignored response headers before writing to the cache.
|
277
|
+
def strip_ignore_headers(response)
|
278
|
+
stripped_values = ignore_headers.map { |name| response.headers.delete(name) }
|
279
|
+
record :ignore if stripped_values.any?
|
280
|
+
end
|
281
|
+
|
271
282
|
def log_error(exception)
|
272
283
|
@env['rack.errors'].write("cache error: #{exception.message}\n#{exception.backtrace.join("\n")}\n")
|
273
284
|
end
|
data/lib/rack/cache/metastore.rb
CHANGED
data/lib/rack/cache/options.rb
CHANGED
@@ -78,6 +78,14 @@ module Rack::Cache
|
|
78
78
|
# Default: 0
|
79
79
|
option_accessor :default_ttl
|
80
80
|
|
81
|
+
# Set of response headers that are removed before storing them in the
|
82
|
+
# cache. These headers are only removed for cacheable responses. For
|
83
|
+
# example, in most cases, it makes sense to prevent cookies from being
|
84
|
+
# stored in the cache.
|
85
|
+
#
|
86
|
+
# Default: ['Set-Cookie']
|
87
|
+
option_accessor :ignore_headers
|
88
|
+
|
81
89
|
# Set of request headers that trigger "private" cache-control behavior
|
82
90
|
# on responses that don't explicitly state whether the response is
|
83
91
|
# public or private via a Cache-Control directive. Applications that use
|
@@ -138,6 +146,7 @@ module Rack::Cache
|
|
138
146
|
'rack-cache.metastore' => 'heap:/',
|
139
147
|
'rack-cache.entitystore' => 'heap:/',
|
140
148
|
'rack-cache.default_ttl' => 0,
|
149
|
+
'rack-cache.ignore_headers' => ['Set-Cookie'],
|
141
150
|
'rack-cache.private_headers' => ['Authorization', 'Cookie'],
|
142
151
|
'rack-cache.allow_reload' => false,
|
143
152
|
'rack-cache.allow_revalidate' => false,
|
data/rack-cache.gemspec
CHANGED
@@ -3,11 +3,11 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'rack-cache'
|
6
|
-
s.version = '1.
|
7
|
-
s.date = '
|
6
|
+
s.version = '1.2'
|
7
|
+
s.date = '2012-03-05'
|
8
8
|
|
9
|
-
s.description = "HTTP Caching for Rack"
|
10
9
|
s.summary = "HTTP Caching for Rack"
|
10
|
+
s.description = "Rack::Cache is suitable as a quick drop-in component to enable HTTP caching for Rack-based applications that produce freshness (Expires, Cache-Control) and/or validation (Last-Modified, ETag) information."
|
11
11
|
|
12
12
|
s.authors = ["Ryan Tomayko"]
|
13
13
|
s.email = "r@tomayko.com"
|
@@ -17,7 +17,6 @@ Gem::Specification.new do |s|
|
|
17
17
|
CHANGES
|
18
18
|
COPYING
|
19
19
|
Gemfile
|
20
|
-
Gemfile.lock
|
21
20
|
README
|
22
21
|
Rakefile
|
23
22
|
TODO
|
data/test/context_test.rb
CHANGED
@@ -57,6 +57,7 @@ describe 'Rack::Cache::Context' do
|
|
57
57
|
response.should.be.ok
|
58
58
|
cache.trace.should.include :miss
|
59
59
|
cache.trace.should.include :store
|
60
|
+
cache.trace.should.not.include :ignore
|
60
61
|
response.headers.should.include 'Age'
|
61
62
|
response.headers['Cache-Control'].should.equal 'public'
|
62
63
|
end
|
@@ -85,6 +86,40 @@ describe 'Rack::Cache::Context' do
|
|
85
86
|
response.headers['Cache-Control'].should.equal 'private'
|
86
87
|
end
|
87
88
|
|
89
|
+
it 'does remove Set-Cookie response header from a cacheable response' do
|
90
|
+
respond_with 200, 'Cache-Control' => 'public', 'ETag' => '"FOO"', 'Set-Cookie' => 'TestCookie=OK'
|
91
|
+
get '/'
|
92
|
+
|
93
|
+
app.should.be.called
|
94
|
+
response.should.be.ok
|
95
|
+
cache.trace.should.include :store
|
96
|
+
cache.trace.should.include :ignore
|
97
|
+
response.headers['Set-Cookie'].should.be.nil
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'does remove all configured ignore_headers from a cacheable response' do
|
101
|
+
respond_with 200, 'Cache-Control' => 'public', 'ETag' => '"FOO"', 'SET-COOKIE' => 'TestCookie=OK', 'X-Strip-Me' => 'Secret'
|
102
|
+
get '/', 'rack-cache.ignore_headers' => ['set-cookie', 'x-strip-me']
|
103
|
+
|
104
|
+
app.should.be.called
|
105
|
+
response.should.be.ok
|
106
|
+
cache.trace.should.include :store
|
107
|
+
cache.trace.should.include :ignore
|
108
|
+
response.headers['Set-Cookie'].should.be.nil
|
109
|
+
response.headers['x-strip-me'].should.be.nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'does not remove Set-Cookie response header from a private response' do
|
113
|
+
respond_with 200, 'Cache-Control' => 'private', 'Set-Cookie' => 'TestCookie=OK'
|
114
|
+
get '/'
|
115
|
+
|
116
|
+
app.should.be.called
|
117
|
+
response.should.be.ok
|
118
|
+
cache.trace.should.not.include :store
|
119
|
+
cache.trace.should.not.include :ignore
|
120
|
+
response.headers['Set-Cookie'].should.equal 'TestCookie=OK'
|
121
|
+
end
|
122
|
+
|
88
123
|
it 'responds with 304 when If-Modified-Since matches Last-Modified' do
|
89
124
|
timestamp = Time.now.httpdate
|
90
125
|
respond_with do |req,res|
|
metadata
CHANGED
@@ -1,94 +1,75 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-cache
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.2'
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 1
|
9
|
-
version: "1.1"
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Ryan Tomayko
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2012-03-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
20
15
|
name: rack
|
21
|
-
|
22
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70248834703480 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
segments:
|
29
|
-
- 0
|
30
|
-
- 4
|
31
|
-
version: "0.4"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.4'
|
32
22
|
type: :runtime
|
33
|
-
version_requirements: *id001
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: bacon
|
36
23
|
prerelease: false
|
37
|
-
|
24
|
+
version_requirements: *70248834703480
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bacon
|
27
|
+
requirement: &70248834703100 !ruby/object:Gem::Requirement
|
38
28
|
none: false
|
39
|
-
requirements:
|
40
|
-
- -
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
version: "0"
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
46
33
|
type: :development
|
47
|
-
version_requirements: *id002
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
name: memcached
|
50
34
|
prerelease: false
|
51
|
-
|
35
|
+
version_requirements: *70248834703100
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: memcached
|
38
|
+
requirement: &70248834702640 !ruby/object:Gem::Requirement
|
52
39
|
none: false
|
53
|
-
requirements:
|
54
|
-
- -
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
|
57
|
-
segments:
|
58
|
-
- 0
|
59
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
60
44
|
type: :development
|
61
|
-
version_requirements: *id003
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: dalli
|
64
45
|
prerelease: false
|
65
|
-
|
46
|
+
version_requirements: *70248834702640
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: dalli
|
49
|
+
requirement: &70248834702220 !ruby/object:Gem::Requirement
|
66
50
|
none: false
|
67
|
-
requirements:
|
68
|
-
- -
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
|
71
|
-
segments:
|
72
|
-
- 0
|
73
|
-
version: "0"
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
74
55
|
type: :development
|
75
|
-
|
76
|
-
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70248834702220
|
58
|
+
description: Rack::Cache is suitable as a quick drop-in component to enable HTTP caching
|
59
|
+
for Rack-based applications that produce freshness (Expires, Cache-Control) and/or
|
60
|
+
validation (Last-Modified, ETag) information.
|
77
61
|
email: r@tomayko.com
|
78
62
|
executables: []
|
79
|
-
|
80
63
|
extensions: []
|
81
|
-
|
82
|
-
extra_rdoc_files:
|
64
|
+
extra_rdoc_files:
|
83
65
|
- README
|
84
66
|
- COPYING
|
85
67
|
- TODO
|
86
68
|
- CHANGES
|
87
|
-
files:
|
69
|
+
files:
|
88
70
|
- CHANGES
|
89
71
|
- COPYING
|
90
72
|
- Gemfile
|
91
|
-
- Gemfile.lock
|
92
73
|
- README
|
93
74
|
- Rakefile
|
94
75
|
- TODO
|
@@ -129,43 +110,35 @@ files:
|
|
129
110
|
- test/storage_test.rb
|
130
111
|
homepage: http://tomayko.com/src/rack-cache/
|
131
112
|
licenses: []
|
132
|
-
|
133
113
|
post_install_message:
|
134
|
-
rdoc_options:
|
114
|
+
rdoc_options:
|
135
115
|
- --line-numbers
|
136
116
|
- --inline-source
|
137
117
|
- --title
|
138
118
|
- Rack::Cache
|
139
119
|
- --main
|
140
120
|
- Rack::Cache
|
141
|
-
require_paths:
|
121
|
+
require_paths:
|
142
122
|
- lib
|
143
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
124
|
none: false
|
145
|
-
requirements:
|
146
|
-
- -
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
|
149
|
-
|
150
|
-
- 0
|
151
|
-
version: "0"
|
152
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ! '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
130
|
none: false
|
154
|
-
requirements:
|
155
|
-
- -
|
156
|
-
- !ruby/object:Gem::Version
|
157
|
-
|
158
|
-
segments:
|
159
|
-
- 0
|
160
|
-
version: "0"
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
161
135
|
requirements: []
|
162
|
-
|
163
136
|
rubyforge_project:
|
164
|
-
rubygems_version: 1.8.
|
137
|
+
rubygems_version: 1.8.11
|
165
138
|
signing_key:
|
166
139
|
specification_version: 2
|
167
140
|
summary: HTTP Caching for Rack
|
168
|
-
test_files:
|
141
|
+
test_files:
|
169
142
|
- test/cache_test.rb
|
170
143
|
- test/cachecontrol_test.rb
|
171
144
|
- test/context_test.rb
|
data/Gemfile.lock
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
rack-cache (1.0.3)
|
5
|
-
rack (>= 0.4)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: http://rubygems.org/
|
9
|
-
specs:
|
10
|
-
bacon (1.1.0)
|
11
|
-
dalli (1.0.5)
|
12
|
-
memcached (1.3)
|
13
|
-
rack (1.3.2)
|
14
|
-
|
15
|
-
PLATFORMS
|
16
|
-
ruby
|
17
|
-
|
18
|
-
DEPENDENCIES
|
19
|
-
bacon
|
20
|
-
dalli
|
21
|
-
memcached
|
22
|
-
rack-cache!
|