rack-cache 0.2.0 → 0.3.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.
- data/CHANGES +58 -0
- data/README +14 -9
- data/Rakefile +11 -5
- data/TODO +11 -19
- data/doc/configuration.markdown +9 -1
- data/doc/index.markdown +17 -10
- data/doc/layout.html.erb +1 -0
- data/doc/server.ru +34 -0
- data/lib/rack/cache/config/default.rb +1 -2
- data/lib/rack/cache/core.rb +37 -9
- data/lib/rack/cache/entitystore.rb +29 -6
- data/lib/rack/cache/headers.rb +118 -30
- data/lib/rack/cache/metastore.rb +22 -39
- data/lib/rack/cache/options.rb +11 -1
- data/lib/rack/cache/response.rb +2 -2
- data/rack-cache.gemspec +5 -4
- data/test/cache_test.rb +3 -3
- data/test/context_test.rb +255 -75
- data/test/core_test.rb +8 -8
- data/test/entitystore_test.rb +23 -11
- data/test/environment_headers_test.rb +10 -12
- data/test/headers_test.rb +106 -23
- data/test/metastore_test.rb +28 -18
- data/test/options_test.rb +13 -10
- data/test/spec_setup.rb +13 -7
- metadata +8 -4
data/rack-cache.gemspec
CHANGED
@@ -3,8 +3,8 @@ 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 = '0.
|
7
|
-
s.date = '2008-
|
6
|
+
s.version = '0.3.0'
|
7
|
+
s.date = '2008-12-28'
|
8
8
|
|
9
9
|
s.description = "HTTP Caching for Rack"
|
10
10
|
s.summary = "HTTP Caching for Rack"
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
doc/layout.html.erb
|
27
27
|
doc/license.markdown
|
28
28
|
doc/rack-cache.css
|
29
|
+
doc/server.ru
|
29
30
|
doc/storage.markdown
|
30
31
|
lib/rack/cache.rb
|
31
32
|
lib/rack/cache/config.rb
|
@@ -62,11 +63,11 @@ Gem::Specification.new do |s|
|
|
62
63
|
|
63
64
|
s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
|
64
65
|
|
65
|
-
s.extra_rdoc_files = %w[COPYING]
|
66
|
+
s.extra_rdoc_files = %w[README COPYING TODO CHANGES]
|
66
67
|
s.add_dependency 'rack', '~> 0.4'
|
67
68
|
|
68
69
|
s.has_rdoc = true
|
69
|
-
s.homepage = "http://
|
70
|
+
s.homepage = "http://tomayko.com/src/rack-cache/"
|
70
71
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rack::Cache", "--main", "Rack::Cache"]
|
71
72
|
s.require_paths = %w[lib]
|
72
73
|
s.rubyforge_project = 'wink'
|
data/test/cache_test.rb
CHANGED
@@ -18,8 +18,8 @@ describe 'Rack::Cache::new' do
|
|
18
18
|
end
|
19
19
|
it 'sets options provided in the options Hash' do
|
20
20
|
object = Rack::Cache.new(@app, :foo => 'bar', 'foo.bar' => 'bling')
|
21
|
-
object.options['foo.bar'].should.
|
22
|
-
object.options['rack-cache.foo'].should.
|
21
|
+
object.options['foo.bar'].should.equal 'bling'
|
22
|
+
object.options['rack-cache.foo'].should.equal 'bar'
|
23
23
|
end
|
24
24
|
it 'takes a block; executes it during initialization' do
|
25
25
|
state, block_scope = 'not invoked', nil
|
@@ -29,7 +29,7 @@ describe 'Rack::Cache::new' do
|
|
29
29
|
state = 'invoked'
|
30
30
|
should.respond_to :on
|
31
31
|
end
|
32
|
-
state.should.
|
32
|
+
state.should.equal 'invoked'
|
33
33
|
object.should.be block_scope
|
34
34
|
end
|
35
35
|
end
|
data/test/context_test.rb
CHANGED
@@ -15,24 +15,98 @@ describe 'Rack::Cache::Context' do
|
|
15
15
|
response.headers.should.not.include 'Age'
|
16
16
|
end
|
17
17
|
|
18
|
-
it '
|
19
|
-
respond_with 200
|
18
|
+
it 'does not cache with Authorization request header and non public response' do
|
19
|
+
respond_with 200, 'Etag' => '"FOO"'
|
20
20
|
get '/', 'HTTP_AUTHORIZATION' => 'basic foobarbaz'
|
21
21
|
|
22
22
|
app.should.be.called
|
23
23
|
response.should.be.ok
|
24
|
-
|
24
|
+
response.headers['Cache-Control'].should.equal 'private'
|
25
|
+
cache.should.a.performed :miss
|
26
|
+
cache.should.a.performed :fetch
|
27
|
+
cache.should.a.not.performed :store
|
28
|
+
cache.should.a.performed :deliver
|
25
29
|
response.headers.should.not.include 'Age'
|
26
30
|
end
|
27
31
|
|
28
|
-
it '
|
32
|
+
it 'does cache with Authorization request header and public response' do
|
33
|
+
respond_with 200, 'Cache-Control' => 'public', 'ETag' => '"FOO"'
|
34
|
+
get '/', 'HTTP_AUTHORIZATION' => 'basic foobarbaz'
|
35
|
+
|
36
|
+
app.should.be.called
|
37
|
+
response.should.be.ok
|
38
|
+
cache.should.a.performed :miss
|
39
|
+
cache.should.a.performed :fetch
|
40
|
+
cache.should.a.performed :store
|
41
|
+
response.headers.should.include 'Age'
|
42
|
+
response.headers['Cache-Control'].should.equal 'public'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not cache with Cookie header and non public response' do
|
46
|
+
respond_with 200, 'Etag' => '"FOO"'
|
47
|
+
get '/', 'HTTP_COOKIE' => 'foo=bar'
|
48
|
+
|
49
|
+
app.should.be.called
|
50
|
+
response.should.be.ok
|
51
|
+
response.headers['Cache-Control'].should.equal 'private'
|
52
|
+
cache.should.a.performed :miss
|
53
|
+
cache.should.a.performed :fetch
|
54
|
+
cache.should.a.not.performed :store
|
55
|
+
cache.should.a.performed :deliver
|
56
|
+
response.headers.should.not.include 'Age'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'does not cache requests with a Cookie header' do
|
29
60
|
respond_with 200
|
30
61
|
get '/', 'HTTP_COOKIE' => 'foo=bar'
|
31
62
|
|
32
63
|
response.should.be.ok
|
33
64
|
app.should.be.called
|
34
|
-
cache.should.a.performed :
|
65
|
+
cache.should.a.performed :miss
|
66
|
+
cache.should.a.performed :fetch
|
67
|
+
cache.should.a.performed :deliver
|
35
68
|
response.headers.should.not.include 'Age'
|
69
|
+
response.headers['Cache-Control'].should.equal 'private'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'responds with 304 when If-Modified-Since matches Last-Modified' do
|
73
|
+
timestamp = Time.now.httpdate
|
74
|
+
respond_with do |req,res|
|
75
|
+
res.status = 200
|
76
|
+
res['Last-Modified'] = timestamp
|
77
|
+
res['Content-Type'] = 'text/plain'
|
78
|
+
res.body = ['Hello World']
|
79
|
+
end
|
80
|
+
|
81
|
+
get '/',
|
82
|
+
'HTTP_IF_MODIFIED_SINCE' => timestamp
|
83
|
+
app.should.be.called
|
84
|
+
response.status.should.equal 304
|
85
|
+
response.headers.should.not.include 'Content-Length'
|
86
|
+
response.headers.should.not.include 'Content-Type'
|
87
|
+
response.body.should.empty
|
88
|
+
cache.should.a.performed :miss
|
89
|
+
cache.should.a.performed :store
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'responds with 304 when If-None-Match matches ETag' do
|
93
|
+
respond_with do |req,res|
|
94
|
+
res.status = 200
|
95
|
+
res['Etag'] = '12345'
|
96
|
+
res['Content-Type'] = 'text/plain'
|
97
|
+
res.body = ['Hello World']
|
98
|
+
end
|
99
|
+
|
100
|
+
get '/',
|
101
|
+
'HTTP_IF_NONE_MATCH' => '12345'
|
102
|
+
app.should.be.called
|
103
|
+
response.status.should.equal 304
|
104
|
+
response.headers.should.not.include 'Content-Length'
|
105
|
+
response.headers.should.not.include 'Content-Type'
|
106
|
+
response.headers.should.include 'Etag'
|
107
|
+
response.body.should.empty
|
108
|
+
cache.should.a.performed :miss
|
109
|
+
cache.should.a.performed :store
|
36
110
|
end
|
37
111
|
|
38
112
|
it 'caches requests when Cache-Control request header set to no-cache' do
|
@@ -41,7 +115,7 @@ describe 'Rack::Cache::Context' do
|
|
41
115
|
|
42
116
|
response.should.be.ok
|
43
117
|
cache.should.a.performed :store
|
44
|
-
response.headers.should.
|
118
|
+
response.headers.should.include 'Age'
|
45
119
|
end
|
46
120
|
|
47
121
|
it 'fetches response from backend when cache misses' do
|
@@ -51,7 +125,7 @@ describe 'Rack::Cache::Context' do
|
|
51
125
|
response.should.be.ok
|
52
126
|
cache.should.a.performed :miss
|
53
127
|
cache.should.a.performed :fetch
|
54
|
-
response.headers.should.
|
128
|
+
response.headers.should.include 'Age'
|
55
129
|
end
|
56
130
|
|
57
131
|
[(201..202),(204..206),(303..305),(400..403),(405..409),(411..417),(500..505)].each do |range|
|
@@ -61,7 +135,7 @@ describe 'Rack::Cache::Context' do
|
|
61
135
|
get '/'
|
62
136
|
|
63
137
|
cache.should.a.not.performed :store
|
64
|
-
response.status.should.
|
138
|
+
response.status.should.equal response_code
|
65
139
|
response.headers.should.not.include 'Age'
|
66
140
|
end
|
67
141
|
end
|
@@ -94,7 +168,7 @@ describe 'Rack::Cache::Context' do
|
|
94
168
|
|
95
169
|
response.should.be.ok
|
96
170
|
cache.should.a.performed :store
|
97
|
-
response.headers.should.
|
171
|
+
response.headers.should.include 'Age'
|
98
172
|
end
|
99
173
|
|
100
174
|
it 'caches responses with an Expiration header' do
|
@@ -102,13 +176,13 @@ describe 'Rack::Cache::Context' do
|
|
102
176
|
get '/'
|
103
177
|
|
104
178
|
response.should.be.ok
|
105
|
-
response.body.should.
|
179
|
+
response.body.should.equal 'Hello World'
|
106
180
|
response.headers.should.include 'Date'
|
107
|
-
response['Age'].should.be.nil
|
108
|
-
response['X-Content-Digest'].should.be.nil
|
181
|
+
response['Age'].should.not.be.nil
|
182
|
+
response['X-Content-Digest'].should.not.be.nil
|
109
183
|
cache.should.a.performed :miss
|
110
184
|
cache.should.a.performed :store
|
111
|
-
cache.metastore.to_hash.keys.length.should.
|
185
|
+
cache.metastore.to_hash.keys.length.should.equal 1
|
112
186
|
end
|
113
187
|
|
114
188
|
it 'caches responses with a max-age directive' do
|
@@ -116,13 +190,27 @@ describe 'Rack::Cache::Context' do
|
|
116
190
|
get '/'
|
117
191
|
|
118
192
|
response.should.be.ok
|
119
|
-
response.body.should.
|
193
|
+
response.body.should.equal 'Hello World'
|
120
194
|
response.headers.should.include 'Date'
|
121
|
-
response['Age'].should.be.nil
|
122
|
-
response['X-Content-Digest'].should.be.nil
|
195
|
+
response['Age'].should.not.be.nil
|
196
|
+
response['X-Content-Digest'].should.not.be.nil
|
123
197
|
cache.should.a.performed :miss
|
124
198
|
cache.should.a.performed :store
|
125
|
-
cache.metastore.to_hash.keys.length.should.
|
199
|
+
cache.metastore.to_hash.keys.length.should.equal 1
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'caches responses with a s-maxage directive' do
|
203
|
+
respond_with 200, 'Cache-Control' => 's-maxage=5'
|
204
|
+
get '/'
|
205
|
+
|
206
|
+
response.should.be.ok
|
207
|
+
response.body.should.equal 'Hello World'
|
208
|
+
response.headers.should.include 'Date'
|
209
|
+
response['Age'].should.not.be.nil
|
210
|
+
response['X-Content-Digest'].should.not.be.nil
|
211
|
+
cache.should.a.performed :miss
|
212
|
+
cache.should.a.performed :store
|
213
|
+
cache.metastore.to_hash.keys.length.should.equal 1
|
126
214
|
end
|
127
215
|
|
128
216
|
it 'caches responses with a Last-Modified validator but no freshness information' do
|
@@ -130,7 +218,7 @@ describe 'Rack::Cache::Context' do
|
|
130
218
|
get '/'
|
131
219
|
|
132
220
|
response.should.be.ok
|
133
|
-
response.body.should.
|
221
|
+
response.body.should.equal 'Hello World'
|
134
222
|
cache.should.a.performed :miss
|
135
223
|
cache.should.a.performed :store
|
136
224
|
end
|
@@ -140,7 +228,7 @@ describe 'Rack::Cache::Context' do
|
|
140
228
|
get '/'
|
141
229
|
|
142
230
|
response.should.be.ok
|
143
|
-
response.body.should.
|
231
|
+
response.body.should.equal 'Hello World'
|
144
232
|
cache.should.a.performed :miss
|
145
233
|
cache.should.a.performed :store
|
146
234
|
end
|
@@ -156,17 +244,17 @@ describe 'Rack::Cache::Context' do
|
|
156
244
|
response.headers.should.include 'Date'
|
157
245
|
cache.should.a.performed :miss
|
158
246
|
cache.should.a.performed :store
|
159
|
-
response.body.should.
|
247
|
+
response.body.should.equal 'Hello World'
|
160
248
|
|
161
249
|
get '/'
|
162
250
|
response.should.be.ok
|
163
251
|
app.should.not.be.called
|
164
|
-
response['Date'].should.
|
165
|
-
response['Age'].to_i.should.
|
252
|
+
response['Date'].should.equal responses.first['Date']
|
253
|
+
response['Age'].to_i.should.satisfy { |age| age > 0 }
|
166
254
|
response['X-Content-Digest'].should.not.be.nil
|
167
255
|
cache.should.a.performed :hit
|
168
256
|
cache.should.a.not.performed :fetch
|
169
|
-
response.body.should.
|
257
|
+
response.body.should.equal 'Hello World'
|
170
258
|
end
|
171
259
|
|
172
260
|
it 'hits cached response with max-age directive' do
|
@@ -180,17 +268,73 @@ describe 'Rack::Cache::Context' do
|
|
180
268
|
response.headers.should.include 'Date'
|
181
269
|
cache.should.a.performed :miss
|
182
270
|
cache.should.a.performed :store
|
183
|
-
response.body.should.
|
271
|
+
response.body.should.equal 'Hello World'
|
184
272
|
|
185
273
|
get '/'
|
186
274
|
response.should.be.ok
|
187
275
|
app.should.not.be.called
|
188
|
-
response['Date'].should.
|
189
|
-
response['Age'].to_i.should.
|
276
|
+
response['Date'].should.equal responses.first['Date']
|
277
|
+
response['Age'].to_i.should.satisfy { |age| age > 0 }
|
190
278
|
response['X-Content-Digest'].should.not.be.nil
|
191
279
|
cache.should.a.performed :hit
|
192
280
|
cache.should.a.not.performed :fetch
|
193
|
-
response.body.should.
|
281
|
+
response.body.should.equal 'Hello World'
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'hits cached response with s-maxage directive' do
|
285
|
+
respond_with 200,
|
286
|
+
'Date' => (Time.now - 5).httpdate,
|
287
|
+
'Cache-Control' => 's-maxage=10, max-age=0'
|
288
|
+
|
289
|
+
get '/'
|
290
|
+
app.should.be.called
|
291
|
+
response.should.be.ok
|
292
|
+
response.headers.should.include 'Date'
|
293
|
+
cache.should.a.performed :miss
|
294
|
+
cache.should.a.performed :store
|
295
|
+
response.body.should.equal 'Hello World'
|
296
|
+
|
297
|
+
get '/'
|
298
|
+
response.should.be.ok
|
299
|
+
app.should.not.be.called
|
300
|
+
response['Date'].should.equal responses.first['Date']
|
301
|
+
response['Age'].to_i.should.satisfy { |age| age > 0 }
|
302
|
+
response['X-Content-Digest'].should.not.be.nil
|
303
|
+
cache.should.a.performed :hit
|
304
|
+
cache.should.a.not.performed :fetch
|
305
|
+
response.body.should.equal 'Hello World'
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'assigns default_ttl when response has no freshness information' do
|
309
|
+
respond_with 200
|
310
|
+
|
311
|
+
get '/', 'rack-cache.default_ttl' => 10
|
312
|
+
app.should.be.called
|
313
|
+
response.should.be.ok
|
314
|
+
cache.should.a.performed :miss
|
315
|
+
cache.should.a.performed :store
|
316
|
+
response.body.should.equal 'Hello World'
|
317
|
+
response['Cache-Control'].should.include 's-maxage=10'
|
318
|
+
|
319
|
+
get '/', 'rack-cache.default_ttl' => 10
|
320
|
+
response.should.be.ok
|
321
|
+
app.should.not.be.called
|
322
|
+
cache.should.a.performed :hit
|
323
|
+
cache.should.a.not.performed :fetch
|
324
|
+
response.body.should.equal 'Hello World'
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'does not assign default_ttl when response has must-revalidate directive' do
|
328
|
+
respond_with 200,
|
329
|
+
'Cache-Control' => 'must-revalidate'
|
330
|
+
|
331
|
+
get '/', 'rack-cache.default_ttl' => 10
|
332
|
+
app.should.be.called
|
333
|
+
response.should.be.ok
|
334
|
+
cache.should.a.performed :miss
|
335
|
+
cache.should.a.not.performed :store
|
336
|
+
response['Cache-Control'].should.not.include 's-maxage'
|
337
|
+
response.body.should.equal 'Hello World'
|
194
338
|
end
|
195
339
|
|
196
340
|
it 'fetches full response when cache stale and no validators present' do
|
@@ -201,27 +345,27 @@ describe 'Rack::Cache::Context' do
|
|
201
345
|
app.should.be.called
|
202
346
|
response.should.be.ok
|
203
347
|
response.headers.should.include 'Date'
|
204
|
-
response.headers.should.
|
205
|
-
response
|
348
|
+
response.headers.should.include 'X-Content-Digest'
|
349
|
+
response.headers.should.include 'Age'
|
206
350
|
cache.should.a.performed :miss
|
207
351
|
cache.should.a.performed :store
|
208
|
-
response.body.should.
|
352
|
+
response.body.should.equal 'Hello World'
|
209
353
|
|
210
354
|
# go in and play around with the cached metadata directly ...
|
211
|
-
cache.metastore.to_hash.values.length.should.
|
355
|
+
cache.metastore.to_hash.values.length.should.equal 1
|
212
356
|
cache.metastore.to_hash.values.first.first[1]['Expires'] = Time.now.httpdate
|
213
357
|
|
214
358
|
# build subsequent request; should be found but miss due to freshness
|
215
359
|
get '/'
|
216
360
|
app.should.be.called
|
217
361
|
response.should.be.ok
|
218
|
-
response['Age'].to_i.should.
|
219
|
-
response
|
362
|
+
response['Age'].to_i.should.equal 0
|
363
|
+
response.headers.should.include 'X-Content-Digest'
|
220
364
|
cache.should.a.not.performed :hit
|
221
365
|
cache.should.a.not.performed :miss
|
222
366
|
cache.should.a.performed :fetch
|
223
367
|
cache.should.a.performed :store
|
224
|
-
response.body.should.
|
368
|
+
response.body.should.equal 'Hello World'
|
225
369
|
end
|
226
370
|
|
227
371
|
it 'validates cached responses with Last-Modified and no freshness information' do
|
@@ -239,8 +383,8 @@ describe 'Rack::Cache::Context' do
|
|
239
383
|
app.should.be.called
|
240
384
|
response.should.be.ok
|
241
385
|
response.headers.should.include 'Last-Modified'
|
242
|
-
response.headers.should.
|
243
|
-
response.body.should.
|
386
|
+
response.headers.should.include 'X-Content-Digest'
|
387
|
+
response.body.should.equal 'Hello World'
|
244
388
|
cache.should.a.performed :miss
|
245
389
|
cache.should.a.performed :store
|
246
390
|
|
@@ -250,9 +394,9 @@ describe 'Rack::Cache::Context' do
|
|
250
394
|
response.should.be.ok
|
251
395
|
response.headers.should.include 'Last-Modified'
|
252
396
|
response.headers.should.include 'X-Content-Digest'
|
253
|
-
response['Age'].to_i.should.
|
254
|
-
response['X-Origin-Status'].should.
|
255
|
-
response.body.should.
|
397
|
+
response['Age'].to_i.should.equal 0
|
398
|
+
response['X-Origin-Status'].should.equal '304'
|
399
|
+
response.body.should.equal 'Hello World'
|
256
400
|
cache.should.a.not.performed :miss
|
257
401
|
cache.should.a.performed :fetch
|
258
402
|
cache.should.a.performed :store
|
@@ -273,8 +417,8 @@ describe 'Rack::Cache::Context' do
|
|
273
417
|
app.should.be.called
|
274
418
|
response.should.be.ok
|
275
419
|
response.headers.should.include 'Etag'
|
276
|
-
response.headers.should.
|
277
|
-
response.body.should.
|
420
|
+
response.headers.should.include 'X-Content-Digest'
|
421
|
+
response.body.should.equal 'Hello World'
|
278
422
|
cache.should.a.performed :miss
|
279
423
|
cache.should.a.performed :store
|
280
424
|
|
@@ -284,9 +428,9 @@ describe 'Rack::Cache::Context' do
|
|
284
428
|
response.should.be.ok
|
285
429
|
response.headers.should.include 'Etag'
|
286
430
|
response.headers.should.include 'X-Content-Digest'
|
287
|
-
response['Age'].to_i.should.
|
288
|
-
response['X-Origin-Status'].should.
|
289
|
-
response.body.should.
|
431
|
+
response['Age'].to_i.should.equal 0
|
432
|
+
response['X-Origin-Status'].should.equal '304'
|
433
|
+
response.body.should.equal 'Hello World'
|
290
434
|
cache.should.a.not.performed :miss
|
291
435
|
cache.should.a.performed :fetch
|
292
436
|
cache.should.a.performed :store
|
@@ -308,22 +452,58 @@ describe 'Rack::Cache::Context' do
|
|
308
452
|
|
309
453
|
# first request should fetch from backend and store in cache
|
310
454
|
get '/'
|
311
|
-
response.status.should.
|
312
|
-
response.body.should.
|
455
|
+
response.status.should.equal 200
|
456
|
+
response.body.should.equal 'first response'
|
313
457
|
|
314
458
|
# second request is validated, is invalid, and replaces cached entry
|
315
459
|
get '/'
|
316
|
-
response.status.should.
|
317
|
-
response.body.should.
|
460
|
+
response.status.should.equal 200
|
461
|
+
response.body.should.equal 'second response'
|
318
462
|
|
319
463
|
# third respone is validated, valid, and returns cached entry
|
320
464
|
get '/'
|
321
|
-
response.status.should.
|
322
|
-
response.body.should.
|
465
|
+
response.status.should.equal 200
|
466
|
+
response.body.should.equal 'second response'
|
467
|
+
|
468
|
+
count.should.equal 3
|
469
|
+
end
|
470
|
+
|
471
|
+
it 'passes HEAD requests through directly on pass' do
|
472
|
+
respond_with do |req,res|
|
473
|
+
res.status = 200
|
474
|
+
res.body = []
|
475
|
+
req.request_method.should.equal 'HEAD'
|
476
|
+
end
|
477
|
+
|
478
|
+
cache_config do
|
479
|
+
on(:receive) { pass! }
|
480
|
+
end
|
481
|
+
|
482
|
+
head '/'
|
483
|
+
app.should.be.called
|
484
|
+
response.body.should.equal ''
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'uses cache to respond to HEAD requests when fresh' do
|
488
|
+
respond_with do |req,res|
|
489
|
+
res['Cache-Control'] = 'max-age=10'
|
490
|
+
res.body = ['Hello World']
|
491
|
+
req.request_method.should.not.equal 'HEAD'
|
492
|
+
end
|
493
|
+
|
494
|
+
get '/'
|
495
|
+
app.should.be.called
|
496
|
+
response.status.should.equal 200
|
497
|
+
response.body.should.equal 'Hello World'
|
323
498
|
|
324
|
-
|
499
|
+
head '/'
|
500
|
+
app.should.not.be.called
|
501
|
+
response.status.should.equal 200
|
502
|
+
response.body.should.equal ''
|
503
|
+
response['Content-Length'].should.equal 'Hello World'.length.to_s
|
325
504
|
end
|
326
505
|
|
506
|
+
|
327
507
|
describe 'with responses that include a Vary header' do
|
328
508
|
before(:each) do
|
329
509
|
count = 0
|
@@ -340,7 +520,7 @@ describe 'Rack::Cache::Context' do
|
|
340
520
|
'HTTP_ACCEPT' => 'text/html',
|
341
521
|
'HTTP_USER_AGENT' => 'Bob/1.0'
|
342
522
|
response.should.be.ok
|
343
|
-
response.body.should.
|
523
|
+
response.body.should.equal 'Bob/1.0'
|
344
524
|
cache.should.a.performed :miss
|
345
525
|
cache.should.a.performed :store
|
346
526
|
|
@@ -348,7 +528,7 @@ describe 'Rack::Cache::Context' do
|
|
348
528
|
'HTTP_ACCEPT' => 'text/html',
|
349
529
|
'HTTP_USER_AGENT' => 'Bob/1.0'
|
350
530
|
response.should.be.ok
|
351
|
-
response.body.should.
|
531
|
+
response.body.should.equal 'Bob/1.0'
|
352
532
|
cache.should.a.performed :hit
|
353
533
|
cache.should.a.not.performed :fetch
|
354
534
|
response.headers.should.include 'X-Content-Digest'
|
@@ -359,36 +539,36 @@ describe 'Rack::Cache::Context' do
|
|
359
539
|
'HTTP_ACCEPT' => 'text/html',
|
360
540
|
'HTTP_USER_AGENT' => 'Bob/1.0'
|
361
541
|
response.should.be.ok
|
362
|
-
response.body.should.
|
363
|
-
response['X-Response-Count'].should.
|
542
|
+
response.body.should.equal 'Bob/1.0'
|
543
|
+
response['X-Response-Count'].should.equal '1'
|
364
544
|
|
365
545
|
get '/',
|
366
546
|
'HTTP_ACCEPT' => 'text/html',
|
367
547
|
'HTTP_USER_AGENT' => 'Bob/2.0'
|
368
548
|
cache.should.a.performed :miss
|
369
549
|
cache.should.a.performed :store
|
370
|
-
response.body.should.
|
371
|
-
response['X-Response-Count'].should.
|
550
|
+
response.body.should.equal 'Bob/2.0'
|
551
|
+
response['X-Response-Count'].should.equal '2'
|
372
552
|
|
373
553
|
get '/',
|
374
554
|
'HTTP_ACCEPT' => 'text/html',
|
375
555
|
'HTTP_USER_AGENT' => 'Bob/1.0'
|
376
556
|
cache.should.a.performed :hit
|
377
|
-
response.body.should.
|
378
|
-
response['X-Response-Count'].should.
|
557
|
+
response.body.should.equal 'Bob/1.0'
|
558
|
+
response['X-Response-Count'].should.equal '1'
|
379
559
|
|
380
560
|
get '/',
|
381
561
|
'HTTP_ACCEPT' => 'text/html',
|
382
562
|
'HTTP_USER_AGENT' => 'Bob/2.0'
|
383
563
|
cache.should.a.performed :hit
|
384
|
-
response.body.should.
|
385
|
-
response['X-Response-Count'].should.
|
564
|
+
response.body.should.equal 'Bob/2.0'
|
565
|
+
response['X-Response-Count'].should.equal '2'
|
386
566
|
|
387
567
|
get '/',
|
388
568
|
'HTTP_USER_AGENT' => 'Bob/2.0'
|
389
569
|
cache.should.a.performed :miss
|
390
|
-
response.body.should.
|
391
|
-
response['X-Response-Count'].should.
|
570
|
+
response.body.should.equal 'Bob/2.0'
|
571
|
+
response['X-Response-Count'].should.equal '3'
|
392
572
|
end
|
393
573
|
end
|
394
574
|
|
@@ -401,7 +581,7 @@ describe 'Rack::Cache::Context' do
|
|
401
581
|
on(:receive) { error! }
|
402
582
|
end
|
403
583
|
get '/'
|
404
|
-
response.status.should.
|
584
|
+
response.status.should.equal 500
|
405
585
|
response.body.should.be.empty
|
406
586
|
cache.should.a.performed :error
|
407
587
|
end
|
@@ -411,7 +591,7 @@ describe 'Rack::Cache::Context' do
|
|
411
591
|
on(:receive) { error! 505 }
|
412
592
|
end
|
413
593
|
get '/'
|
414
|
-
response.status.should.
|
594
|
+
response.status.should.equal 505
|
415
595
|
end
|
416
596
|
|
417
597
|
it 'sets the status and headers with args: status, Hash' do
|
@@ -419,8 +599,8 @@ describe 'Rack::Cache::Context' do
|
|
419
599
|
on(:receive) { error! 504, 'Content-Type' => 'application/x-foo' }
|
420
600
|
end
|
421
601
|
get '/'
|
422
|
-
response.status.should.
|
423
|
-
response['Content-Type'].should.
|
602
|
+
response.status.should.equal 504
|
603
|
+
response['Content-Type'].should.equal 'application/x-foo'
|
424
604
|
response.body.should.be.empty
|
425
605
|
end
|
426
606
|
|
@@ -429,8 +609,8 @@ describe 'Rack::Cache::Context' do
|
|
429
609
|
on(:receive) { error! 503, 'foo bar baz' }
|
430
610
|
end
|
431
611
|
get '/'
|
432
|
-
response.status.should.
|
433
|
-
response.body.should.
|
612
|
+
response.status.should.equal 503
|
613
|
+
response.body.should.equal 'foo bar baz'
|
434
614
|
end
|
435
615
|
|
436
616
|
it 'sets the status and body with args: status, Array' do
|
@@ -438,8 +618,8 @@ describe 'Rack::Cache::Context' do
|
|
438
618
|
on(:receive) { error! 503, ['foo bar baz'] }
|
439
619
|
end
|
440
620
|
get '/'
|
441
|
-
response.status.should.
|
442
|
-
response.body.should.
|
621
|
+
response.status.should.equal 503
|
622
|
+
response.body.should.equal 'foo bar baz'
|
443
623
|
end
|
444
624
|
|
445
625
|
it 'fires the error event before finishing' do
|
@@ -448,16 +628,16 @@ describe 'Rack::Cache::Context' do
|
|
448
628
|
on(:receive) { error! }
|
449
629
|
on(:error) {
|
450
630
|
fired = true
|
451
|
-
response.status.should.
|
631
|
+
response.status.should.equal 500
|
452
632
|
response['Content-Type'] = 'application/x-foo'
|
453
633
|
response.body = ['overridden response body']
|
454
634
|
}
|
455
635
|
end
|
456
636
|
get '/'
|
457
637
|
fired.should.be true
|
458
|
-
response.status.should.
|
459
|
-
response.body.should.
|
460
|
-
response['Content-Type'].should.
|
638
|
+
response.status.should.equal 500
|
639
|
+
response.body.should.equal 'overridden response body'
|
640
|
+
response['Content-Type'].should.equal 'application/x-foo'
|
461
641
|
end
|
462
642
|
|
463
643
|
end
|