rack 1.6.12 → 2.0.3

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 (142) 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 +10 -11
  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.rb +70 -21
  11. data/lib/rack/auth/abstract/request.rb +5 -1
  12. data/lib/rack/auth/digest/params.rb +2 -3
  13. data/lib/rack/auth/digest/request.rb +1 -1
  14. data/lib/rack/body_proxy.rb +14 -9
  15. data/lib/rack/builder.rb +3 -3
  16. data/lib/rack/chunked.rb +5 -5
  17. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  18. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  19. data/lib/rack/content_length.rb +2 -2
  20. data/lib/rack/deflater.rb +4 -39
  21. data/lib/rack/directory.rb +66 -54
  22. data/lib/rack/etag.rb +4 -3
  23. data/lib/rack/events.rb +154 -0
  24. data/lib/rack/file.rb +64 -40
  25. data/lib/rack/handler.rb +3 -25
  26. data/lib/rack/handler/cgi.rb +15 -16
  27. data/lib/rack/handler/fastcgi.rb +13 -14
  28. data/lib/rack/handler/lsws.rb +11 -11
  29. data/lib/rack/handler/scgi.rb +15 -15
  30. data/lib/rack/handler/thin.rb +3 -0
  31. data/lib/rack/handler/webrick.rb +24 -26
  32. data/lib/rack/head.rb +15 -17
  33. data/lib/rack/lint.rb +40 -40
  34. data/lib/rack/lobster.rb +1 -1
  35. data/lib/rack/lock.rb +6 -10
  36. data/lib/rack/logger.rb +2 -2
  37. data/lib/rack/media_type.rb +38 -0
  38. data/lib/rack/{methodoverride.rb → method_override.rb} +6 -10
  39. data/lib/rack/mime.rb +18 -5
  40. data/lib/rack/mock.rb +36 -54
  41. data/lib/rack/multipart.rb +35 -6
  42. data/lib/rack/multipart/generator.rb +5 -5
  43. data/lib/rack/multipart/parser.rb +272 -158
  44. data/lib/rack/multipart/uploaded_file.rb +1 -2
  45. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  46. data/lib/rack/query_parser.rb +192 -0
  47. data/lib/rack/recursive.rb +8 -8
  48. data/lib/rack/request.rb +383 -307
  49. data/lib/rack/response.rb +130 -57
  50. data/lib/rack/rewindable_input.rb +1 -12
  51. data/lib/rack/runtime.rb +10 -18
  52. data/lib/rack/sendfile.rb +5 -7
  53. data/lib/rack/server.rb +30 -23
  54. data/lib/rack/session/abstract/id.rb +108 -138
  55. data/lib/rack/session/cookie.rb +26 -28
  56. data/lib/rack/session/memcache.rb +8 -14
  57. data/lib/rack/session/pool.rb +14 -21
  58. data/lib/rack/show_exceptions.rb +386 -0
  59. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  60. data/lib/rack/static.rb +30 -5
  61. data/lib/rack/tempfile_reaper.rb +2 -2
  62. data/lib/rack/urlmap.rb +15 -14
  63. data/lib/rack/utils.rb +136 -211
  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_single_quote +7 -0
  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 +37 -35
  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 +85 -49
  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 +120 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +164 -199
  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_methodoverride.rb → spec_method_override.rb} +22 -37
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +206 -144
  104. data/test/spec_multipart.rb +322 -200
  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 +215 -112
  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 +45 -0
  115. data/test/spec_session_cookie.rb +99 -67
  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 +93 -68
  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 +102 -66
  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_mongrel.rb +0 -182
  142. 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_be_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,63 +74,98 @@ 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
+ # automatic gzip detection (streamable)
85
+ def auto_inflater
86
+ Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
87
+ end
88
+
89
+ def deflate_or_gzip
90
+ {'deflate, gzip' => 'gzip'}
91
+ end
92
+
93
+ it 'be able to deflate bodies that respond to each' do
84
94
  app_body = Object.new
85
95
  class << app_body; def each; yield('foo'); yield('bar'); end; end
86
96
 
87
- verify(200, 'foobar', 'deflate', { 'app_body' => app_body }) do |status, headers, body|
88
- headers.should.equal({
89
- 'Content-Encoding' => 'deflate',
97
+ verify(200, 'foobar', deflate_or_gzip, { 'app_body' => app_body }) do |status, headers, body|
98
+ headers.must_equal({
99
+ 'Content-Encoding' => 'gzip',
90
100
  'Vary' => 'Accept-Encoding',
91
101
  'Content-Type' => 'text/plain'
92
102
  })
93
103
  end
94
104
  end
95
105
 
96
- should 'flush deflated chunks to the client as they become ready' do
106
+ it 'flush deflated chunks to the client as they become ready' do
97
107
  app_body = Object.new
98
108
  class << app_body; def each; yield('foo'); yield('bar'); end; end
99
109
 
100
- verify(200, app_body, 'deflate', { 'skip_body_verify' => true }) do |status, headers, body|
101
- headers.should.equal({
102
- 'Content-Encoding' => 'deflate',
110
+ verify(200, app_body, deflate_or_gzip, { 'skip_body_verify' => true }) do |status, headers, body|
111
+ headers.must_equal({
112
+ 'Content-Encoding' => 'gzip',
103
113
  'Vary' => 'Accept-Encoding',
104
114
  'Content-Type' => 'text/plain'
105
115
  })
106
116
 
107
117
  buf = []
108
- inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
118
+ inflater = auto_inflater
109
119
  body.each { |part| buf << inflater.inflate(part) }
110
120
  buf << inflater.finish
111
121
 
112
- buf.delete_if { |part| part.empty? }.join.should.equal('foobar')
122
+ buf.delete_if { |part| part.empty? }.join.must_equal 'foobar'
123
+ end
124
+ end
125
+
126
+ it 'does not raise when a client aborts reading' do
127
+ app_body = Object.new
128
+ class << app_body; def each; yield('foo'); yield('bar'); end; end
129
+ opts = { 'skip_body_verify' => true }
130
+ verify(200, app_body, 'gzip', opts) do |status, headers, body|
131
+ headers.must_equal({
132
+ 'Content-Encoding' => 'gzip',
133
+ 'Vary' => 'Accept-Encoding',
134
+ 'Content-Type' => 'text/plain'
135
+ })
136
+
137
+ buf = []
138
+ inflater = auto_inflater
139
+ FakeDisconnect = Class.new(RuntimeError)
140
+ assert_raises(FakeDisconnect, "not Zlib::DataError not raised") do
141
+ body.each do |part|
142
+ tmp = inflater.inflate(part)
143
+ buf << tmp if tmp.bytesize > 0
144
+ raise FakeDisconnect
145
+ end
146
+ end
147
+ inflater.finish
148
+ buf.must_equal(%w(foo))
113
149
  end
114
150
  end
115
151
 
116
152
  # TODO: This is really just a special case of the above...
117
- should 'be able to deflate String bodies' do
118
- verify(200, 'Hello world!', 'deflate') do |status, headers, body|
119
- headers.should.equal({
120
- 'Content-Encoding' => 'deflate',
153
+ it 'be able to deflate String bodies' do
154
+ verify(200, 'Hello world!', deflate_or_gzip) do |status, headers, body|
155
+ headers.must_equal({
156
+ 'Content-Encoding' => 'gzip',
121
157
  'Vary' => 'Accept-Encoding',
122
158
  'Content-Type' => 'text/plain'
123
159
  })
124
160
  end
125
161
  end
126
162
 
127
- should 'be able to gzip bodies that respond to each' do
163
+ it 'be able to gzip bodies that respond to each' do
128
164
  app_body = Object.new
129
165
  class << app_body; def each; yield('foo'); yield('bar'); end; end
130
166
 
131
167
  verify(200, 'foobar', 'gzip', { 'app_body' => app_body }) do |status, headers, body|
132
- headers.should.equal({
168
+ headers.must_equal({
133
169
  'Content-Encoding' => 'gzip',
134
170
  'Vary' => 'Accept-Encoding',
135
171
  'Content-Type' => 'text/plain'
@@ -137,12 +173,12 @@ describe Rack::Deflater do
137
173
  end
138
174
  end
139
175
 
140
- should 'flush gzipped chunks to the client as they become ready' do
176
+ it 'flush gzipped chunks to the client as they become ready' do
141
177
  app_body = Object.new
142
178
  class << app_body; def each; yield('foo'); yield('bar'); end; end
143
179
 
144
180
  verify(200, app_body, 'gzip', { 'skip_body_verify' => true }) do |status, headers, body|
145
- headers.should.equal({
181
+ headers.must_equal({
146
182
  'Content-Encoding' => 'gzip',
147
183
  'Vary' => 'Accept-Encoding',
148
184
  'Content-Type' => 'text/plain'
@@ -153,26 +189,26 @@ describe Rack::Deflater do
153
189
  body.each { |part| buf << inflater.inflate(part) }
154
190
  buf << inflater.finish
155
191
 
156
- buf.delete_if { |part| part.empty? }.join.should.equal('foobar')
192
+ buf.delete_if { |part| part.empty? }.join.must_equal 'foobar'
157
193
  end
158
194
  end
159
195
 
160
- should 'be able to fallback to no deflation' do
196
+ it 'be able to fallback to no deflation' do
161
197
  verify(200, 'Hello world!', 'superzip') do |status, headers, body|
162
- headers.should.equal({
198
+ headers.must_equal({
163
199
  'Vary' => 'Accept-Encoding',
164
200
  'Content-Type' => 'text/plain'
165
201
  })
166
202
  end
167
203
  end
168
204
 
169
- should 'be able to skip when there is no response entity body' do
205
+ it 'be able to skip when there is no response entity body' do
170
206
  verify(304, '', { 'gzip' => nil }, { 'app_body' => [] }) do |status, headers, body|
171
- headers.should.equal({})
207
+ headers.must_equal({})
172
208
  end
173
209
  end
174
210
 
175
- should 'handle the lack of an acceptable encoding' do
211
+ it 'handle the lack of an acceptable encoding' do
176
212
  app_body = 'Hello world!'
177
213
  not_found_body1 = 'An acceptable encoding for the requested resource / could not be found.'
178
214
  not_found_body2 = 'An acceptable encoding for the requested resource /foo/bar could not be found.'
@@ -192,21 +228,21 @@ describe Rack::Deflater do
192
228
  }
193
229
 
194
230
  verify(406, not_found_body1, 'identity;q=0', options1) do |status, headers, body|
195
- headers.should.equal({
231
+ headers.must_equal({
196
232
  'Content-Type' => 'text/plain',
197
233
  'Content-Length' => not_found_body1.length.to_s
198
234
  })
199
235
  end
200
236
 
201
237
  verify(406, not_found_body2, 'identity;q=0', options2) do |status, headers, body|
202
- headers.should.equal({
238
+ headers.must_equal({
203
239
  'Content-Type' => 'text/plain',
204
240
  'Content-Length' => not_found_body2.length.to_s
205
241
  })
206
242
  end
207
243
  end
208
244
 
209
- should 'handle gzip response with Last-Modified header' do
245
+ it 'handle gzip response with Last-Modified header' do
210
246
  last_modified = Time.now.httpdate
211
247
  options = {
212
248
  'response_headers' => {
@@ -216,7 +252,7 @@ describe Rack::Deflater do
216
252
  }
217
253
 
218
254
  verify(200, 'Hello World!', 'gzip', options) do |status, headers, body|
219
- headers.should.equal({
255
+ headers.must_equal({
220
256
  'Content-Encoding' => 'gzip',
221
257
  'Vary' => 'Accept-Encoding',
222
258
  'Last-Modified' => last_modified,
@@ -225,7 +261,7 @@ describe Rack::Deflater do
225
261
  end
226
262
  end
227
263
 
228
- should 'do nothing when no-transform Cache-Control directive present' do
264
+ it 'do nothing when no-transform Cache-Control directive present' do
229
265
  options = {
230
266
  'response_headers' => {
231
267
  'Content-Type' => 'text/plain',
@@ -233,11 +269,11 @@ describe Rack::Deflater do
233
269
  }
234
270
  }
235
271
  verify(200, 'Hello World!', { 'gzip' => nil }, options) do |status, headers, body|
236
- headers.should.not.include 'Content-Encoding'
272
+ headers.wont_include 'Content-Encoding'
237
273
  end
238
274
  end
239
275
 
240
- should 'do nothing when Content-Encoding already present' do
276
+ it 'do nothing when Content-Encoding already present' do
241
277
  options = {
242
278
  'response_headers' => {
243
279
  'Content-Type' => 'text/plain',
@@ -247,17 +283,17 @@ describe Rack::Deflater do
247
283
  verify(200, 'Hello World!', { 'gzip' => nil }, options)
248
284
  end
249
285
 
250
- should 'deflate when Content-Encoding is identity' do
286
+ it 'deflate when Content-Encoding is identity' do
251
287
  options = {
252
288
  'response_headers' => {
253
289
  'Content-Type' => 'text/plain',
254
290
  'Content-Encoding' => 'identity'
255
291
  }
256
292
  }
257
- verify(200, 'Hello World!', 'deflate', options)
293
+ verify(200, 'Hello World!', deflate_or_gzip, options)
258
294
  end
259
295
 
260
- should "deflate if content-type matches :include" do
296
+ it "deflate if content-type matches :include" do
261
297
  options = {
262
298
  'response_headers' => {
263
299
  'Content-Type' => 'text/plain'
@@ -269,7 +305,7 @@ describe Rack::Deflater do
269
305
  verify(200, 'Hello World!', 'gzip', options)
270
306
  end
271
307
 
272
- should "deflate if content-type is included it :include" do
308
+ it "deflate if content-type is included it :include" do
273
309
  options = {
274
310
  'response_headers' => {
275
311
  'Content-Type' => 'text/plain; charset=us-ascii'
@@ -281,7 +317,7 @@ describe Rack::Deflater do
281
317
  verify(200, 'Hello World!', 'gzip', options)
282
318
  end
283
319
 
284
- should "not deflate if content-type is not set but given in :include" do
320
+ it "not deflate if content-type is not set but given in :include" do
285
321
  options = {
286
322
  'deflater_options' => {
287
323
  :include => %w(text/plain)
@@ -290,7 +326,7 @@ describe Rack::Deflater do
290
326
  verify(304, 'Hello World!', { 'gzip' => nil }, options)
291
327
  end
292
328
 
293
- should "not deflate if content-type do not match :include" do
329
+ it "not deflate if content-type do not match :include" do
294
330
  options = {
295
331
  'response_headers' => {
296
332
  'Content-Type' => 'text/plain'
@@ -302,16 +338,16 @@ describe Rack::Deflater do
302
338
  verify(200, 'Hello World!', { 'gzip' => nil }, options)
303
339
  end
304
340
 
305
- should "deflate response if :if lambda evaluates to true" do
341
+ it "deflate response if :if lambda evaluates to true" do
306
342
  options = {
307
343
  'deflater_options' => {
308
344
  :if => lambda { |env, status, headers, body| true }
309
345
  }
310
346
  }
311
- verify(200, 'Hello World!', 'deflate', options)
347
+ verify(200, 'Hello World!', deflate_or_gzip, options)
312
348
  end
313
349
 
314
- should "not deflate if :if lambda evaluates to false" do
350
+ it "not deflate if :if lambda evaluates to false" do
315
351
  options = {
316
352
  'deflater_options' => {
317
353
  :if => lambda { |env, status, headers, body| false }
@@ -320,20 +356,20 @@ describe Rack::Deflater do
320
356
  verify(200, 'Hello World!', { 'gzip' => nil }, options)
321
357
  end
322
358
 
323
- should "check for Content-Length via :if" do
324
- body = 'Hello World!'
325
- body_len = body.length
359
+ it "check for Content-Length via :if" do
360
+ response = 'Hello World!'
361
+ response_len = response.length
326
362
  options = {
327
363
  'response_headers' => {
328
- 'Content-Length' => body_len.to_s
364
+ 'Content-Length' => response_len.to_s
329
365
  },
330
366
  'deflater_options' => {
331
367
  :if => lambda { |env, status, headers, body|
332
- headers['Content-Length'].to_i >= body_len
368
+ headers['Content-Length'].to_i >= response_len
333
369
  }
334
370
  }
335
371
  }
336
372
 
337
- verify(200, body, 'gzip', options)
373
+ verify(200, response, 'gzip', options)
338
374
  end
339
375
  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