diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2015-09-04 17:33:45 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2015-09-04 17:33:45 -0700 |
commit | b2d73960e9ea6b8b15321ef190f13a290d1aedf0 (patch) | |
tree | 86ade50f1fbae3dbcb7b048bd3157f053dabd330 | |
parent | 7f1fcde28785051886b9d88dc66db32c932d94d2 (diff) | |
download | rack-b2d73960e9ea6b8b15321ef190f13a290d1aedf0.tar.gz |
pull env access in the request object to a module
this also tests that delegation to the request object is possible. I want to see exactly how many methods we need to delegate in order to look like a real request object
-rw-r--r-- | HISTORY.md | 6 | ||||
-rw-r--r-- | lib/rack/mock.rb | 4 | ||||
-rw-r--r-- | lib/rack/multipart.rb | 3 | ||||
-rw-r--r-- | lib/rack/request.rb | 164 | ||||
-rw-r--r-- | lib/rack/utils.rb | 3 | ||||
-rw-r--r-- | test/spec_multipart.rb | 8 | ||||
-rw-r--r-- | test/spec_request.rb | 329 |
7 files changed, 289 insertions, 228 deletions
@@ -1,3 +1,9 @@ +Fri Sep 4 17:32:12 2015 Aaron Patterson <tenderlove@ruby-lang.org> + + * Pull `ENV` access inside the request object in to a module. This + will help with legacy Request objects that are ENV based but don't + want to inherit from Rack::Request + Fri Sep 4 16:09:11 2015 Aaron Patterson <tenderlove@ruby-lang.org> * Move most methods on the `Rack::Request` to a module diff --git a/lib/rack/mock.rb b/lib/rack/mock.rb index 0002bfe4..a2fc2401 100644 --- a/lib/rack/mock.rb +++ b/lib/rack/mock.rb @@ -115,10 +115,10 @@ module Rack elsif !opts.has_key?(:input) opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" if params.is_a?(Hash) - if data = Utils::Multipart.build_multipart(params) + if data = Rack::Multipart.build_multipart(params) opts[:input] = data opts["CONTENT_LENGTH"] ||= data.length.to_s - opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}" else opts[:input] = Utils.build_nested_query(params) end diff --git a/lib/rack/multipart.rb b/lib/rack/multipart.rb index 748fba00..12c3917b 100644 --- a/lib/rack/multipart.rb +++ b/lib/rack/multipart.rb @@ -1,10 +1,11 @@ +require 'rack/multipart/parser' + module Rack # A multipart form data parser, adapted from IOWA. # # Usually, Rack::Request#POST takes care of calling this. module Multipart autoload :UploadedFile, 'rack/multipart/uploaded_file' - autoload :Parser, 'rack/multipart/parser' autoload :Generator, 'rack/multipart/generator' EOL = "\r\n" diff --git a/lib/rack/request.rb b/lib/rack/request.rb index c0c921d4..afa5d590 100644 --- a/lib/rack/request.rb +++ b/lib/rack/request.rb @@ -11,72 +11,11 @@ module Rack # req.params["data"] class Request - HTTP_X_FORWARDED_SCHEME = 'HTTP_X_FORWARDED_SCHEME'.freeze - HTTP_X_FORWARDED_PROTO = 'HTTP_X_FORWARDED_PROTO'.freeze - HTTP_X_FORWARDED_HOST = 'HTTP_X_FORWARDED_HOST'.freeze - HTTP_X_FORWARDED_PORT = 'HTTP_X_FORWARDED_PORT'.freeze - HTTP_X_FORWARDED_SSL = 'HTTP_X_FORWARDED_SSL'.freeze - - # The environment of the request. - attr_reader :env - def initialize(env) - @env = env - super() - end - - # Get a request specific value for `name`. - def get_header(name) - @env[name] - end - - # If a block is given, it yields to the block if the value hasn't been set - # on the request. - def fetch_header(name, &block) - @env.fetch(name, &block) - end - - # Delete a request specific value for `name`. - def delete_header(name) - @env.delete name - end - - # Set a request specific value for `name` to `v` - def set_header(name, v) - @env[name] = v + @params = nil + super(env) end - # Predicate method to test to see if `name` has been set as request - # specific data - def has_header?(name) - @env.key? name - end - - # Loops through each key / value pair in the request specific data. - def each_header(&block) - @env.each(&block) - end - - # The set of form-data media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for form-data / param parsing. - FORM_DATA_MEDIA_TYPES = [ - 'application/x-www-form-urlencoded', - 'multipart/form-data' - ] - - # The set of media-types. Requests that do not indicate - # one of the media types presents in this list will not be eligible - # for param parsing like soap attachments or generic multiparts - PARSEABLE_DATA_MEDIA_TYPES = [ - 'multipart/related', - 'multipart/mixed' - ] - - # Default ports depending on scheme. Used to decide whether or not - # to include the port in a generated URI. - DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 } - # shortcut for request.params[key] def [](key) params[key.to_s] @@ -94,15 +33,94 @@ module Rack keys.map{|key| params[key] } end - def initialize_copy(other) - @env = other.env.dup + def params + @params ||= super end - module Helpers - def initialize - @params = nil + def update_param(k, v) + super + @params = nil + end + + def delete_param(k) + v = super + @params = nil + v + end + + module Env + # The environment of the request. + attr_reader :env + + def initialize(env) + @env = env + super() + end + + # Get a request specific value for `name`. + def get_header(name) + @env[name] + end + + # If a block is given, it yields to the block if the value hasn't been set + # on the request. + def fetch_header(name, &block) + @env.fetch(name, &block) + end + + # Delete a request specific value for `name`. + def delete_header(name) + @env.delete name + end + + # Set a request specific value for `name` to `v` + def set_header(name, v) + @env[name] = v end + # Predicate method to test to see if `name` has been set as request + # specific data + def has_header?(name) + @env.key? name + end + + # Loops through each key / value pair in the request specific data. + def each_header(&block) + @env.each(&block) + end + + def initialize_copy(other) + @env = other.env.dup + end + end + + module Helpers + # The set of form-data media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for form-data / param parsing. + FORM_DATA_MEDIA_TYPES = [ + 'application/x-www-form-urlencoded', + 'multipart/form-data' + ] + + # The set of media-types. Requests that do not indicate + # one of the media types presents in this list will not be eligible + # for param parsing like soap attachments or generic multiparts + PARSEABLE_DATA_MEDIA_TYPES = [ + 'multipart/related', + 'multipart/mixed' + ] + + # Default ports depending on scheme. Used to decide whether or not + # to include the port in a generated URI. + DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 } + + HTTP_X_FORWARDED_SCHEME = 'HTTP_X_FORWARDED_SCHEME'.freeze + HTTP_X_FORWARDED_PROTO = 'HTTP_X_FORWARDED_PROTO'.freeze + HTTP_X_FORWARDED_HOST = 'HTTP_X_FORWARDED_HOST'.freeze + HTTP_X_FORWARDED_PORT = 'HTTP_X_FORWARDED_PORT'.freeze + HTTP_X_FORWARDED_SSL = 'HTTP_X_FORWARDED_SSL'.freeze + def body; get_header(RACK_INPUT) end def script_name; get_header(SCRIPT_NAME).to_s end def script_name=(s); set_header(SCRIPT_NAME, s.to_s) end @@ -319,7 +337,7 @@ module Rack get_header(RACK_INPUT).rewind end - set_header RACK_REQUEST_FORM_INPUT, @env[RACK_INPUT] + set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT) get_header RACK_REQUEST_FORM_HASH else {} @@ -330,7 +348,7 @@ module Rack # # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params. def params - @params ||= self.GET.merge(self.POST) + self.GET.merge(self.POST) rescue EOFError self.GET.dup end @@ -353,7 +371,6 @@ module Rack unless found self.GET[k] = v end - @params = nil end # Destructively delete a parameter, whether it's in GET or POST. Returns the value of the deleted parameter. @@ -362,9 +379,7 @@ module Rack # # env['rack.input'] is not touched. def delete_param(k) - v = [ self.POST.delete(k), self.GET.delete(k) ].compact.first - @params = nil - v + [ self.POST.delete(k), self.GET.delete(k) ].compact.first end def base_url @@ -432,6 +447,7 @@ module Rack end end + include Env include Helpers end end diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb index 05b50921..cc4d1ba8 100644 --- a/lib/rack/utils.rb +++ b/lib/rack/utils.rb @@ -2,7 +2,6 @@ require 'fileutils' require 'set' require 'tempfile' -require 'rack/multipart' require 'rack/query_parser' require 'time' @@ -570,8 +569,6 @@ module Rack end module_function :status_code - Multipart = Rack::Multipart - PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact) def clean_path_info(path_info) diff --git a/test/spec_multipart.rb b/test/spec_multipart.rb index 1f4c69fd..cfe508c1 100644 --- a/test/spec_multipart.rb +++ b/test/spec_multipart.rb @@ -306,7 +306,7 @@ describe Rack::Multipart do it "parse multipart/mixed" do env = Rack::MockRequest.env_for("/", multipart_fixture(:mixed_files)) - params = Rack::Utils::Multipart.parse_multipart(env) + params = Rack::Multipart.parse_multipart(env) params["foo"].must_equal "bar" params["files"].must_be_instance_of String params["files"].size.must_equal 252 @@ -572,7 +572,7 @@ EOF :input => StringIO.new(data) } env = Rack::MockRequest.env_for("/", options) - params = Rack::Utils::Multipart.parse_multipart(env) + params = Rack::Multipart.parse_multipart(env) params.must_equal "description"=>"Very very blue" end @@ -601,7 +601,7 @@ contents\r :input => StringIO.new(data) } env = Rack::MockRequest.env_for("/", options) - params = Rack::Utils::Multipart.parse_multipart(env) + params = Rack::Multipart.parse_multipart(env) params["file"][:filename].must_equal 'long' * 100 end @@ -655,7 +655,7 @@ Content-Type: image/png\r :input => StringIO.new(data) } env = Rack::MockRequest.env_for("/", options) - params = Rack::Utils::Multipart.parse_multipart(env) + params = Rack::Multipart.parse_multipart(env) params["text/plain"].must_equal ["some text", "some more text (I didn't specify Content-Type)"] params["image/png"].length.must_equal 1 diff --git a/test/spec_request.rb b/test/spec_request.rb index 8b56b7f2..44fcfd45 100644 --- a/test/spec_request.rb +++ b/test/spec_request.rb @@ -6,19 +6,19 @@ require 'rack/mock' require 'rack/multipart' require 'securerandom' -describe Rack::Request do +class RackRequestTest < Minitest::Spec it "copies the env when duping" do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) refute_same req.env, req.dup.env end it "can get a key from the env" do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) assert_equal "example.com", req.get_header("SERVER_NAME") end it 'yields to the block if no value has been set' do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) yielded = false req.fetch_header("FOO") do yielded = true @@ -30,18 +30,18 @@ describe Rack::Request do end it 'can set values in the env' do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) req.set_header("FOO", "BAR") assert_equal "BAR", req.get_header("FOO") end it 'can check if something has been set' do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) refute req.has_header?("FOO") end it 'can iterate over values' do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) req.set_header 'foo', 'bar' hash = {} req.each_header do |k,v| @@ -51,7 +51,7 @@ describe Rack::Request do end it 'can delete env values' do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) req.set_header 'foo', 'bar' assert req.has_header? 'foo' req.delete_header 'foo' @@ -59,7 +59,7 @@ describe Rack::Request do end it "wrap the rack variables" do - req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + req = make_request(Rack::MockRequest.env_for("http://example.com:8080/")) req.body.must_respond_to :gets req.scheme.must_equal "http" @@ -84,103 +84,103 @@ describe Rack::Request do end it "figure out the correct host" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org") req.host.must_equal "www2.example.org" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292") req.host.must_equal "example.org" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292") req.host.must_equal "example.org" env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292") env.delete("SERVER_NAME") - req = Rack::Request.new(env) + req = make_request(env) req.host.must_equal "192.168.1.1" env = Rack::MockRequest.env_for("/") env.delete("SERVER_NAME") - req = Rack::Request.new(env) + req = make_request(env) req.host.must_equal "" end it "figure out the correct port" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org") req.port.must_equal 80 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org:81") req.port.must_equal 81 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292") req.port.must_equal 9292 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292") req.port.must_equal 9292 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org") req.port.must_equal 80 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_SSL" => "on") req.port.must_equal 443 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PROTO" => "https") req.port.must_equal 443 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PORT" => "9393") req.port.must_equal 9393 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9393", "SERVER_PORT" => "80") req.port.must_equal 9393 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393") req.port.must_equal 80 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https", "SERVER_PORT" => "80") req.port.must_equal 443 - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https,https", "SERVER_PORT" => "80") req.port.must_equal 443 end it "figure out the correct host with port" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org") req.host_with_port.must_equal "www2.example.org" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81") req.host_with_port.must_equal "localhost:81" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292") req.host_with_port.must_equal "example.org:9292" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292") req.host_with_port.must_equal "example.org:9292" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393") req.host_with_port.must_equal "example.org" end it "parse the query string" do - req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla")) + req = make_request(Rack::MockRequest.env_for("/?foo=bar&quux=bla")) req.query_string.must_equal "foo=bar&quux=bla" req.GET.must_equal "foo" => "bar", "quux" => "bla" req.POST.must_be :empty? @@ -191,7 +191,7 @@ describe Rack::Request do mr = Rack::MockRequest.env_for("/", "REQUEST_METHOD" => 'POST', :input => "foo=bar&quux=b;la") - req = Rack::Request.new mr + req = make_request mr req.query_string.must_equal "" req.GET.must_be :empty? req.POST.must_equal "foo" => "bar", "quux" => "b;la" @@ -219,7 +219,7 @@ describe Rack::Request do end it "use semi-colons as separators for query strings in GET" do - req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=b;la;wun=duh")) + req = make_request(Rack::MockRequest.env_for("/?foo=bar&quux=b;la;wun=duh")) req.query_string.must_equal "foo=bar&quux=b;la;wun=duh" req.GET.must_equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh" req.POST.must_be :empty? @@ -231,7 +231,7 @@ describe Rack::Request do old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1 begin - req = Rack::Request.new(env) + req = make_request(env) lambda { req.GET }.must_raise RangeError ensure Rack::Utils.key_space_limit = old @@ -245,8 +245,8 @@ describe Rack::Request do old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 3 begin exp = {"foo"=>{"bar"=>{"baz"=>{"qux"=>"1"}}}} - Rack::Request.new(nested_query).GET.must_equal exp - lambda { Rack::Request.new(plain_query).GET }.must_raise RangeError + make_request(nested_query).GET.must_equal exp + lambda { make_request(plain_query).GET }.must_raise RangeError ensure Rack::Utils.key_space_limit = old end @@ -257,7 +257,7 @@ describe Rack::Request do "REQUEST_METHOD" => 'POST', :input => "foo=bar&quux=bla" ) - req = Rack::Request.new mr + req = make_request mr req.params @@ -299,19 +299,19 @@ describe Rack::Request do "REQUEST_METHOD" => 'POST', :input => "a%=1" ) - req = Rack::Request.new mr + req = make_request mr lambda { req.POST }.must_raise(Rack::Utils::InvalidParameterError). message.must_equal "invalid %-encoding (a%)" end it "raise if rack.input is missing" do - req = Rack::Request.new({}) + req = make_request({}) lambda { req.POST }.must_raise RuntimeError end it "parse POST data when method is POST and no Content-Type given" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/?foo=quux", "REQUEST_METHOD" => 'POST', :input => "foo=bar&quux=bla") @@ -330,7 +330,7 @@ describe Rack::Request do old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1 begin - req = Rack::Request.new(env) + req = make_request(env) lambda { req.POST }.must_raise RangeError ensure Rack::Utils.key_space_limit = old @@ -338,7 +338,7 @@ describe Rack::Request do end it "parse POST data with explicit content type regardless of method" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar', :input => "foo=bar&quux=bla") @@ -350,7 +350,7 @@ describe Rack::Request do end it "not parse POST data when media type is not form-data" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/?foo=quux", "REQUEST_METHOD" => 'POST', "CONTENT_TYPE" => 'text/plain;charset=utf-8', @@ -364,7 +364,7 @@ describe Rack::Request do end it "parse POST data on PUT when media type is form-data" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/?foo=quux", "REQUEST_METHOD" => 'PUT', "CONTENT_TYPE" => 'application/x-www-form-urlencoded', @@ -375,7 +375,7 @@ describe Rack::Request do it "rewind input after parsing POST data" do input = StringIO.new("foo=bar&quux=bla") - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar', :input => input) @@ -390,7 +390,7 @@ describe Rack::Request do "CONTENT_LENGTH" => '0', :input => nil) - req = Rack::Request.new mr + req = make_request mr req.query_string.must_equal "" req.GET.must_be :empty? req.POST.must_be :empty? @@ -398,26 +398,30 @@ describe Rack::Request do end it "clean up Safari's ajax POST body" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", 'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0") req.POST.must_equal "foo" => "bar", "quux" => "bla" end it "get value by key from params with #[]" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("?foo=quux") req['foo'].must_equal 'quux' req[:foo].must_equal 'quux' end it "set value to key on params with #[]=" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("?foo=duh") req['foo'].must_equal 'duh' req[:foo].must_equal 'duh' req.params.must_equal 'foo' => 'duh' + if req.delegate? + skip "delegate requests don't cache params, so mutations have no impact" + end + req['foo'] = 'bar' req.params.must_equal 'foo' => 'bar' req['foo'].must_equal 'bar' @@ -430,7 +434,7 @@ describe Rack::Request do end it "return values for the keys in the order given from values_at" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful") req.values_at('foo').must_equal ['baz'] req.values_at('foo', 'wun').must_equal ['baz', 'der'] @@ -438,119 +442,119 @@ describe Rack::Request do end it "extract referrer correctly" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path") req.referer.must_equal "/some/path" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/") req.referer.must_equal nil end it "extract user agent correctly" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)") req.user_agent.must_equal "Mozilla/4.0 (compatible)" - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/") req.user_agent.must_equal nil end it "treat missing content type as nil" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/") req.content_type.must_equal nil end it "treat empty content type as nil" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "") req.content_type.must_equal nil end it "return nil media type for empty content type" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "") req.media_type.must_equal nil end it "cache, but invalidates the cache" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/?foo=quux", "CONTENT_TYPE" => "application/x-www-form-urlencoded", :input => "foo=bar&quux=bla") req.GET.must_equal "foo" => "quux" req.GET.must_equal "foo" => "quux" - req.env["QUERY_STRING"] = "bla=foo" + req.set_header("QUERY_STRING", "bla=foo") req.GET.must_equal "bla" => "foo" req.GET.must_equal "bla" => "foo" req.POST.must_equal "foo" => "bar", "quux" => "bla" req.POST.must_equal "foo" => "bar", "quux" => "bla" - req.env["rack.input"] = StringIO.new("foo=bla&quux=bar") + req.set_header("rack.input", StringIO.new("foo=bla&quux=bar")) req.POST.must_equal "foo" => "bla", "quux" => "bar" req.POST.must_equal "foo" => "bla", "quux" => "bar" end it "figure out if called via XHR" do - req = Rack::Request.new(Rack::MockRequest.env_for("")) + req = make_request(Rack::MockRequest.env_for("")) req.wont_be :xhr? - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest") req.must_be :xhr? end it "ssl detection" do - request = Rack::Request.new(Rack::MockRequest.env_for("/")) + request = make_request(Rack::MockRequest.env_for("/")) request.scheme.must_equal "http" request.wont_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTPS' => 'on')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTPS' => 'on')) request.scheme.must_equal "https" request.must_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https')) + request = make_request(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https')) request.scheme.must_equal "https" request.must_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8080')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8080')) request.scheme.must_equal "http" request.wont_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on')) request.scheme.must_equal "https" request.must_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTP_X_FORWARDED_SSL' => 'on')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTP_X_FORWARDED_SSL' => 'on')) request.scheme.must_equal "https" request.must_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'https')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'https')) request.scheme.must_equal "https" request.must_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https')) request.scheme.must_equal "https" request.must_be :ssl? - request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https, http, http')) + request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https, http, http')) request.scheme.must_equal "https" request.must_be :ssl? end it "parse cookies" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m") req.cookies.must_equal "foo" => "bar", "quux" => "h&m" req.cookies.must_equal "foo" => "bar", "quux" => "h&m" - req.env.delete("HTTP_COOKIE") + req.delete_header("HTTP_COOKIE") req.cookies.must_equal({}) end it "always return the same hash object" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m") hash = req.cookies req.env.delete("HTTP_COOKIE") @@ -560,7 +564,7 @@ describe Rack::Request do end it "modify the cookies hash in place" do - req = Rack::Request.new(Rack::MockRequest.env_for("")) + req = make_request(Rack::MockRequest.env_for("")) req.cookies.must_equal({}) req.cookies['foo'] = 'bar' req.cookies.must_equal 'foo' => 'bar' @@ -568,47 +572,50 @@ describe Rack::Request do it "not modify the params hash in place" do e = Rack::MockRequest.env_for("") - req1 = Rack::Request.new(e) + req1 = make_request(e) + if req1.delegate? + skip "delegate requests don't cache params, so mutations have no impact" + end req1.params.must_equal({}) req1.params['foo'] = 'bar' req1.params.must_equal 'foo' => 'bar' - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.params.must_equal({}) end it "modify params hash if param is in GET" do e = Rack::MockRequest.env_for("?foo=duh") - req1 = Rack::Request.new(e) + req1 = make_request(e) req1.params.must_equal 'foo' => 'duh' req1.update_param 'foo', 'bar' req1.params.must_equal 'foo' => 'bar' - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.params.must_equal 'foo' => 'bar' end it "modify params hash if param is in POST" do e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh') - req1 = Rack::Request.new(e) + req1 = make_request(e) req1.params.must_equal 'foo' => 'duh' req1.update_param 'foo', 'bar' req1.params.must_equal 'foo' => 'bar' - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.params.must_equal 'foo' => 'bar' end it "modify params hash, even if param didn't exist before" do e = Rack::MockRequest.env_for("") - req1 = Rack::Request.new(e) + req1 = make_request(e) req1.params.must_equal({}) req1.update_param 'foo', 'bar' req1.params.must_equal 'foo' => 'bar' - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.params.must_equal 'foo' => 'bar' end it "modify params hash by changing only GET" do e = Rack::MockRequest.env_for("?foo=duhget") - req = Rack::Request.new(e) + req = make_request(e) req.GET.must_equal 'foo' => 'duhget' req.POST.must_equal({}) req.update_param 'foo', 'bar' @@ -618,7 +625,7 @@ describe Rack::Request do it "modify params hash by changing only POST" do e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost") - req = Rack::Request.new(e) + req = make_request(e) req.GET.must_equal({}) req.POST.must_equal 'foo' => 'duhpost' req.update_param 'foo', 'bar' @@ -628,7 +635,7 @@ describe Rack::Request do it "modify params hash, even if param is defined in both POST and GET" do e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost") - req1 = Rack::Request.new(e) + req1 = make_request(e) req1.GET.must_equal 'foo' => 'duhget' req1.POST.must_equal 'foo' => 'duhpost' req1.params.must_equal 'foo' => 'duhpost' @@ -636,7 +643,7 @@ describe Rack::Request do req1.GET.must_equal 'foo' => 'bar' req1.POST.must_equal 'foo' => 'bar' req1.params.must_equal 'foo' => 'bar' - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.GET.must_equal 'foo' => 'bar' req2.POST.must_equal 'foo' => 'bar' req2.params.must_equal 'foo' => 'bar' @@ -645,37 +652,37 @@ describe Rack::Request do it "allow deleting from params hash if param is in GET" do e = Rack::MockRequest.env_for("?foo=bar") - req1 = Rack::Request.new(e) + req1 = make_request(e) req1.params.must_equal 'foo' => 'bar' req1.delete_param('foo').must_equal 'bar' req1.params.must_equal({}) - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.params.must_equal({}) end it "allow deleting from params hash if param is in POST" do e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=bar') - req1 = Rack::Request.new(e) + req1 = make_request(e) req1.params.must_equal 'foo' => 'bar' req1.delete_param('foo').must_equal 'bar' req1.params.must_equal({}) - req2 = Rack::Request.new(e) + req2 = make_request(e) req2.params.must_equal({}) end it "pass through non-uri escaped cookies as-is" do - req = Rack::Request.new Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%") + req = make_request Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%") req.cookies["foo"].must_equal "%" end it "parse cookies according to RFC 2109" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car') req.cookies.must_equal 'foo' => 'bar' end it 'parse cookies with quotes' do - req = Rack::Request.new Rack::MockRequest.env_for('', { + req = make_request Rack::MockRequest.env_for('', { 'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"' }) req.cookies.must_equal({ @@ -687,7 +694,7 @@ describe Rack::Request do end it "provide setters" do - req = Rack::Request.new(e=Rack::MockRequest.env_for("")) + req = make_request(e=Rack::MockRequest.env_for("")) req.script_name.must_equal "" req.script_name = "/foo" req.script_name.must_equal "/foo" @@ -700,58 +707,58 @@ describe Rack::Request do end it "provide the original env" do - req = Rack::Request.new(e = Rack::MockRequest.env_for("")) + req = make_request(e = Rack::MockRequest.env_for("")) req.env.must_equal e end it "restore the base URL" do - Rack::Request.new(Rack::MockRequest.env_for("")).base_url. + make_request(Rack::MockRequest.env_for("")).base_url. must_equal "http://example.org" - Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url. + make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url. must_equal "http://example.org" end it "restore the URL" do - Rack::Request.new(Rack::MockRequest.env_for("")).url. + make_request(Rack::MockRequest.env_for("")).url. must_equal "http://example.org/" - Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url. + make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url. must_equal "http://example.org/foo/" - Rack::Request.new(Rack::MockRequest.env_for("/foo")).url. + make_request(Rack::MockRequest.env_for("/foo")).url. must_equal "http://example.org/foo" - Rack::Request.new(Rack::MockRequest.env_for("?foo")).url. + make_request(Rack::MockRequest.env_for("?foo")).url. must_equal "http://example.org/?foo" - Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).url. + make_request(Rack::MockRequest.env_for("http://example.org:8080/")).url. must_equal "http://example.org:8080/" - Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url. + make_request(Rack::MockRequest.env_for("https://example.org/")).url. must_equal "https://example.org/" - Rack::Request.new(Rack::MockRequest.env_for("coffee://example.org/")).url. + make_request(Rack::MockRequest.env_for("coffee://example.org/")).url. must_equal "coffee://example.org/" - Rack::Request.new(Rack::MockRequest.env_for("coffee://example.org:443/")).url. + make_request(Rack::MockRequest.env_for("coffee://example.org:443/")).url. must_equal "coffee://example.org:443/" - Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url. + make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url. must_equal "https://example.com:8080/foo?foo" end it "restore the full path" do - Rack::Request.new(Rack::MockRequest.env_for("")).fullpath. + make_request(Rack::MockRequest.env_for("")).fullpath. must_equal "/" - Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath. + make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath. must_equal "/foo/" - Rack::Request.new(Rack::MockRequest.env_for("/foo")).fullpath. + make_request(Rack::MockRequest.env_for("/foo")).fullpath. must_equal "/foo" - Rack::Request.new(Rack::MockRequest.env_for("?foo")).fullpath. + make_request(Rack::MockRequest.env_for("?foo")).fullpath. must_equal "/?foo" - Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath. + make_request(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath. must_equal "/" - Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).fullpath. + make_request(Rack::MockRequest.env_for("https://example.org/")).fullpath. must_equal "/" - Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath. + make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath. must_equal "/foo?foo" end it "handle multiple media type parameters" do - req = Rack::Request.new \ + req = make_request \ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam;blong="boo";zump="zoo\"o";weird=lol"') req.wont_be :form_data? @@ -784,7 +791,7 @@ Content-Transfer-Encoding: base64\r /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r --AaB03x--\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -823,7 +830,7 @@ Content-Transfer-Encoding: base64 /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg --AaB03x-- EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -847,7 +854,7 @@ Content-Transfer-Encoding: base64\r /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r --AaB03x--\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -882,7 +889,7 @@ EOF :input => StringIO.new(data) } - request = Rack::Request.new Rack::MockRequest.env_for("/", options) + request = make_request Rack::MockRequest.env_for("/", options) lambda { request.POST }.must_raise Rack::Multipart::MultipartPartLimitError end end @@ -904,7 +911,7 @@ EOF :input => StringIO.new(data) } - request = Rack::Request.new Rack::MockRequest.env_for("/", options) + request = make_request Rack::MockRequest.env_for("/", options) assert_raises(Rack::Multipart::MultipartPartLimitError) do request.POST end @@ -925,7 +932,7 @@ content-disposition: form-data; name="mean"; filename="mean"\r --AaB03xha\r --AaB03x--\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -955,7 +962,7 @@ EOF "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) - req = Rack::Request.new(env) + req = make_request(env) req.params env['rack.tempfiles'].size.must_equal 2 end @@ -965,7 +972,7 @@ EOF --AaB03x\r content-disposition: form-data; name="huge"; filename="huge"\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -978,7 +985,7 @@ content-disposition: form-data; name="huge"; filename="huge"\r \r foo\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -991,7 +998,7 @@ content-disposition: form-data; name="huge"; filename="huge"\r \r foo\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -1004,7 +1011,7 @@ EOF --AaB03x\r content-disposition: form-data; name="huge"; filename="huge"\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -1023,7 +1030,7 @@ Content-Transfer-Encoding: 7bit\r foo\r --AaB03x--\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/related, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -1041,7 +1048,7 @@ content-type: application/octet-stream\r --AaB03x--\r EOF - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size, :input => input) @@ -1056,7 +1063,7 @@ EOF rack_input.write(input) rack_input.rewind - req = Rack::Request.new Rack::MockRequest.env_for("/", + req = make_request Rack::MockRequest.env_for("/", "rack.request.form_hash" => {'foo' => 'bar'}, "rack.request.form_input" => rack_input, :input => rack_input) @@ -1066,7 +1073,7 @@ EOF it "conform to the Rack spec" do app = lambda { |env| - content = Rack::Request.new(env).POST["file"].inspect + content = make_request(env).POST["file"].inspect size = content.bytesize [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]] } @@ -1094,7 +1101,7 @@ EOF it "parse Accept-Encoding correctly" do parser = lambda do |x| - Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding + make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding end parser.call(nil).must_equal [] @@ -1111,7 +1118,7 @@ EOF it "parse Accept-Language correctly" do parser = lambda do |x| - Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language + make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language end parser.call(nil).must_equal [] @@ -1126,12 +1133,14 @@ EOF parser.call("fr").must_equal [["fr", 1.0]] end - ip_app = lambda { |env| - request = Rack::Request.new(env) - response = Rack::Response.new - response.write request.ip - response.finish - } + def ip_app + lambda { |env| + request = make_request(env) + response = Rack::Response.new + response.write request.ip + response.finish + } + end it 'provide ip information' do mock = Rack::MockRequest.new(Rack::Lint.new(ip_app)) @@ -1245,7 +1254,7 @@ EOF end it "regard local addresses as proxies" do - req = Rack::Request.new(Rack::MockRequest.env_for("/")) + req = make_request(Rack::MockRequest.env_for("/")) req.trusted_proxy?('127.0.0.1').must_equal 0 req.trusted_proxy?('10.0.0.1').must_equal 0 req.trusted_proxy?('172.16.0.1').must_equal 0 @@ -1277,7 +1286,7 @@ EOF it "allow subclass request to be instantiated after parent request" do env = Rack::MockRequest.env_for("/?foo=bar") - req1 = Rack::Request.new(env) + req1 = make_request(env) req1.GET.must_equal "foo" => "bar" req1.params.must_equal "foo" => "bar" @@ -1293,14 +1302,14 @@ EOF req1.GET.must_equal "foo" => "bar" req1.params.must_equal :foo => "bar" - req2 = Rack::Request.new(env) + req2 = make_request(env) req2.GET.must_equal "foo" => "bar" req2.params.must_equal "foo" => "bar" end it "raise TypeError every time if request parameters are broken" do broken_query = Rack::MockRequest.env_for("/?foo%5B%5D=0&foo%5Bbar%5D=1") - req = Rack::Request.new(broken_query) + req = make_request(broken_query) lambda{req.GET}.must_raise TypeError lambda{req.params}.must_raise TypeError end @@ -1311,9 +1320,41 @@ EOF it "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do url = "/?foo=#{c}bar#{c}" env = Rack::MockRequest.env_for(url) - req2 = Rack::Request.new(env) + req2 = make_request(env) req2.GET.must_equal "foo" => "#{b}bar#{b}" req2.params.must_equal "foo" => "#{b}bar#{b}" end } + + class NonDelegate < Rack::Request + def delegate?; false; end + end + + def make_request(env) + NonDelegate.new env + end + + class TestProxyRequest < RackRequestTest + class DelegateRequest + include Rack::Request::Helpers + extend Forwardable + + def_delegators :@req, :get_header, :fetch_header, :delete_header, + :set_header, :has_header?, :each_header + + def_delegators :@req, :[], :[]=, :values_at + + def initialize(req) + @req = req + end + + def delegate?; true; end + + def env; @req.env.dup; end + end + + def make_request(env) + DelegateRequest.new super(env) + end + end end |