diff options
-rw-r--r-- | lib/rack.rb | 2 | ||||
-rw-r--r-- | lib/rack/auth/abstract/request.rb | 6 | ||||
-rw-r--r-- | lib/rack/handler/webrick.rb | 8 | ||||
-rw-r--r-- | lib/rack/multipart/parser.rb | 2 | ||||
-rw-r--r-- | lib/rack/query_parser.rb | 15 | ||||
-rw-r--r-- | lib/rack/session/abstract/id.rb | 14 | ||||
-rw-r--r-- | rack.gemspec | 6 | ||||
-rw-r--r-- | test/multipart/filename_with_null_byte | 7 | ||||
-rw-r--r-- | test/spec_auth_basic.rb | 7 | ||||
-rw-r--r-- | test/spec_multipart.rb | 6 | ||||
-rw-r--r-- | test/spec_session_abstract_session_hash.rb | 17 | ||||
-rw-r--r-- | test/spec_utils.rb | 12 | ||||
-rw-r--r-- | test/spec_webrick.rb | 2 |
13 files changed, 88 insertions, 16 deletions
diff --git a/lib/rack.rb b/lib/rack.rb index 00621178..f1417d2d 100644 --- a/lib/rack.rb +++ b/lib/rack.rb @@ -18,7 +18,7 @@ module Rack VERSION.join(".") end - RELEASE = "2.0.0.rc1" + RELEASE = "2.0.1" # Return the Rack release as a dotted string. def self.release diff --git a/lib/rack/auth/abstract/request.rb b/lib/rack/auth/abstract/request.rb index 80d1c272..b738cc98 100644 --- a/lib/rack/auth/abstract/request.rb +++ b/lib/rack/auth/abstract/request.rb @@ -13,7 +13,11 @@ module Rack end def provided? - !authorization_key.nil? + !authorization_key.nil? && valid? + end + + def valid? + !@env[authorization_key].nil? end def parts diff --git a/lib/rack/handler/webrick.rb b/lib/rack/handler/webrick.rb index 95aa8927..d0fcd213 100644 --- a/lib/rack/handler/webrick.rb +++ b/lib/rack/handler/webrick.rb @@ -86,10 +86,11 @@ module Rack status, headers, body = @app.call(env) begin res.status = status.to_i + io_lambda = nil headers.each { |k, vs| - next if k.downcase == RACK_HIJACK - - if k.downcase == "set-cookie" + if k == RACK_HIJACK + io_lambda = vs + elsif k.downcase == "set-cookie" res.cookies.concat vs.split("\n") else # Since WEBrick won't accept repeated headers, @@ -98,7 +99,6 @@ module Rack end } - io_lambda = headers[RACK_HIJACK] if io_lambda rd, wr = IO.pipe res.body = rd diff --git a/lib/rack/multipart/parser.rb b/lib/rack/multipart/parser.rb index 74a7ee67..d8cb3670 100644 --- a/lib/rack/multipart/parser.rb +++ b/lib/rack/multipart/parser.rb @@ -8,7 +8,7 @@ module Rack BUFSIZE = 16384 TEXT_PLAIN = "text/plain" TEMPFILE_FACTORY = lambda { |filename, content_type| - Tempfile.new(["RackMultipart", ::File.extname(filename)]) + Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0".freeze, '%00'.freeze))]) } class BoundedIO # :nodoc: diff --git a/lib/rack/query_parser.rb b/lib/rack/query_parser.rb index 17b77128..be74bc06 100644 --- a/lib/rack/query_parser.rb +++ b/lib/rack/query_parser.rb @@ -102,8 +102,7 @@ module Rack child_key = $1 params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - first_key = child_key.gsub(/[\[\]]/, ' ').split.first - if params_hash_type?(params[k].last) && !params[k].last.key?(first_key) + if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key) normalize_params(params[k].last, child_key, v, depth - 1) else params[k] << normalize_params(make_params, child_key, v, depth - 1) @@ -135,6 +134,18 @@ module Rack obj.kind_of?(@params_class) end + def params_hash_has_key?(hash, key) + return false if key =~ /\[\]/ + + key.split(/[\[\]]+/).inject(hash) do |h, part| + next h if part == '' + return false unless params_hash_type?(h) && h.key?(part) + h[part] + end + + true + end + def unescape(s) Utils.unescape(s) end diff --git a/lib/rack/session/abstract/id.rb b/lib/rack/session/abstract/id.rb index 204bdb34..ca1a2628 100644 --- a/lib/rack/session/abstract/id.rb +++ b/lib/rack/session/abstract/id.rb @@ -18,6 +18,8 @@ module Rack include Enumerable attr_writer :id + Unspecified = Object.new + def self.find(req) req.get_header RACK_SESSION end @@ -54,7 +56,15 @@ module Rack load_for_read! @data[key.to_s] end - alias :fetch :[] + + def fetch(key, default=Unspecified, &block) + load_for_read! + if default == Unspecified + @data.fetch(key.to_s, &block) + else + @data.fetch(key.to_s, default, &block) + end + end def has_key?(key) load_for_read! @@ -200,7 +210,7 @@ module Rack :sidbits => 128, :cookie_only => true, :secure_random => ::SecureRandom - } + }.freeze attr_reader :key, :default_options, :sid_secure diff --git a/rack.gemspec b/rack.gemspec index 1b412793..259ae3ab 100644 --- a/rack.gemspec +++ b/rack.gemspec @@ -23,13 +23,11 @@ EOF s.extra_rdoc_files = ['README.rdoc', 'HISTORY.md'] s.test_files = Dir['test/spec_*.rb'] - s.author = 'Christian Neukirchen' - s.email = 'chneukirchen@gmail.com' + s.author = 'Aaron Patterson' + s.email = 'tenderlove@ruby-lang.org' s.homepage = 'http://rack.github.io/' s.required_ruby_version = '>= 2.2.2' - s.add_dependency 'json' - s.add_development_dependency 'minitest', "~> 5.0" s.add_development_dependency 'minitest-sprint' s.add_development_dependency 'concurrent-ruby' diff --git a/test/multipart/filename_with_null_byte b/test/multipart/filename_with_null_byte new file mode 100644 index 00000000..961d44c4 --- /dev/null +++ b/test/multipart/filename_with_null_byte @@ -0,0 +1,7 @@ +--AaB03x
+Content-Type: image/jpeg
+Content-Disposition: attachment; name="files"; filename="flowers.exe%00.jpg"
+Content-Description: a complete map of the human genome
+
+contents
+--AaB03x--
diff --git a/test/spec_auth_basic.rb b/test/spec_auth_basic.rb index 1e19bf66..45d28576 100644 --- a/test/spec_auth_basic.rb +++ b/test/spec_auth_basic.rb @@ -75,6 +75,13 @@ describe Rack::Auth::Basic do end end + it 'return 401 Bad Request for a nil authorization header' do + request 'HTTP_AUTHORIZATION' => nil do |response| + response.must_be :client_error? + response.status.must_equal 401 + end + end + it 'takes realm as optional constructor arg' do app = Rack::Auth::Basic.new(unprotected_app, realm) { true } realm.must_equal app.realm diff --git a/test/spec_multipart.rb b/test/spec_multipart.rb index 80e49ccb..02b86bed 100644 --- a/test/spec_multipart.rb +++ b/test/spec_multipart.rb @@ -305,6 +305,12 @@ describe Rack::Multipart do params["files"][:filename].must_equal "bob's flowers.jpg" end + it "parse multipart form with a null byte in the filename" do + env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_null_byte) + params = Rack::Multipart.parse_multipart(env) + params["files"][:filename].must_equal "flowers.exe\u0000.jpg" + end + it "not include file params if no file was selected" do env = Rack::MockRequest.env_for("/", multipart_fixture(:none)) params = Rack::Multipart.parse_multipart(env) diff --git a/test/spec_session_abstract_session_hash.rb b/test/spec_session_abstract_session_hash.rb index 6d73a80a..76b34a01 100644 --- a/test/spec_session_abstract_session_hash.rb +++ b/test/spec_session_abstract_session_hash.rb @@ -25,4 +25,21 @@ describe Rack::Session::Abstract::SessionHash do assert_equal [:bar, :qux], hash.values end + describe "#fetch" do + it "returns value for a matching key" do + assert_equal :bar, hash.fetch(:foo) + end + + it "works with a default value" do + assert_equal :default, hash.fetch(:unknown, :default) + end + + it "works with a block" do + assert_equal :default, hash.fetch(:unkown) { :default } + end + + it "it raises when fetching unknown keys without defaults" do + lambda { hash.fetch(:unknown) }.must_raise KeyError + end + end end diff --git a/test/spec_utils.rb b/test/spec_utils.rb index b24762c9..e5d4d244 100644 --- a/test/spec_utils.rb +++ b/test/spec_utils.rb @@ -231,6 +231,18 @@ describe Rack::Utils do message.must_equal "invalid byte sequence in UTF-8" end + it "only moves to a new array when the full key has been seen" do + Rack::Utils.parse_nested_query("x[][y][][z]=1&x[][y][][w]=2"). + must_equal "x" => [{"y" => [{"z" => "1", "w" => "2"}]}] + + Rack::Utils.parse_nested_query( + "x[][id]=1&x[][y][a]=5&x[][y][b]=7&x[][z][id]=3&x[][z][w]=0&x[][id]=2&x[][y][a]=6&x[][y][b]=8&x[][z][id]=4&x[][z][w]=0" + ).must_equal "x" => [ + {"id" => "1", "y" => {"a" => "5", "b" => "7"}, "z" => {"id" => "3", "w" => "0"}}, + {"id" => "2", "y" => {"a" => "6", "b" => "8"}, "z" => {"id" => "4", "w" => "0"}}, + ] + end + it "allow setting the params hash class to use for parsing query strings" do begin default_parser = Rack::Utils.default_query_parser diff --git a/test/spec_webrick.rb b/test/spec_webrick.rb index 9ae6103d..4a10c1ca 100644 --- a/test/spec_webrick.rb +++ b/test/spec_webrick.rb @@ -171,7 +171,7 @@ describe Rack::Handler::WEBrick do Rack::Lint.new(lambda{ |req| [ 200, - {"rack.hijack" => io_lambda}, + [ [ "rack.hijack", io_lambda ] ], [""] ] }) |