rack 1.6.13 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (144) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +17 -25
  5. data/Rakefile +6 -14
  6. data/SPEC +8 -9
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack/auth/abstract/request.rb +5 -1
  11. data/lib/rack/auth/digest/params.rb +2 -3
  12. data/lib/rack/auth/digest/request.rb +1 -1
  13. data/lib/rack/body_proxy.rb +14 -9
  14. data/lib/rack/builder.rb +3 -3
  15. data/lib/rack/chunked.rb +5 -5
  16. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  17. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  18. data/lib/rack/content_length.rb +2 -2
  19. data/lib/rack/deflater.rb +4 -4
  20. data/lib/rack/directory.rb +66 -54
  21. data/lib/rack/etag.rb +4 -3
  22. data/lib/rack/events.rb +154 -0
  23. data/lib/rack/file.rb +63 -39
  24. data/lib/rack/handler/cgi.rb +15 -16
  25. data/lib/rack/handler/fastcgi.rb +13 -14
  26. data/lib/rack/handler/lsws.rb +11 -11
  27. data/lib/rack/handler/scgi.rb +15 -15
  28. data/lib/rack/handler/thin.rb +3 -0
  29. data/lib/rack/handler/webrick.rb +22 -24
  30. data/lib/rack/handler.rb +3 -25
  31. data/lib/rack/head.rb +15 -17
  32. data/lib/rack/lint.rb +38 -38
  33. data/lib/rack/lobster.rb +1 -1
  34. data/lib/rack/lock.rb +6 -10
  35. data/lib/rack/logger.rb +2 -2
  36. data/lib/rack/media_type.rb +38 -0
  37. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  38. data/lib/rack/mime.rb +18 -5
  39. data/lib/rack/mock.rb +35 -53
  40. data/lib/rack/multipart/generator.rb +5 -5
  41. data/lib/rack/multipart/parser.rb +272 -158
  42. data/lib/rack/multipart/uploaded_file.rb +1 -2
  43. data/lib/rack/multipart.rb +35 -6
  44. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  45. data/lib/rack/query_parser.rb +192 -0
  46. data/lib/rack/recursive.rb +8 -8
  47. data/lib/rack/request.rb +383 -307
  48. data/lib/rack/response.rb +129 -56
  49. data/lib/rack/rewindable_input.rb +1 -12
  50. data/lib/rack/runtime.rb +10 -18
  51. data/lib/rack/sendfile.rb +5 -7
  52. data/lib/rack/server.rb +31 -25
  53. data/lib/rack/session/abstract/id.rb +95 -135
  54. data/lib/rack/session/cookie.rb +26 -28
  55. data/lib/rack/session/memcache.rb +8 -14
  56. data/lib/rack/session/pool.rb +14 -21
  57. data/lib/rack/show_exceptions.rb +386 -0
  58. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  59. data/lib/rack/static.rb +30 -5
  60. data/lib/rack/tempfile_reaper.rb +2 -2
  61. data/lib/rack/urlmap.rb +15 -14
  62. data/lib/rack/utils.rb +135 -210
  63. data/lib/rack.rb +70 -21
  64. data/rack.gemspec +7 -5
  65. data/test/builder/an_underscore_app.rb +5 -0
  66. data/test/builder/options.ru +1 -1
  67. data/test/cgi/test.fcgi +1 -0
  68. data/test/cgi/test.gz +0 -0
  69. data/test/helper.rb +34 -0
  70. data/test/multipart/filename_with_encoded_words +7 -0
  71. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +36 -34
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +66 -40
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +107 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +162 -197
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +69 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/spec_method_override.rb +83 -0
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +196 -151
  104. data/test/spec_multipart.rb +317 -201
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +768 -607
  108. data/test/spec_response.rb +214 -111
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +28 -0
  115. data/test/spec_session_cookie.rb +97 -65
  116. data/test/spec_session_memcache.rb +63 -101
  117. data/test/spec_session_pool.rb +48 -84
  118. data/test/spec_show_exceptions.rb +80 -0
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +91 -67
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +103 -69
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_methodoverride.rb +0 -111
  142. data/test/spec_mongrel.rb +0 -182
  143. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  144. data/test/spec_showexceptions.rb +0 -98
@@ -1,3 +1,4 @@
1
+ require 'minitest/autorun'
1
2
  require 'stringio'
2
3
  require 'time' # for Time#httpdate
3
4
  require 'rack/deflater'
@@ -32,7 +33,7 @@ describe Rack::Deflater do
32
33
  # [options] hash of request options, i.e.
33
34
  # 'app_status' - what status dummy app should return (may be changed by deflater at some point)
34
35
  # 'app_body' - what body dummy app should return (may be changed by deflater at some point)
35
- # 'request_headers' - extra reqest headers to be sent
36
+ # 'request_headers' - extra request headers to be sent
36
37
  # 'response_headers' - extra response headers to be returned
37
38
  # 'deflater_options' - options passed to deflater middleware
38
39
  # [block] useful for doing some extra verification
@@ -52,7 +53,7 @@ describe Rack::Deflater do
52
53
  )
53
54
 
54
55
  # verify status
55
- status.should.equal(expected_status)
56
+ status.must_equal expected_status
56
57
 
57
58
  # verify body
58
59
  unless options['skip_body_verify']
@@ -73,19 +74,19 @@ describe Rack::Deflater do
73
74
  body_text
74
75
  end
75
76
 
76
- deflated_body.should.equal(expected_body)
77
+ deflated_body.must_equal expected_body
77
78
  end
78
79
 
79
80
  # yield full response verification
80
81
  yield(status, headers, body) if block_given?
81
82
  end
82
83
 
83
- should 'be able to deflate bodies that respond to each' do
84
+ it 'be able to deflate bodies that respond to each' do
84
85
  app_body = Object.new
85
86
  class << app_body; def each; yield('foo'); yield('bar'); end; end
86
87
 
87
88
  verify(200, 'foobar', 'deflate', { 'app_body' => app_body }) do |status, headers, body|
88
- headers.should.equal({
89
+ headers.must_equal({
89
90
  'Content-Encoding' => 'deflate',
90
91
  'Vary' => 'Accept-Encoding',
91
92
  'Content-Type' => 'text/plain'
@@ -93,12 +94,12 @@ describe Rack::Deflater do
93
94
  end
94
95
  end
95
96
 
96
- should 'flush deflated chunks to the client as they become ready' do
97
+ it 'flush deflated chunks to the client as they become ready' do
97
98
  app_body = Object.new
98
99
  class << app_body; def each; yield('foo'); yield('bar'); end; end
99
100
 
100
101
  verify(200, app_body, 'deflate', { 'skip_body_verify' => true }) do |status, headers, body|
101
- headers.should.equal({
102
+ headers.must_equal({
102
103
  'Content-Encoding' => 'deflate',
103
104
  'Vary' => 'Accept-Encoding',
104
105
  'Content-Type' => 'text/plain'
@@ -109,14 +110,39 @@ describe Rack::Deflater do
109
110
  body.each { |part| buf << inflater.inflate(part) }
110
111
  buf << inflater.finish
111
112
 
112
- buf.delete_if { |part| part.empty? }.join.should.equal('foobar')
113
+ buf.delete_if { |part| part.empty? }.join.must_equal 'foobar'
114
+ end
115
+ end
116
+
117
+ it 'does not raise when a client aborts reading' do
118
+ app_body = Object.new
119
+ class << app_body; def each; yield('foo'); yield('bar'); end; end
120
+ opts = { 'skip_body_verify' => true }
121
+ verify(200, app_body, 'deflate', opts) do |status, headers, body|
122
+ headers.must_equal({
123
+ 'Content-Encoding' => 'deflate',
124
+ 'Vary' => 'Accept-Encoding',
125
+ 'Content-Type' => 'text/plain'
126
+ })
127
+
128
+ buf = []
129
+ inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
130
+ FakeDisconnect = Class.new(RuntimeError)
131
+ assert_raises(FakeDisconnect, "not Zlib::DataError not raised") do
132
+ body.each do |part|
133
+ buf << inflater.inflate(part)
134
+ raise FakeDisconnect
135
+ end
136
+ end
137
+ assert_raises(Zlib::BufError) { inflater.finish }
138
+ buf.must_equal(%w(foo))
113
139
  end
114
140
  end
115
141
 
116
142
  # TODO: This is really just a special case of the above...
117
- should 'be able to deflate String bodies' do
143
+ it 'be able to deflate String bodies' do
118
144
  verify(200, 'Hello world!', 'deflate') do |status, headers, body|
119
- headers.should.equal({
145
+ headers.must_equal({
120
146
  'Content-Encoding' => 'deflate',
121
147
  'Vary' => 'Accept-Encoding',
122
148
  'Content-Type' => 'text/plain'
@@ -124,12 +150,12 @@ describe Rack::Deflater do
124
150
  end
125
151
  end
126
152
 
127
- should 'be able to gzip bodies that respond to each' do
153
+ it 'be able to gzip bodies that respond to each' do
128
154
  app_body = Object.new
129
155
  class << app_body; def each; yield('foo'); yield('bar'); end; end
130
156
 
131
157
  verify(200, 'foobar', 'gzip', { 'app_body' => app_body }) do |status, headers, body|
132
- headers.should.equal({
158
+ headers.must_equal({
133
159
  'Content-Encoding' => 'gzip',
134
160
  'Vary' => 'Accept-Encoding',
135
161
  'Content-Type' => 'text/plain'
@@ -137,12 +163,12 @@ describe Rack::Deflater do
137
163
  end
138
164
  end
139
165
 
140
- should 'flush gzipped chunks to the client as they become ready' do
166
+ it 'flush gzipped chunks to the client as they become ready' do
141
167
  app_body = Object.new
142
168
  class << app_body; def each; yield('foo'); yield('bar'); end; end
143
169
 
144
170
  verify(200, app_body, 'gzip', { 'skip_body_verify' => true }) do |status, headers, body|
145
- headers.should.equal({
171
+ headers.must_equal({
146
172
  'Content-Encoding' => 'gzip',
147
173
  'Vary' => 'Accept-Encoding',
148
174
  'Content-Type' => 'text/plain'
@@ -153,26 +179,26 @@ describe Rack::Deflater do
153
179
  body.each { |part| buf << inflater.inflate(part) }
154
180
  buf << inflater.finish
155
181
 
156
- buf.delete_if { |part| part.empty? }.join.should.equal('foobar')
182
+ buf.delete_if { |part| part.empty? }.join.must_equal 'foobar'
157
183
  end
158
184
  end
159
185
 
160
- should 'be able to fallback to no deflation' do
186
+ it 'be able to fallback to no deflation' do
161
187
  verify(200, 'Hello world!', 'superzip') do |status, headers, body|
162
- headers.should.equal({
188
+ headers.must_equal({
163
189
  'Vary' => 'Accept-Encoding',
164
190
  'Content-Type' => 'text/plain'
165
191
  })
166
192
  end
167
193
  end
168
194
 
169
- should 'be able to skip when there is no response entity body' do
195
+ it 'be able to skip when there is no response entity body' do
170
196
  verify(304, '', { 'gzip' => nil }, { 'app_body' => [] }) do |status, headers, body|
171
- headers.should.equal({})
197
+ headers.must_equal({})
172
198
  end
173
199
  end
174
200
 
175
- should 'handle the lack of an acceptable encoding' do
201
+ it 'handle the lack of an acceptable encoding' do
176
202
  app_body = 'Hello world!'
177
203
  not_found_body1 = 'An acceptable encoding for the requested resource / could not be found.'
178
204
  not_found_body2 = 'An acceptable encoding for the requested resource /foo/bar could not be found.'
@@ -192,21 +218,21 @@ describe Rack::Deflater do
192
218
  }
193
219
 
194
220
  verify(406, not_found_body1, 'identity;q=0', options1) do |status, headers, body|
195
- headers.should.equal({
221
+ headers.must_equal({
196
222
  'Content-Type' => 'text/plain',
197
223
  'Content-Length' => not_found_body1.length.to_s
198
224
  })
199
225
  end
200
226
 
201
227
  verify(406, not_found_body2, 'identity;q=0', options2) do |status, headers, body|
202
- headers.should.equal({
228
+ headers.must_equal({
203
229
  'Content-Type' => 'text/plain',
204
230
  'Content-Length' => not_found_body2.length.to_s
205
231
  })
206
232
  end
207
233
  end
208
234
 
209
- should 'handle gzip response with Last-Modified header' do
235
+ it 'handle gzip response with Last-Modified header' do
210
236
  last_modified = Time.now.httpdate
211
237
  options = {
212
238
  'response_headers' => {
@@ -216,7 +242,7 @@ describe Rack::Deflater do
216
242
  }
217
243
 
218
244
  verify(200, 'Hello World!', 'gzip', options) do |status, headers, body|
219
- headers.should.equal({
245
+ headers.must_equal({
220
246
  'Content-Encoding' => 'gzip',
221
247
  'Vary' => 'Accept-Encoding',
222
248
  'Last-Modified' => last_modified,
@@ -225,7 +251,7 @@ describe Rack::Deflater do
225
251
  end
226
252
  end
227
253
 
228
- should 'do nothing when no-transform Cache-Control directive present' do
254
+ it 'do nothing when no-transform Cache-Control directive present' do
229
255
  options = {
230
256
  'response_headers' => {
231
257
  'Content-Type' => 'text/plain',
@@ -233,11 +259,11 @@ describe Rack::Deflater do
233
259
  }
234
260
  }
235
261
  verify(200, 'Hello World!', { 'gzip' => nil }, options) do |status, headers, body|
236
- headers.should.not.include 'Content-Encoding'
262
+ headers.wont_include 'Content-Encoding'
237
263
  end
238
264
  end
239
265
 
240
- should 'do nothing when Content-Encoding already present' do
266
+ it 'do nothing when Content-Encoding already present' do
241
267
  options = {
242
268
  'response_headers' => {
243
269
  'Content-Type' => 'text/plain',
@@ -247,7 +273,7 @@ describe Rack::Deflater do
247
273
  verify(200, 'Hello World!', { 'gzip' => nil }, options)
248
274
  end
249
275
 
250
- should 'deflate when Content-Encoding is identity' do
276
+ it 'deflate when Content-Encoding is identity' do
251
277
  options = {
252
278
  'response_headers' => {
253
279
  'Content-Type' => 'text/plain',
@@ -257,7 +283,7 @@ describe Rack::Deflater do
257
283
  verify(200, 'Hello World!', 'deflate', options)
258
284
  end
259
285
 
260
- should "deflate if content-type matches :include" do
286
+ it "deflate if content-type matches :include" do
261
287
  options = {
262
288
  'response_headers' => {
263
289
  'Content-Type' => 'text/plain'
@@ -269,7 +295,7 @@ describe Rack::Deflater do
269
295
  verify(200, 'Hello World!', 'gzip', options)
270
296
  end
271
297
 
272
- should "deflate if content-type is included it :include" do
298
+ it "deflate if content-type is included it :include" do
273
299
  options = {
274
300
  'response_headers' => {
275
301
  'Content-Type' => 'text/plain; charset=us-ascii'
@@ -281,7 +307,7 @@ describe Rack::Deflater do
281
307
  verify(200, 'Hello World!', 'gzip', options)
282
308
  end
283
309
 
284
- should "not deflate if content-type is not set but given in :include" do
310
+ it "not deflate if content-type is not set but given in :include" do
285
311
  options = {
286
312
  'deflater_options' => {
287
313
  :include => %w(text/plain)
@@ -290,7 +316,7 @@ describe Rack::Deflater do
290
316
  verify(304, 'Hello World!', { 'gzip' => nil }, options)
291
317
  end
292
318
 
293
- should "not deflate if content-type do not match :include" do
319
+ it "not deflate if content-type do not match :include" do
294
320
  options = {
295
321
  'response_headers' => {
296
322
  'Content-Type' => 'text/plain'
@@ -302,7 +328,7 @@ describe Rack::Deflater do
302
328
  verify(200, 'Hello World!', { 'gzip' => nil }, options)
303
329
  end
304
330
 
305
- should "deflate response if :if lambda evaluates to true" do
331
+ it "deflate response if :if lambda evaluates to true" do
306
332
  options = {
307
333
  'deflater_options' => {
308
334
  :if => lambda { |env, status, headers, body| true }
@@ -311,7 +337,7 @@ describe Rack::Deflater do
311
337
  verify(200, 'Hello World!', 'deflate', options)
312
338
  end
313
339
 
314
- should "not deflate if :if lambda evaluates to false" do
340
+ it "not deflate if :if lambda evaluates to false" do
315
341
  options = {
316
342
  'deflater_options' => {
317
343
  :if => lambda { |env, status, headers, body| false }
@@ -320,20 +346,20 @@ describe Rack::Deflater do
320
346
  verify(200, 'Hello World!', { 'gzip' => nil }, options)
321
347
  end
322
348
 
323
- should "check for Content-Length via :if" do
324
- body = 'Hello World!'
325
- body_len = body.length
349
+ it "check for Content-Length via :if" do
350
+ response = 'Hello World!'
351
+ response_len = response.length
326
352
  options = {
327
353
  'response_headers' => {
328
- 'Content-Length' => body_len.to_s
354
+ 'Content-Length' => response_len.to_s
329
355
  },
330
356
  'deflater_options' => {
331
357
  :if => lambda { |env, status, headers, body|
332
- headers['Content-Length'].to_i >= body_len
358
+ headers['Content-Length'].to_i >= response_len
333
359
  }
334
360
  }
335
361
  }
336
362
 
337
- verify(200, body, 'gzip', options)
363
+ verify(200, response, 'gzip', options)
338
364
  end
339
365
  end
@@ -1,77 +1,129 @@
1
+ require 'minitest/autorun'
1
2
  require 'rack/directory'
2
3
  require 'rack/lint'
3
4
  require 'rack/mock'
5
+ require 'tempfile'
6
+ require 'fileutils'
4
7
 
5
8
  describe Rack::Directory do
6
9
  DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
7
10
  FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] }
8
- app = Rack::Lint.new(Rack::Directory.new(DOCROOT, FILE_CATCH))
9
11
 
10
- should "serve directory indices" do
12
+ attr_reader :app
13
+
14
+ def setup
15
+ @app = Rack::Lint.new(Rack::Directory.new(DOCROOT, FILE_CATCH))
16
+ end
17
+
18
+ it 'serves directories with + in the name' do
19
+ Dir.mktmpdir do |dir|
20
+ plus_dir = "foo+bar"
21
+ full_dir = File.join(dir, plus_dir)
22
+ FileUtils.mkdir full_dir
23
+ FileUtils.touch File.join(full_dir, "omg.txt")
24
+ app = Rack::Directory.new(dir, FILE_CATCH)
25
+ env = Rack::MockRequest.env_for("/#{plus_dir}/")
26
+ status,_,body = app.call env
27
+
28
+ assert_equal 200, status
29
+
30
+ str = ''
31
+ body.each { |x| str << x }
32
+ assert_match "foo+bar", str
33
+ end
34
+ end
35
+
36
+ it "serve directory indices" do
11
37
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
12
38
  get("/cgi/")
13
39
 
14
- res.should.be.ok
15
- res.should =~ /<html><head>/
40
+ res.must_be :ok?
41
+ assert_match(res, /<html><head>/)
16
42
  end
17
43
 
18
- should "pass to app if file found" do
44
+ it "pass to app if file found" do
19
45
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
20
46
  get("/cgi/test")
21
47
 
22
- res.should.be.ok
23
- res.should =~ /passed!/
48
+ res.must_be :ok?
49
+ assert_match(res, /passed!/)
24
50
  end
25
51
 
26
- should "serve uri with URL encoded filenames" do
52
+ it "serve uri with URL encoded filenames" do
27
53
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
28
54
  get("/%63%67%69/") # "/cgi/test"
29
55
 
30
- res.should.be.ok
31
- res.should =~ /<html><head>/
56
+ res.must_be :ok?
57
+ assert_match(res, /<html><head>/)
32
58
 
33
59
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
34
60
  get("/cgi/%74%65%73%74") # "/cgi/test"
35
61
 
36
- res.should.be.ok
37
- res.should =~ /passed!/
62
+ res.must_be :ok?
63
+ assert_match(res, /passed!/)
64
+ end
65
+
66
+ it "serve uri with URL encoded null byte (%00) in filenames" do
67
+ res = Rack::MockRequest.new(Rack::Lint.new(app))
68
+ .get("/cgi/test%00")
69
+
70
+ res.must_be :bad_request?
38
71
  end
39
72
 
40
- should "not allow directory traversal" do
73
+ it "not allow directory traversal" do
41
74
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
42
75
  get("/cgi/../test")
43
76
 
44
- res.should.be.forbidden
77
+ res.must_be :forbidden?
45
78
 
46
79
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
47
80
  get("/cgi/%2E%2E/test")
48
81
 
49
- res.should.be.forbidden
82
+ res.must_be :forbidden?
50
83
  end
51
84
 
52
- should "404 if it can't find the file" do
85
+ it "404 if it can't find the file" do
53
86
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
54
87
  get("/cgi/blubb")
55
88
 
56
- res.should.be.not_found
89
+ res.must_be :not_found?
57
90
  end
58
91
 
59
- should "uri escape path parts" do # #265, properly escape file names
92
+ it "uri escape path parts" do # #265, properly escape file names
60
93
  mr = Rack::MockRequest.new(Rack::Lint.new(app))
61
94
 
62
95
  res = mr.get("/cgi/test%2bdirectory")
63
96
 
64
- res.should.be.ok
65
- res.body.should =~ %r[/cgi/test%2Bdirectory/test%2Bfile]
97
+ res.must_be :ok?
98
+ res.body.must_match(%r[/cgi/test\+directory/test\+file])
66
99
 
67
100
  res = mr.get("/cgi/test%2bdirectory/test%2bfile")
68
- res.should.be.ok
101
+ res.must_be :ok?
102
+ end
103
+
104
+ it "correctly escape script name with spaces" do
105
+ Dir.mktmpdir do |dir|
106
+ space_dir = "foo bar"
107
+ full_dir = File.join(dir, space_dir)
108
+ FileUtils.mkdir full_dir
109
+ FileUtils.touch File.join(full_dir, "omg omg.txt")
110
+ app = Rack::Directory.new(dir, FILE_CATCH)
111
+ env = Rack::MockRequest.env_for(Rack::Utils.escape_path("/#{space_dir}/"))
112
+ status,_,body = app.call env
113
+
114
+ assert_equal 200, status
115
+
116
+ str = ''
117
+ body.each { |x| str << x }
118
+ assert_match "/foo%20bar/omg%20omg.txt", str
119
+ end
69
120
  end
70
121
 
71
- should "correctly escape script name" do
122
+ it "correctly escape script name" do
123
+ _app = app
72
124
  app2 = Rack::Builder.new do
73
125
  map '/script-path' do
74
- run app
126
+ run _app
75
127
  end
76
128
  end
77
129
 
@@ -79,10 +131,18 @@ describe Rack::Directory do
79
131
 
80
132
  res = mr.get("/script-path/cgi/test%2bdirectory")
81
133
 
82
- res.should.be.ok
83
- res.body.should =~ %r[/script-path/cgi/test%2Bdirectory/test%2Bfile]
134
+ res.must_be :ok?
135
+ res.body.must_match(%r[/script-path/cgi/test\+directory/test\+file])
136
+
137
+ res = mr.get("/script-path/cgi/test+directory/test+file")
138
+ res.must_be :ok?
139
+ end
140
+
141
+ it "return error when file not found for head request" do
142
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
143
+ head("/cgi/missing")
84
144
 
85
- res = mr.get("/script-path/cgi/test%2bdirectory/test%2bfile")
86
- res.should.be.ok
145
+ res.must_be :not_found?
146
+ res.body.must_be :empty?
87
147
  end
88
148
  end
data/test/spec_etag.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'minitest/autorun'
1
2
  require 'rack/etag'
2
3
  require 'rack/lint'
3
4
  require 'rack/mock'
@@ -7,101 +8,101 @@ describe Rack::ETag do
7
8
  def etag(app, *args)
8
9
  Rack::Lint.new Rack::ETag.new(app, *args)
9
10
  end
10
-
11
+
11
12
  def request
12
13
  Rack::MockRequest.env_for
13
14
  end
14
-
15
+
15
16
  def sendfile_body
16
17
  res = ['Hello World']
17
18
  def res.to_path ; "/tmp/hello.txt" ; end
18
19
  res
19
20
  end
20
21
 
21
- should "set ETag if none is set if status is 200" do
22
+ it "set ETag if none is set if status is 200" do
22
23
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
23
24
  response = etag(app).call(request)
24
- response[1]['ETag'].should.equal "W/\"65a8e27d8879283831b664bd8b7f0ad4\""
25
+ response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
25
26
  end
26
27
 
27
- should "set ETag if none is set if status is 201" do
28
+ it "set ETag if none is set if status is 201" do
28
29
  app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
29
30
  response = etag(app).call(request)
30
- response[1]['ETag'].should.equal "W/\"65a8e27d8879283831b664bd8b7f0ad4\""
31
+ response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
31
32
  end
32
33
 
33
- should "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
34
+ it "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
34
35
  app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
35
36
  response = etag(app).call(request)
36
- response[1]['Cache-Control'].should.equal 'max-age=0, private, must-revalidate'
37
+ response[1]['Cache-Control'].must_equal 'max-age=0, private, must-revalidate'
37
38
  end
38
39
 
39
- should "set Cache-Control to chosen one if none is set" do
40
+ it "set Cache-Control to chosen one if none is set" do
40
41
  app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
41
42
  response = etag(app, nil, 'public').call(request)
42
- response[1]['Cache-Control'].should.equal 'public'
43
+ response[1]['Cache-Control'].must_equal 'public'
43
44
  end
44
45
 
45
- should "set a given Cache-Control even if digest could not be calculated" do
46
+ it "set a given Cache-Control even if digest could not be calculated" do
46
47
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, []] }
47
48
  response = etag(app, 'no-cache').call(request)
48
- response[1]['Cache-Control'].should.equal 'no-cache'
49
+ response[1]['Cache-Control'].must_equal 'no-cache'
49
50
  end
50
51
 
51
- should "not set Cache-Control if it is already set" do
52
+ it "not set Cache-Control if it is already set" do
52
53
  app = lambda { |env| [201, {'Content-Type' => 'text/plain', 'Cache-Control' => 'public'}, ["Hello, World!"]] }
53
54
  response = etag(app).call(request)
54
- response[1]['Cache-Control'].should.equal 'public'
55
+ response[1]['Cache-Control'].must_equal 'public'
55
56
  end
56
57
 
57
- should "not set Cache-Control if directive isn't present" do
58
+ it "not set Cache-Control if directive isn't present" do
58
59
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
59
60
  response = etag(app, nil, nil).call(request)
60
- response[1]['Cache-Control'].should.equal nil
61
+ response[1]['Cache-Control'].must_equal nil
61
62
  end
62
63
 
63
- should "not change ETag if it is already set" do
64
+ it "not change ETag if it is already set" do
64
65
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
65
66
  response = etag(app).call(request)
66
- response[1]['ETag'].should.equal "\"abc\""
67
+ response[1]['ETag'].must_equal "\"abc\""
67
68
  end
68
69
 
69
- should "not set ETag if body is empty" do
70
+ it "not set ETag if body is empty" do
70
71
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, []] }
71
72
  response = etag(app).call(request)
72
- response[1]['ETag'].should.be.nil
73
+ response[1]['ETag'].must_be_nil
73
74
  end
74
75
 
75
- should "not set ETag if Last-Modified is set" do
76
+ it "not set ETag if Last-Modified is set" do
76
77
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, ["Hello, World!"]] }
77
78
  response = etag(app).call(request)
78
- response[1]['ETag'].should.be.nil
79
+ response[1]['ETag'].must_be_nil
79
80
  end
80
81
 
81
- should "not set ETag if a sendfile_body is given" do
82
+ it "not set ETag if a sendfile_body is given" do
82
83
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, sendfile_body] }
83
84
  response = etag(app).call(request)
84
- response[1]['ETag'].should.be.nil
85
+ response[1]['ETag'].must_be_nil
85
86
  end
86
87
 
87
- should "not set ETag if a status is not 200 or 201" do
88
+ it "not set ETag if a status is not 200 or 201" do
88
89
  app = lambda { |env| [401, {'Content-Type' => 'text/plain'}, ['Access denied.']] }
89
90
  response = etag(app).call(request)
90
- response[1]['ETag'].should.be.nil
91
+ response[1]['ETag'].must_be_nil
91
92
  end
92
93
 
93
- should "not set ETag if no-cache is given" do
94
+ it "not set ETag if no-cache is given" do
94
95
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-cache, must-revalidate'}, ['Hello, World!']] }
95
96
  response = etag(app).call(request)
96
- response[1]['ETag'].should.be.nil
97
+ response[1]['ETag'].must_be_nil
97
98
  end
98
99
 
99
- should "close the original body" do
100
+ it "close the original body" do
100
101
  body = StringIO.new
101
102
  app = lambda { |env| [200, {}, body] }
102
103
  response = etag(app).call(request)
103
- body.should.not.be.closed
104
+ body.wont_be :closed?
104
105
  response[2].close
105
- body.should.be.closed
106
+ body.must_be :closed?
106
107
  end
107
108
  end