rack 1.6.13 → 2.0.0.alpha

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 (138) hide show
  1. checksums.yaml +5 -5
  2. data/HISTORY.md +139 -18
  3. data/README.rdoc +17 -25
  4. data/Rakefile +6 -14
  5. data/SPEC +8 -9
  6. data/contrib/rack_logo.svg +164 -111
  7. data/lib/rack.rb +70 -21
  8. data/lib/rack/auth/digest/request.rb +1 -1
  9. data/lib/rack/body_proxy.rb +14 -9
  10. data/lib/rack/builder.rb +3 -3
  11. data/lib/rack/chunked.rb +5 -5
  12. data/lib/rack/{commonlogger.rb → common_logger.rb} +2 -2
  13. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  14. data/lib/rack/content_length.rb +2 -2
  15. data/lib/rack/deflater.rb +4 -4
  16. data/lib/rack/directory.rb +49 -55
  17. data/lib/rack/etag.rb +2 -1
  18. data/lib/rack/events.rb +154 -0
  19. data/lib/rack/file.rb +55 -40
  20. data/lib/rack/handler.rb +2 -24
  21. data/lib/rack/handler/cgi.rb +15 -16
  22. data/lib/rack/handler/fastcgi.rb +13 -14
  23. data/lib/rack/handler/lsws.rb +11 -11
  24. data/lib/rack/handler/scgi.rb +15 -15
  25. data/lib/rack/handler/thin.rb +3 -0
  26. data/lib/rack/handler/webrick.rb +22 -24
  27. data/lib/rack/head.rb +15 -17
  28. data/lib/rack/lint.rb +38 -38
  29. data/lib/rack/lobster.rb +1 -1
  30. data/lib/rack/lock.rb +6 -10
  31. data/lib/rack/logger.rb +2 -2
  32. data/lib/rack/media_type.rb +38 -0
  33. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  34. data/lib/rack/mime.rb +18 -5
  35. data/lib/rack/mock.rb +35 -52
  36. data/lib/rack/multipart.rb +35 -6
  37. data/lib/rack/multipart/generator.rb +4 -4
  38. data/lib/rack/multipart/parser.rb +273 -158
  39. data/lib/rack/multipart/uploaded_file.rb +1 -2
  40. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  41. data/lib/rack/query_parser.rb +174 -0
  42. data/lib/rack/recursive.rb +8 -8
  43. data/lib/rack/reloader.rb +1 -2
  44. data/lib/rack/request.rb +370 -304
  45. data/lib/rack/response.rb +129 -56
  46. data/lib/rack/rewindable_input.rb +1 -12
  47. data/lib/rack/runtime.rb +10 -18
  48. data/lib/rack/sendfile.rb +5 -7
  49. data/lib/rack/server.rb +31 -25
  50. data/lib/rack/session/abstract/id.rb +93 -135
  51. data/lib/rack/session/cookie.rb +26 -28
  52. data/lib/rack/session/memcache.rb +8 -14
  53. data/lib/rack/session/pool.rb +14 -21
  54. data/lib/rack/show_exceptions.rb +386 -0
  55. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  56. data/lib/rack/static.rb +30 -5
  57. data/lib/rack/tempfile_reaper.rb +2 -2
  58. data/lib/rack/urlmap.rb +13 -14
  59. data/lib/rack/utils.rb +128 -221
  60. data/rack.gemspec +9 -5
  61. data/test/builder/an_underscore_app.rb +5 -0
  62. data/test/builder/options.ru +1 -1
  63. data/test/cgi/test.fcgi +1 -0
  64. data/test/cgi/test.gz +0 -0
  65. data/test/helper.rb +31 -0
  66. data/test/multipart/filename_with_encoded_words +7 -0
  67. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  68. data/test/multipart/quoted +15 -0
  69. data/test/multipart/rack-logo.png +0 -0
  70. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  71. data/test/spec_auth_basic.rb +20 -19
  72. data/test/spec_auth_digest.rb +47 -46
  73. data/test/spec_body_proxy.rb +27 -27
  74. data/test/spec_builder.rb +51 -41
  75. data/test/spec_cascade.rb +24 -22
  76. data/test/spec_cgi.rb +49 -67
  77. data/test/spec_chunked.rb +36 -34
  78. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  79. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  80. data/test/spec_config.rb +3 -2
  81. data/test/spec_content_length.rb +18 -17
  82. data/test/spec_content_type.rb +13 -12
  83. data/test/spec_deflater.rb +66 -40
  84. data/test/spec_directory.rb +72 -27
  85. data/test/spec_etag.rb +32 -31
  86. data/test/spec_events.rb +133 -0
  87. data/test/spec_fastcgi.rb +50 -72
  88. data/test/spec_file.rb +96 -77
  89. data/test/spec_handler.rb +19 -34
  90. data/test/spec_head.rb +15 -14
  91. data/test/spec_lint.rb +162 -197
  92. data/test/spec_lobster.rb +24 -23
  93. data/test/spec_lock.rb +69 -39
  94. data/test/spec_logger.rb +4 -3
  95. data/test/spec_media_type.rb +42 -0
  96. data/test/spec_method_override.rb +83 -0
  97. data/test/spec_mime.rb +19 -19
  98. data/test/spec_mock.rb +196 -151
  99. data/test/spec_multipart.rb +310 -202
  100. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  101. data/test/spec_recursive.rb +17 -14
  102. data/test/spec_request.rb +763 -607
  103. data/test/spec_response.rb +209 -156
  104. data/test/spec_rewindable_input.rb +50 -40
  105. data/test/spec_runtime.rb +11 -10
  106. data/test/spec_sendfile.rb +30 -35
  107. data/test/spec_server.rb +78 -52
  108. data/test/spec_session_abstract_id.rb +11 -33
  109. data/test/spec_session_cookie.rb +97 -65
  110. data/test/spec_session_memcache.rb +63 -101
  111. data/test/spec_session_pool.rb +48 -84
  112. data/test/spec_show_exceptions.rb +80 -0
  113. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  114. data/test/spec_static.rb +71 -32
  115. data/test/spec_tempfile_reaper.rb +11 -10
  116. data/test/spec_thin.rb +55 -50
  117. data/test/spec_urlmap.rb +79 -78
  118. data/test/spec_utils.rb +417 -345
  119. data/test/spec_version.rb +2 -8
  120. data/test/spec_webrick.rb +77 -67
  121. data/test/static/foo.html +1 -0
  122. data/test/testrequest.rb +1 -1
  123. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  124. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  125. metadata +116 -71
  126. data/KNOWN-ISSUES +0 -44
  127. data/lib/rack/backports/uri/common_18.rb +0 -56
  128. data/lib/rack/backports/uri/common_192.rb +0 -52
  129. data/lib/rack/backports/uri/common_193.rb +0 -29
  130. data/lib/rack/handler/evented_mongrel.rb +0 -8
  131. data/lib/rack/handler/mongrel.rb +0 -106
  132. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  133. data/lib/rack/showexceptions.rb +0 -387
  134. data/lib/rack/utils/okjson.rb +0 -600
  135. data/test/spec_methodoverride.rb +0 -111
  136. data/test/spec_mongrel.rb +0 -182
  137. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  138. data/test/spec_showexceptions.rb +0 -98
@@ -1,3 +1,4 @@
1
+ require 'minitest/autorun'
1
2
  require 'rack/content_type'
2
3
  require 'rack/lint'
3
4
  require 'rack/mock'
@@ -6,40 +7,40 @@ describe Rack::ContentType do
6
7
  def content_type(app, *args)
7
8
  Rack::Lint.new Rack::ContentType.new(app, *args)
8
9
  end
9
-
10
+
10
11
  def request
11
12
  Rack::MockRequest.env_for
12
13
  end
13
-
14
- should "set Content-Type to default text/html if none is set" do
14
+
15
+ it "set Content-Type to default text/html if none is set" do
15
16
  app = lambda { |env| [200, {}, "Hello, World!"] }
16
17
  headers = content_type(app).call(request)[1]
17
- headers['Content-Type'].should.equal 'text/html'
18
+ headers['Content-Type'].must_equal 'text/html'
18
19
  end
19
20
 
20
- should "set Content-Type to chosen default if none is set" do
21
+ it "set Content-Type to chosen default if none is set" do
21
22
  app = lambda { |env| [200, {}, "Hello, World!"] }
22
23
  headers =
23
24
  content_type(app, 'application/octet-stream').call(request)[1]
24
- headers['Content-Type'].should.equal 'application/octet-stream'
25
+ headers['Content-Type'].must_equal 'application/octet-stream'
25
26
  end
26
27
 
27
- should "not change Content-Type if it is already set" do
28
+ it "not change Content-Type if it is already set" do
28
29
  app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
29
30
  headers = content_type(app).call(request)[1]
30
- headers['Content-Type'].should.equal 'foo/bar'
31
+ headers['Content-Type'].must_equal 'foo/bar'
31
32
  end
32
33
 
33
- should "detect Content-Type case insensitive" do
34
+ it "detect Content-Type case insensitive" do
34
35
  app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
35
36
  headers = content_type(app).call(request)[1]
36
37
  headers.to_a.select { |k,v| k.downcase == "content-type" }.
37
- should.equal [["CONTENT-Type","foo/bar"]]
38
+ must_equal [["CONTENT-Type","foo/bar"]]
38
39
  end
39
40
 
40
- should "not set Content-Type on 304 responses" do
41
+ it "not set Content-Type on 304 responses" do
41
42
  app = lambda { |env| [304, {}, []] }
42
43
  response = content_type(app, "text/html").call(request)
43
- response[1]['Content-Type'].should.equal nil
44
+ response[1]['Content-Type'].must_equal nil
44
45
  end
45
46
  end
@@ -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,122 @@
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!/)
38
64
  end
39
65
 
40
- should "not allow directory traversal" do
66
+ it "not allow directory traversal" do
41
67
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
42
68
  get("/cgi/../test")
43
69
 
44
- res.should.be.forbidden
70
+ res.must_be :forbidden?
45
71
 
46
72
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
47
73
  get("/cgi/%2E%2E/test")
48
74
 
49
- res.should.be.forbidden
75
+ res.must_be :forbidden?
50
76
  end
51
77
 
52
- should "404 if it can't find the file" do
78
+ it "404 if it can't find the file" do
53
79
  res = Rack::MockRequest.new(Rack::Lint.new(app)).
54
80
  get("/cgi/blubb")
55
81
 
56
- res.should.be.not_found
82
+ res.must_be :not_found?
57
83
  end
58
84
 
59
- should "uri escape path parts" do # #265, properly escape file names
85
+ it "uri escape path parts" do # #265, properly escape file names
60
86
  mr = Rack::MockRequest.new(Rack::Lint.new(app))
61
87
 
62
88
  res = mr.get("/cgi/test%2bdirectory")
63
89
 
64
- res.should.be.ok
65
- res.body.should =~ %r[/cgi/test%2Bdirectory/test%2Bfile]
90
+ res.must_be :ok?
91
+ res.body.must_match(%r[/cgi/test\+directory/test\+file])
66
92
 
67
93
  res = mr.get("/cgi/test%2bdirectory/test%2bfile")
68
- res.should.be.ok
94
+ res.must_be :ok?
95
+ end
96
+
97
+ it "correctly escape script name with spaces" do
98
+ Dir.mktmpdir do |dir|
99
+ space_dir = "foo bar"
100
+ full_dir = File.join(dir, space_dir)
101
+ FileUtils.mkdir full_dir
102
+ FileUtils.touch File.join(full_dir, "omg omg.txt")
103
+ app = Rack::Directory.new(dir, FILE_CATCH)
104
+ env = Rack::MockRequest.env_for(Rack::Utils.escape_path("/#{space_dir}/"))
105
+ status,_,body = app.call env
106
+
107
+ assert_equal 200, status
108
+
109
+ str = ''
110
+ body.each { |x| str << x }
111
+ assert_match "/foo%20bar/omg%20omg.txt", str
112
+ end
69
113
  end
70
114
 
71
- should "correctly escape script name" do
115
+ it "correctly escape script name" do
116
+ _app = app
72
117
  app2 = Rack::Builder.new do
73
118
  map '/script-path' do
74
- run app
119
+ run _app
75
120
  end
76
121
  end
77
122
 
@@ -79,10 +124,10 @@ describe Rack::Directory do
79
124
 
80
125
  res = mr.get("/script-path/cgi/test%2bdirectory")
81
126
 
82
- res.should.be.ok
83
- res.body.should =~ %r[/script-path/cgi/test%2Bdirectory/test%2Bfile]
127
+ res.must_be :ok?
128
+ res.body.must_match(%r[/script-path/cgi/test\+directory/test\+file])
84
129
 
85
- res = mr.get("/script-path/cgi/test%2bdirectory/test%2bfile")
86
- res.should.be.ok
130
+ res = mr.get("/script-path/cgi/test+directory/test+file")
131
+ res.must_be :ok?
87
132
  end
88
133
  end