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 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'
@@ -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
- response.not_modified! if not_modified?(response)
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
@@ -37,7 +37,7 @@ module Rack::Cache
37
37
  match = entries.detect{|req,res| requests_match?(res['Vary'], env, req)}
38
38
  return nil if match.nil?
39
39
 
40
- req, res = match
40
+ _, res = match
41
41
  if body = entity_store.open(res['X-Content-Digest'])
42
42
  restore_response(res, body)
43
43
  else
@@ -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,
@@ -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.1'
7
- s.date = '2011-09-18'
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
@@ -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
- hash: 13
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
- date: 2011-09-18 00:00:00 Z
18
- dependencies:
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
- prerelease: false
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
- hash: 3
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
- requirement: &id002 !ruby/object:Gem::Requirement
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
- hash: 3
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
- requirement: &id003 !ruby/object:Gem::Requirement
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
- hash: 3
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
- requirement: &id004 !ruby/object:Gem::Requirement
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
- hash: 3
71
- segments:
72
- - 0
73
- version: "0"
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
74
55
  type: :development
75
- version_requirements: *id004
76
- description: HTTP Caching for Rack
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
- hash: 3
149
- segments:
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
- hash: 3
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.6
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
@@ -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!