rack 2.0.1 → 2.0.2

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4e9c67e795c425f3e8faa0d0fe8d48daba757e5
4
- data.tar.gz: bf8c0c20c6310e7bd53e8b20c8c4946b1205eb65
3
+ metadata.gz: 8fee84474048108cce439e6089d87176a6870bc2
4
+ data.tar.gz: 0ed86a0e0e70541873ffa31dfef66e5268a107b2
5
5
  SHA512:
6
- metadata.gz: 5540bc2b6de513db3c5c494e6e32229087fb20040c4670a8c2215a9ea5a04b010ac9b5143cc3703ab73df0417234a416e49370fb3eafc85bde1c569e521c0612
7
- data.tar.gz: f2af8aa5ee53427248393dd707ca34428d18b064c3081a3db663cd0f1e6f35e4b18ce54f607f7cea3c56569ef2552240dd55d0c4ff7006e0e2ab80db3800a933
6
+ metadata.gz: 460ecadb871f77085e040982f9cb56fd2fd165f95d172c4ff73b3d16c899dc26f0e8a352667044dd32b34a57d3a179efe65f3b933c58adf7b0427566a6356188
7
+ data.tar.gz: 1ab651dc52e8ff7ace49f22359aff5c7d2baff1787082398c7cf21aa593552183872466b3cf03e6675ca1621e44076e85cddae9486713311412e916baee5bac1
data/SPEC CHANGED
@@ -237,10 +237,10 @@ consisting of lines (for multiple header values, e.g. multiple
237
237
  The lines must not contain characters below 037.
238
238
  === The Content-Type
239
239
  There must not be a <tt>Content-Type</tt>, when the +Status+ is 1xx,
240
- 204, 205 or 304.
240
+ 204 or 304.
241
241
  === The Content-Length
242
242
  There must not be a <tt>Content-Length</tt> header when the
243
- +Status+ is 1xx, 204, 205 or 304.
243
+ +Status+ is 1xx, 204 or 304.
244
244
  === The Body
245
245
  The Body must respond to +each+
246
246
  and must only yield String values.
@@ -18,7 +18,7 @@ module Rack
18
18
  VERSION.join(".")
19
19
  end
20
20
 
21
- RELEASE = "2.0.1"
21
+ RELEASE = "2.0.2"
22
22
 
23
23
  # Return the Rack release as a dotted string.
24
24
  def self.release
@@ -8,7 +8,6 @@ module Rack
8
8
  # Currently supported compression algorithms:
9
9
  #
10
10
  # * gzip
11
- # * deflate
12
11
  # * identity (no transformation)
13
12
  #
14
13
  # The middleware automatically detects when compression is supported
@@ -22,7 +21,7 @@ module Rack
22
21
  # [app] rack app instance
23
22
  # [options] hash of deflater options, i.e.
24
23
  # 'if' - a lambda enabling / disabling deflation based on returned boolean value
25
- # e.g use Rack::Deflater, :if => lambda { |env, status, headers, body| body.length > 512 }
24
+ # e.g use Rack::Deflater, :if => lambda { |env, status, headers, body| body.map(&:bytesize).reduce(0, :+) > 512 }
26
25
  # 'include' - a list of content types that should be compressed
27
26
  def initialize(app, options = {})
28
27
  @app = app
@@ -41,7 +40,7 @@ module Rack
41
40
 
42
41
  request = Request.new(env)
43
42
 
44
- encoding = Utils.select_best_encoding(%w(gzip deflate identity),
43
+ encoding = Utils.select_best_encoding(%w(gzip identity),
45
44
  request.accept_encoding)
46
45
 
47
46
  # Set the Vary HTTP header.
@@ -57,10 +56,6 @@ module Rack
57
56
  mtime = headers.key?("Last-Modified") ?
58
57
  Time.httpdate(headers["Last-Modified"]) : Time.now
59
58
  [status, headers, GzipStream.new(body, mtime)]
60
- when "deflate"
61
- headers['Content-Encoding'] = "deflate"
62
- headers.delete(CONTENT_LENGTH)
63
- [status, headers, DeflateStream.new(body)]
64
59
  when "identity"
65
60
  [status, headers, body]
66
61
  when nil
@@ -101,36 +96,6 @@ module Rack
101
96
  end
102
97
  end
103
98
 
104
- class DeflateStream
105
- DEFLATE_ARGS = [
106
- Zlib::DEFAULT_COMPRESSION,
107
- # drop the zlib header which causes both Safari and IE to choke
108
- -Zlib::MAX_WBITS,
109
- Zlib::DEF_MEM_LEVEL,
110
- Zlib::DEFAULT_STRATEGY
111
- ]
112
-
113
- def initialize(body)
114
- @body = body
115
- @closed = false
116
- end
117
-
118
- def each
119
- deflator = ::Zlib::Deflate.new(*DEFLATE_ARGS)
120
- @body.each { |part| yield deflator.deflate(part, Zlib::SYNC_FLUSH) }
121
- yield fin = deflator.finish
122
- ensure
123
- deflator.finish unless fin
124
- deflator.close
125
- end
126
-
127
- def close
128
- return if @closed
129
- @closed = true
130
- @body.close if @body.respond_to?(:close)
131
- end
132
- end
133
-
134
99
  private
135
100
 
136
101
  def should_deflate?(env, status, headers, body)
@@ -158,7 +158,7 @@ module Rack
158
158
 
159
159
  def filesize path
160
160
  # If response_body is present, use its size.
161
- return Rack::Utils.bytesize(response_body) if response_body
161
+ return response_body.bytesize if response_body
162
162
 
163
163
  # We check via File::size? whether this file provides size info
164
164
  # via stat (e.g. /proc files often don't), otherwise we have to
@@ -86,10 +86,11 @@ module Rack
86
86
  status, headers, body = @app.call(env)
87
87
  begin
88
88
  res.status = status.to_i
89
+ io_lambda = nil
89
90
  headers.each { |k, vs|
90
- next if k.downcase == RACK_HIJACK
91
-
92
- if k.downcase == "set-cookie"
91
+ if k == RACK_HIJACK
92
+ io_lambda = vs
93
+ elsif k.downcase == "set-cookie"
93
94
  res.cookies.concat vs.split("\n")
94
95
  else
95
96
  # Since WEBrick won't accept repeated headers,
@@ -98,7 +99,6 @@ module Rack
98
99
  end
99
100
  }
100
101
 
101
- io_lambda = headers[RACK_HIJACK]
102
102
  if io_lambda
103
103
  rd, wr = IO.pipe
104
104
  res.body = rd
@@ -659,7 +659,7 @@ module Rack
659
659
  def check_content_type(status, headers)
660
660
  headers.each { |key, value|
661
661
  ## There must not be a <tt>Content-Type</tt>, when the +Status+ is 1xx,
662
- ## 204, 205 or 304.
662
+ ## 204 or 304.
663
663
  if key.downcase == "content-type"
664
664
  assert("Content-Type header found in #{status} response, not allowed") {
665
665
  not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
@@ -674,7 +674,7 @@ module Rack
674
674
  headers.each { |key, value|
675
675
  if key.downcase == 'content-length'
676
676
  ## There must not be a <tt>Content-Length</tt> header when the
677
- ## +Status+ is 1xx, 204, 205 or 304.
677
+ ## +Status+ is 1xx, 204 or 304.
678
678
  assert("Content-Length header found in #{status} response, not allowed") {
679
679
  not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
680
680
  }
@@ -38,6 +38,9 @@ module Rack
38
38
  def method_override_param(req)
39
39
  req.POST[METHOD_OVERRIDE_PARAM_KEY]
40
40
  rescue Utils::InvalidParameterError, Utils::ParameterTypeError
41
+ req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params"
42
+ rescue EOFError
43
+ req.get_header(RACK_ERRORS).puts "Bad request content body"
41
44
  end
42
45
  end
43
46
  end
@@ -190,7 +190,7 @@ module Rack
190
190
  end
191
191
 
192
192
  def empty?
193
- [201, 204, 205, 304].include? status
193
+ [201, 204, 304].include? status
194
194
  end
195
195
  end
196
196
  end
@@ -8,7 +8,7 @@ module Rack
8
8
  BUFSIZE = 16384
9
9
  TEXT_PLAIN = "text/plain"
10
10
  TEMPFILE_FACTORY = lambda { |filename, content_type|
11
- Tempfile.new(["RackMultipart", ::File.extname(filename)])
11
+ Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0".freeze, '%00'.freeze))])
12
12
  }
13
13
 
14
14
  class BoundedIO # :nodoc:
@@ -422,7 +422,7 @@ module Rack
422
422
 
423
423
  # shortcut for <tt>request.params[key]</tt>
424
424
  def [](key)
425
- if $verbose
425
+ if $VERBOSE
426
426
  warn("Request#[] is deprecated and will be removed in a future version of Rack. Please use request.params[] instead")
427
427
  end
428
428
 
@@ -433,7 +433,7 @@ module Rack
433
433
  #
434
434
  # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params.
435
435
  def []=(key, value)
436
- if $verbose
436
+ if $VERBOSE
437
437
  warn("Request#[]= is deprecated and will be removed in a future version of Rack. Please use request.params[]= instead")
438
438
  end
439
439
 
@@ -60,7 +60,7 @@ module Rack
60
60
  def finish(&block)
61
61
  @block = block
62
62
 
63
- if [204, 205, 304].include?(status.to_i)
63
+ if [204, 304].include?(status.to_i)
64
64
  delete_header CONTENT_TYPE
65
65
  delete_header CONTENT_LENGTH
66
66
  close
@@ -1,4 +1,5 @@
1
1
  require 'optparse'
2
+ require 'fileutils'
2
3
 
3
4
 
4
5
  module Rack
@@ -359,7 +360,7 @@ module Rack
359
360
 
360
361
  def write_pid
361
362
  ::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") }
362
- at_exit { ::File.delete(options[:pid]) if ::File.exist?(options[:pid]) }
363
+ at_exit { ::FileUtils.rm_f(options[:pid]) }
363
364
  rescue Errno::EEXIST
364
365
  check_pid!
365
366
  retry
@@ -18,6 +18,8 @@ module Rack
18
18
  include Enumerable
19
19
  attr_writer :id
20
20
 
21
+ Unspecified = Object.new
22
+
21
23
  def self.find(req)
22
24
  req.get_header RACK_SESSION
23
25
  end
@@ -54,7 +56,15 @@ module Rack
54
56
  load_for_read!
55
57
  @data[key.to_s]
56
58
  end
57
- alias :fetch :[]
59
+
60
+ def fetch(key, default=Unspecified, &block)
61
+ load_for_read!
62
+ if default == Unspecified
63
+ @data.fetch(key.to_s, &block)
64
+ else
65
+ @data.fetch(key.to_s, default, &block)
66
+ end
67
+ end
58
68
 
59
69
  def has_key?(key)
60
70
  load_for_read!
@@ -167,7 +177,7 @@ module Rack
167
177
  # * :key determines the name of the cookie, by default it is
168
178
  # 'rack.session'
169
179
  # * :path, :domain, :expire_after, :secure, and :httponly set the related
170
- # cookie options as by Rack::Response#add_cookie
180
+ # cookie options as by Rack::Response#set_cookie
171
181
  # * :skip will not a set a cookie in the response nor update the session state
172
182
  # * :defer will not set a cookie in the response but still update the session
173
183
  # state if it is used with a backend
@@ -200,7 +210,7 @@ module Rack
200
210
  :sidbits => 128,
201
211
  :cookie_only => true,
202
212
  :secure_random => ::SecureRandom
203
- }
213
+ }.freeze
204
214
 
205
215
  attr_reader :key, :default_options, :sid_secure
206
216
 
@@ -576,7 +576,7 @@ module Rack
576
576
  }
577
577
 
578
578
  # Responses with HTTP status codes that should not have an entity body
579
- STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 205 << 304)
579
+ STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304)
580
580
 
581
581
  SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
582
582
  [message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
@@ -0,0 +1,7 @@
1
+ --AaB03x
2
+ Content-Type: image/jpeg
3
+ Content-Disposition: attachment; name="files"; filename="flowers.exe%00.jpg"
4
+ Content-Description: a complete map of the human genome
5
+
6
+ contents
7
+ --AaB03x--
@@ -92,7 +92,7 @@ describe Rack::Chunked do
92
92
  body.join.must_equal 'Hello World!'
93
93
  end
94
94
 
95
- [100, 204, 205, 304].each do |status_code|
95
+ [100, 204, 304].each do |status_code|
96
96
  it "not modify response when status code is #{status_code}" do
97
97
  app = lambda { |env| [status_code, {}, []] }
98
98
  status, headers, _ = chunked(app).call(@env)
@@ -36,13 +36,13 @@ describe Rack::ContentLength do
36
36
  it "not set Content-Length on 304 responses" do
37
37
  app = lambda { |env| [304, {}, []] }
38
38
  response = content_length(app).call(request)
39
- response[1]['Content-Length'].must_equal nil
39
+ response[1]['Content-Length'].must_be_nil
40
40
  end
41
41
 
42
42
  it "not set Content-Length when Transfer-Encoding is chunked" do
43
43
  app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Transfer-Encoding' => 'chunked'}, []] }
44
44
  response = content_length(app).call(request)
45
- response[1]['Content-Length'].must_equal nil
45
+ response[1]['Content-Length'].must_be_nil
46
46
  end
47
47
 
48
48
  # Using "Connection: close" for this is fairly contended. It might be useful
@@ -51,7 +51,7 @@ describe Rack::ContentLength do
51
51
  # should "not force a Content-Length when Connection:close" do
52
52
  # app = lambda { |env| [200, {'Connection' => 'close'}, []] }
53
53
  # response = content_length(app).call({})
54
- # response[1]['Content-Length'].must_equal nil
54
+ # response[1]['Content-Length'].must_be_nil
55
55
  # end
56
56
 
57
57
  it "close bodies that need to be closed" do
@@ -64,7 +64,7 @@ describe Rack::ContentLength do
64
64
 
65
65
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
66
66
  response = content_length(app).call(request)
67
- body.closed.must_equal nil
67
+ body.closed.must_be_nil
68
68
  response[2].close
69
69
  body.closed.must_equal true
70
70
  end
@@ -41,6 +41,6 @@ describe Rack::ContentType do
41
41
  it "not set Content-Type on 304 responses" do
42
42
  app = lambda { |env| [304, {}, []] }
43
43
  response = content_type(app, "text/html").call(request)
44
- response[1]['Content-Type'].must_equal nil
44
+ response[1]['Content-Type'].must_be_nil
45
45
  end
46
46
  end
@@ -81,13 +81,22 @@ describe Rack::Deflater do
81
81
  yield(status, headers, body) if block_given?
82
82
  end
83
83
 
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
+
84
93
  it 'be able to deflate bodies that respond to each' do
85
94
  app_body = Object.new
86
95
  class << app_body; def each; yield('foo'); yield('bar'); end; end
87
96
 
88
- verify(200, 'foobar', 'deflate', { 'app_body' => app_body }) do |status, headers, body|
97
+ verify(200, 'foobar', deflate_or_gzip, { 'app_body' => app_body }) do |status, headers, body|
89
98
  headers.must_equal({
90
- 'Content-Encoding' => 'deflate',
99
+ 'Content-Encoding' => 'gzip',
91
100
  'Vary' => 'Accept-Encoding',
92
101
  'Content-Type' => 'text/plain'
93
102
  })
@@ -98,15 +107,15 @@ describe Rack::Deflater do
98
107
  app_body = Object.new
99
108
  class << app_body; def each; yield('foo'); yield('bar'); end; end
100
109
 
101
- verify(200, app_body, 'deflate', { 'skip_body_verify' => true }) do |status, headers, body|
110
+ verify(200, app_body, deflate_or_gzip, { 'skip_body_verify' => true }) do |status, headers, body|
102
111
  headers.must_equal({
103
- 'Content-Encoding' => 'deflate',
112
+ 'Content-Encoding' => 'gzip',
104
113
  'Vary' => 'Accept-Encoding',
105
114
  'Content-Type' => 'text/plain'
106
115
  })
107
116
 
108
117
  buf = []
109
- inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
118
+ inflater = auto_inflater
110
119
  body.each { |part| buf << inflater.inflate(part) }
111
120
  buf << inflater.finish
112
121
 
@@ -118,32 +127,33 @@ describe Rack::Deflater do
118
127
  app_body = Object.new
119
128
  class << app_body; def each; yield('foo'); yield('bar'); end; end
120
129
  opts = { 'skip_body_verify' => true }
121
- verify(200, app_body, 'deflate', opts) do |status, headers, body|
130
+ verify(200, app_body, 'gzip', opts) do |status, headers, body|
122
131
  headers.must_equal({
123
- 'Content-Encoding' => 'deflate',
132
+ 'Content-Encoding' => 'gzip',
124
133
  'Vary' => 'Accept-Encoding',
125
134
  'Content-Type' => 'text/plain'
126
135
  })
127
136
 
128
137
  buf = []
129
- inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
138
+ inflater = auto_inflater
130
139
  FakeDisconnect = Class.new(RuntimeError)
131
140
  assert_raises(FakeDisconnect, "not Zlib::DataError not raised") do
132
141
  body.each do |part|
133
- buf << inflater.inflate(part)
142
+ tmp = inflater.inflate(part)
143
+ buf << tmp if tmp.bytesize > 0
134
144
  raise FakeDisconnect
135
145
  end
136
146
  end
137
- assert_raises(Zlib::BufError) { inflater.finish }
147
+ inflater.finish
138
148
  buf.must_equal(%w(foo))
139
149
  end
140
150
  end
141
151
 
142
152
  # TODO: This is really just a special case of the above...
143
153
  it 'be able to deflate String bodies' do
144
- verify(200, 'Hello world!', 'deflate') do |status, headers, body|
154
+ verify(200, 'Hello world!', deflate_or_gzip) do |status, headers, body|
145
155
  headers.must_equal({
146
- 'Content-Encoding' => 'deflate',
156
+ 'Content-Encoding' => 'gzip',
147
157
  'Vary' => 'Accept-Encoding',
148
158
  'Content-Type' => 'text/plain'
149
159
  })
@@ -280,7 +290,7 @@ describe Rack::Deflater do
280
290
  'Content-Encoding' => 'identity'
281
291
  }
282
292
  }
283
- verify(200, 'Hello World!', 'deflate', options)
293
+ verify(200, 'Hello World!', deflate_or_gzip, options)
284
294
  end
285
295
 
286
296
  it "deflate if content-type matches :include" do
@@ -334,7 +344,7 @@ describe Rack::Deflater do
334
344
  :if => lambda { |env, status, headers, body| true }
335
345
  }
336
346
  }
337
- verify(200, 'Hello World!', 'deflate', options)
347
+ verify(200, 'Hello World!', deflate_or_gzip, options)
338
348
  end
339
349
 
340
350
  it "not deflate if :if lambda evaluates to false" do
@@ -58,7 +58,7 @@ describe Rack::ETag do
58
58
  it "not set Cache-Control if directive isn't present" do
59
59
  app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
60
60
  response = etag(app, nil, nil).call(request)
61
- response[1]['Cache-Control'].must_equal nil
61
+ response[1]['Cache-Control'].must_be_nil
62
62
  end
63
63
 
64
64
  it "not change ETag if it is already set" do
@@ -184,8 +184,8 @@ describe Rack::File do
184
184
  status, heads, _ = file(DOCROOT).call(env)
185
185
 
186
186
  status.must_equal 200
187
- heads['Cache-Control'].must_equal nil
188
- heads['Access-Control-Allow-Origin'].must_equal nil
187
+ heads['Cache-Control'].must_be_nil
188
+ heads['Access-Control-Allow-Origin'].must_be_nil
189
189
  end
190
190
 
191
191
  it "only support GET, HEAD, and OPTIONS requests" do
@@ -239,7 +239,7 @@ describe Rack::File do
239
239
  req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, nil)))
240
240
  res = req.get "/cgi/test"
241
241
  res.must_be :successful?
242
- res['Content-Type'].must_equal nil
242
+ res['Content-Type'].must_be_nil
243
243
  end
244
244
 
245
245
  it "return error when file not found for head request" do
@@ -248,4 +248,17 @@ describe Rack::File do
248
248
  res.body.must_be :empty?
249
249
  end
250
250
 
251
+ class MyFile < Rack::File
252
+ def response_body
253
+ "hello world"
254
+ end
255
+ end
256
+
257
+ it "behaves gracefully if response_body is present" do
258
+ file = Rack::Lint.new MyFile.new(DOCROOT)
259
+ res = Rack::MockRequest.new(file).get("/cgi/test")
260
+
261
+ res.must_be :ok?
262
+ end
263
+
251
264
  end
@@ -269,7 +269,7 @@ describe Rack::Lint do
269
269
  # }.must_raise(Rack::Lint::LintError).
270
270
  # message.must_match(/No Content-Type/)
271
271
 
272
- [100, 101, 204, 205, 304].each do |status|
272
+ [100, 101, 204, 304].each do |status|
273
273
  lambda {
274
274
  Rack::Lint.new(lambda { |env|
275
275
  [status, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
@@ -280,7 +280,7 @@ describe Rack::Lint do
280
280
  end
281
281
 
282
282
  it "notice content-length errors" do
283
- [100, 101, 204, 205, 304].each do |status|
283
+ [100, 101, 204, 304].each do |status|
284
284
  lambda {
285
285
  Rack::Lint.new(lambda { |env|
286
286
  [status, {"Content-length" => "0"}, []]
@@ -8,7 +8,7 @@ describe Rack::MediaType do
8
8
  before { @content_type = nil }
9
9
 
10
10
  it '#type is nil' do
11
- Rack::MediaType.type(@content_type).must_equal nil
11
+ Rack::MediaType.type(@content_type).must_be_nil
12
12
  end
13
13
 
14
14
  it '#params is empty' do
@@ -66,14 +66,27 @@ EOF
66
66
  "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
67
67
  "CONTENT_LENGTH" => input.size.to_s,
68
68
  :method => "POST", :input => input)
69
- begin
70
- app.call env
71
- rescue EOFError
72
- end
69
+ app.call env
73
70
 
74
71
  env["REQUEST_METHOD"].must_equal "POST"
75
72
  end
76
73
 
74
+ it "writes error to RACK_ERRORS when given invalid multipart form data" do
75
+ input = <<EOF
76
+ --AaB03x\r
77
+ content-disposition: form-data; name="huge"; filename="huge"\r
78
+ EOF
79
+ env = Rack::MockRequest.env_for("/",
80
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
81
+ "CONTENT_LENGTH" => input.size.to_s,
82
+ Rack::RACK_ERRORS => StringIO.new,
83
+ :method => "POST", :input => input)
84
+ Rack::MethodOverride.new(proc { [200, {"Content-Type" => "text/plain"}, []] }).call env
85
+
86
+ env[Rack::RACK_ERRORS].rewind
87
+ env[Rack::RACK_ERRORS].read.must_match /Bad request content body/
88
+ end
89
+
77
90
  it "not modify REQUEST_METHOD for POST requests when the params are unparseable" do
78
91
  env = Rack::MockRequest.env_for("/", :method => "POST", :input => "(%bad-params%)")
79
92
  app.call env
@@ -19,7 +19,7 @@ describe Rack::Mime do
19
19
  end
20
20
 
21
21
  it "should support null fallbacks" do
22
- Rack::Mime.mime_type('.nothing', nil).must_equal nil
22
+ Rack::Mime.mime_type('.nothing', nil).must_be_nil
23
23
  end
24
24
 
25
25
  it "should match exact mimes" do
@@ -27,7 +27,7 @@ describe Rack::Multipart do
27
27
  it "return nil if content type is not multipart" do
28
28
  env = Rack::MockRequest.env_for("/",
29
29
  "CONTENT_TYPE" => 'application/x-www-form-urlencoded')
30
- Rack::Multipart.parse_multipart(env).must_equal nil
30
+ Rack::Multipart.parse_multipart(env).must_be_nil
31
31
  end
32
32
 
33
33
  it "parse multipart content when content type present but filename is not" do
@@ -305,11 +305,17 @@ describe Rack::Multipart do
305
305
  params["files"][:filename].must_equal "bob's flowers.jpg"
306
306
  end
307
307
 
308
+ it "parse multipart form with a null byte in the filename" do
309
+ env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_null_byte)
310
+ params = Rack::Multipart.parse_multipart(env)
311
+ params["files"][:filename].must_equal "flowers.exe\u0000.jpg"
312
+ end
313
+
308
314
  it "not include file params if no file was selected" do
309
315
  env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
310
316
  params = Rack::Multipart.parse_multipart(env)
311
317
  params["submit-name"].must_equal "Larry"
312
- params["files"].must_equal nil
318
+ params["files"].must_be_nil
313
319
  params.keys.wont_include "files"
314
320
  end
315
321
 
@@ -557,7 +563,7 @@ Content-Type: image/jpeg\r
557
563
 
558
564
  it "return nil if no UploadedFiles were used" do
559
565
  data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
560
- data.must_equal nil
566
+ data.must_be_nil
561
567
  end
562
568
 
563
569
  it "raise ArgumentError if params is not a Hash" do
@@ -476,7 +476,7 @@ class RackRequestTest < Minitest::Spec
476
476
 
477
477
  req = make_request \
478
478
  Rack::MockRequest.env_for("/")
479
- req.referer.must_equal nil
479
+ req.referer.must_be_nil
480
480
  end
481
481
 
482
482
  it "extract user agent correctly" do
@@ -486,25 +486,25 @@ class RackRequestTest < Minitest::Spec
486
486
 
487
487
  req = make_request \
488
488
  Rack::MockRequest.env_for("/")
489
- req.user_agent.must_equal nil
489
+ req.user_agent.must_be_nil
490
490
  end
491
491
 
492
492
  it "treat missing content type as nil" do
493
493
  req = make_request \
494
494
  Rack::MockRequest.env_for("/")
495
- req.content_type.must_equal nil
495
+ req.content_type.must_be_nil
496
496
  end
497
497
 
498
498
  it "treat empty content type as nil" do
499
499
  req = make_request \
500
500
  Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
501
- req.content_type.must_equal nil
501
+ req.content_type.must_be_nil
502
502
  end
503
503
 
504
504
  it "return nil media type for empty content type" do
505
505
  req = make_request \
506
506
  Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
507
- req.media_type.must_equal nil
507
+ req.media_type.must_be_nil
508
508
  end
509
509
 
510
510
  it "cache, but invalidates the cache" do
@@ -1296,13 +1296,13 @@ EOF
1296
1296
  req.trusted_proxy?('unix').must_equal 0
1297
1297
  req.trusted_proxy?('unix:/tmp/sock').must_equal 0
1298
1298
 
1299
- req.trusted_proxy?("unix.example.org").must_equal nil
1300
- req.trusted_proxy?("example.org\n127.0.0.1").must_equal nil
1301
- req.trusted_proxy?("127.0.0.1\nexample.org").must_equal nil
1302
- req.trusted_proxy?("11.0.0.1").must_equal nil
1303
- req.trusted_proxy?("172.15.0.1").must_equal nil
1304
- req.trusted_proxy?("172.32.0.1").must_equal nil
1305
- req.trusted_proxy?("2001:470:1f0b:18f8::1").must_equal nil
1299
+ req.trusted_proxy?("unix.example.org").must_be_nil
1300
+ req.trusted_proxy?("example.org\n127.0.0.1").must_be_nil
1301
+ req.trusted_proxy?("127.0.0.1\nexample.org").must_be_nil
1302
+ req.trusted_proxy?("11.0.0.1").must_be_nil
1303
+ req.trusted_proxy?("172.15.0.1").must_be_nil
1304
+ req.trusted_proxy?("172.32.0.1").must_be_nil
1305
+ req.trusted_proxy?("2001:470:1f0b:18f8::1").must_be_nil
1306
1306
  end
1307
1307
 
1308
1308
  it "sets the default session to an empty hash" do
@@ -55,7 +55,7 @@ describe Rack::Response do
55
55
 
56
56
  it "can set and read headers" do
57
57
  response = Rack::Response.new
58
- response["Content-Type"].must_equal nil
58
+ response["Content-Type"].must_be_nil
59
59
  response["Content-Type"] = "text/plain"
60
60
  response["Content-Type"].must_equal "text/plain"
61
61
  end
@@ -273,8 +273,8 @@ describe Rack::Response do
273
273
  _, header, body = r.finish
274
274
  str = ""; body.each { |part| str << part }
275
275
  str.must_be :empty?
276
- header["Content-Type"].must_equal nil
277
- header['Content-Length'].must_equal nil
276
+ header["Content-Type"].must_be_nil
277
+ header['Content-Length'].must_be_nil
278
278
 
279
279
  lambda {
280
280
  Rack::Response.new(Object.new)
@@ -410,7 +410,7 @@ describe Rack::Response do
410
410
  res.body.must_be :closed?
411
411
  end
412
412
 
413
- it "calls close on #body when 204, 205, or 304" do
413
+ it "calls close on #body when 204 or 304" do
414
414
  res = Rack::Response.new
415
415
  res.body = StringIO.new
416
416
  res.finish
@@ -424,7 +424,7 @@ describe Rack::Response do
424
424
  res.body = StringIO.new
425
425
  res.status = 205
426
426
  _, _, b = res.finish
427
- res.body.must_be :closed?
427
+ res.body.wont_be :closed?
428
428
  b.wont_equal res.body
429
429
 
430
430
  res.body = StringIO.new
@@ -77,7 +77,7 @@ describe Rack::Server do
77
77
  o, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], 'foo'
78
78
  server = Rack::Server.new(:app => 'foo')
79
79
  server.server.name =~ /CGI/
80
- Rack::Server.logging_middleware.call(server).must_equal nil
80
+ Rack::Server.logging_middleware.call(server).must_be_nil
81
81
  ensure
82
82
  ENV['REQUEST_METHOD'] = o
83
83
  end
@@ -85,7 +85,7 @@ describe Rack::Server do
85
85
 
86
86
  it "be quiet if said so" do
87
87
  server = Rack::Server.new(:app => "FOO", :quiet => true)
88
- Rack::Server.logging_middleware.call(server).must_equal nil
88
+ Rack::Server.logging_middleware.call(server).must_be_nil
89
89
  end
90
90
 
91
91
  it "use a full path to the pidfile" do
@@ -25,4 +25,21 @@ describe Rack::Session::Abstract::SessionHash do
25
25
  assert_equal [:bar, :qux], hash.values
26
26
  end
27
27
 
28
+ describe "#fetch" do
29
+ it "returns value for a matching key" do
30
+ assert_equal :bar, hash.fetch(:foo)
31
+ end
32
+
33
+ it "works with a default value" do
34
+ assert_equal :default, hash.fetch(:unknown, :default)
35
+ end
36
+
37
+ it "works with a block" do
38
+ assert_equal :default, hash.fetch(:unkown) { :default }
39
+ end
40
+
41
+ it "it raises when fetching unknown keys without defaults" do
42
+ lambda { hash.fetch(:unknown) }.must_raise KeyError
43
+ end
44
+ end
28
45
  end
@@ -98,18 +98,18 @@ describe Rack::Session::Cookie do
98
98
 
99
99
  it 'rescues failures on decode' do
100
100
  coder = Rack::Session::Cookie::Base64::Marshal.new
101
- coder.decode('lulz').must_equal nil
101
+ coder.decode('lulz').must_be_nil
102
102
  end
103
103
  end
104
104
 
105
105
  describe 'JSON' do
106
- it 'marshals and base64 encodes' do
106
+ it 'JSON and base64 encodes' do
107
107
  coder = Rack::Session::Cookie::Base64::JSON.new
108
108
  obj = %w[fuuuuu]
109
109
  coder.encode(obj).must_equal [::JSON.dump(obj)].pack('m')
110
110
  end
111
111
 
112
- it 'marshals and base64 decodes' do
112
+ it 'JSON and base64 decodes' do
113
113
  coder = Rack::Session::Cookie::Base64::JSON.new
114
114
  str = [::JSON.dump(%w[fuuuuu])].pack('m')
115
115
  coder.decode(str).must_equal ::JSON.parse(str.unpack('m').first)
@@ -117,7 +117,7 @@ describe Rack::Session::Cookie do
117
117
 
118
118
  it 'rescues failures on decode' do
119
119
  coder = Rack::Session::Cookie::Base64::JSON.new
120
- coder.decode('lulz').must_equal nil
120
+ coder.decode('lulz').must_be_nil
121
121
  end
122
122
  end
123
123
 
@@ -139,7 +139,7 @@ describe Rack::Session::Cookie do
139
139
 
140
140
  it 'rescues failures on decode' do
141
141
  coder = Rack::Session::Cookie::Base64::ZipJSON.new
142
- coder.decode('lulz').must_equal nil
142
+ coder.decode('lulz').must_be_nil
143
143
  end
144
144
  end
145
145
  end
@@ -143,7 +143,7 @@ begin
143
143
  res1.body.must_equal '{"counter"=>1}'
144
144
 
145
145
  res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
146
- res2["Set-Cookie"].must_equal nil
146
+ res2["Set-Cookie"].must_be_nil
147
147
  res2.body.must_equal '{"counter"=>2}'
148
148
 
149
149
  res3 = req.get("/", "HTTP_COOKIE" => cookie)
@@ -183,7 +183,7 @@ begin
183
183
  creq = Rack::MockRequest.new(count)
184
184
 
185
185
  res0 = dreq.get("/")
186
- res0["Set-Cookie"].must_equal nil
186
+ res0["Set-Cookie"].must_be_nil
187
187
  res0.body.must_equal '{"counter"=>1}'
188
188
 
189
189
  res0 = creq.get("/")
@@ -201,7 +201,7 @@ begin
201
201
  creq = Rack::MockRequest.new(count)
202
202
 
203
203
  res0 = sreq.get("/")
204
- res0["Set-Cookie"].must_equal nil
204
+ res0["Set-Cookie"].must_be_nil
205
205
  res0.body.must_equal '{"counter"=>1}'
206
206
 
207
207
  res0 = creq.get("/")
@@ -138,7 +138,7 @@ describe Rack::Session::Pool do
138
138
  dreq = Rack::MockRequest.new(defer)
139
139
 
140
140
  res1 = dreq.get("/")
141
- res1["Set-Cookie"].must_equal nil
141
+ res1["Set-Cookie"].must_be_nil
142
142
  res1.body.must_equal '{"counter"=>1}'
143
143
  pool.pool.size.must_equal 1
144
144
  end
@@ -97,7 +97,7 @@ describe Rack::Static do
97
97
  it "serves regular files if client accepts gzip encoding and gzip files are not present" do
98
98
  res = @gzip_request.get("/cgi/rackup_stub.rb", 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')
99
99
  res.must_be :ok?
100
- res.headers['Content-Encoding'].must_equal nil
100
+ res.headers['Content-Encoding'].must_be_nil
101
101
  res.headers['Content-Type'].must_equal 'text/x-script.ruby'
102
102
  res.body.must_match(/ruby/)
103
103
  end
@@ -105,7 +105,7 @@ describe Rack::Static do
105
105
  it "serves regular files if client does not accept gzip encoding" do
106
106
  res = @gzip_request.get("/cgi/test")
107
107
  res.must_be :ok?
108
- res.headers['Content-Encoding'].must_equal nil
108
+ res.headers['Content-Encoding'].must_be_nil
109
109
  res.headers['Content-Type'].must_equal 'text/plain'
110
110
  res.body.must_match(/ruby/)
111
111
  end
@@ -394,7 +394,7 @@ describe Rack::Utils do
394
394
  Rack::Utils.best_q_match("text/plain,text/html", %w[text/html text/plain]).must_equal "text/html"
395
395
 
396
396
  # When there are no matches, return nil:
397
- Rack::Utils.best_q_match("application/json", %w[text/html text/plain]).must_equal nil
397
+ Rack::Utils.best_q_match("application/json", %w[text/html text/plain]).must_be_nil
398
398
  end
399
399
 
400
400
  it "escape html entities [&><'\"/]" do
@@ -427,9 +427,9 @@ describe Rack::Utils do
427
427
  Rack::Utils.select_best_encoding(a, b)
428
428
  end
429
429
 
430
- helper.call(%w(), [["x", 1]]).must_equal nil
431
- helper.call(%w(identity), [["identity", 0.0]]).must_equal nil
432
- helper.call(%w(identity), [["*", 0.0]]).must_equal nil
430
+ helper.call(%w(), [["x", 1]]).must_be_nil
431
+ helper.call(%w(identity), [["identity", 0.0]]).must_be_nil
432
+ helper.call(%w(identity), [["*", 0.0]]).must_be_nil
433
433
 
434
434
  helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).must_equal "identity"
435
435
 
@@ -538,15 +538,15 @@ end
538
538
 
539
539
  describe Rack::Utils, "byte_range" do
540
540
  it "ignore missing or syntactically invalid byte ranges" do
541
- Rack::Utils.byte_ranges({},500).must_equal nil
542
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).must_equal nil
543
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).must_equal nil
544
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).must_equal nil
545
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).must_equal nil
546
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).must_equal nil
541
+ Rack::Utils.byte_ranges({},500).must_be_nil
542
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).must_be_nil
543
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).must_be_nil
544
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).must_be_nil
545
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).must_be_nil
546
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).must_be_nil
547
547
  # A range of non-positive length is syntactically invalid and ignored:
548
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).must_equal nil
549
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).must_equal nil
548
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).must_be_nil
549
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).must_be_nil
550
550
  end
551
551
 
552
552
  it "parse simple byte ranges" do
@@ -1,5 +1,6 @@
1
1
  require 'minitest/autorun'
2
2
  require 'rack/mock'
3
+ require 'concurrent/utility/native_integer'
3
4
  require 'concurrent/atomic/count_down_latch'
4
5
  require File.expand_path('../testrequest', __FILE__)
5
6
 
@@ -171,7 +172,7 @@ describe Rack::Handler::WEBrick do
171
172
  Rack::Lint.new(lambda{ |req|
172
173
  [
173
174
  200,
174
- {"rack.hijack" => io_lambda},
175
+ [ [ "rack.hijack", io_lambda ] ],
175
176
  [""]
176
177
  ]
177
178
  })
@@ -195,7 +196,7 @@ describe Rack::Handler::WEBrick do
195
196
  Net::HTTP.start(@host, @port){ |http|
196
197
  res = http.get("/chunked")
197
198
  res["Transfer-Encoding"].must_equal "chunked"
198
- res["Content-Length"].must_equal nil
199
+ res["Content-Length"].must_be_nil
199
200
  res.body.must_equal "chunked"
200
201
  }
201
202
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Neukirchen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-30 00:00:00.000000000 Z
11
+ date: 2017-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -191,6 +191,7 @@ files:
191
191
  - test/multipart/filename_with_encoded_words
192
192
  - test/multipart/filename_with_escaped_quotes
193
193
  - test/multipart/filename_with_escaped_quotes_and_modification_param
194
+ - test/multipart/filename_with_null_byte
194
195
  - test/multipart/filename_with_percent_escaped_quotes
195
196
  - test/multipart/filename_with_single_quote
196
197
  - test/multipart/filename_with_unescaped_percentages
@@ -288,7 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
288
289
  version: '0'
289
290
  requirements: []
290
291
  rubyforge_project:
291
- rubygems_version: 2.6.6
292
+ rubygems_version: 2.6.8
292
293
  signing_key:
293
294
  specification_version: 4
294
295
  summary: a modular Ruby webserver interface
@@ -344,4 +345,3 @@ test_files:
344
345
  - test/spec_utils.rb
345
346
  - test/spec_version.rb
346
347
  - test/spec_webrick.rb
347
- has_rdoc: