summary refs log tree commit
diff options
context:
space:
mode:
authorRafael Mendonça França <rafael.franca@plataformatec.com.br>2014-07-18 17:25:49 -0300
committerRafael Mendonça França <rafael.franca@plataformatec.com.br>2014-07-18 18:59:46 -0300
commit586cfba23fc0365b252fd0f16317c7d3cf7211cd (patch)
tree0f5f9dd9eecc1554fdf48342065027f725adfc2e
parent2683d278913529400d13fd32b2a85e9eaa7f272c (diff)
downloadrack-586cfba23fc0365b252fd0f16317c7d3cf7211cd.tar.gz
Raise specific exception if the parameters are invalid
There are some cases where we try to parse the parameters but it fails
with ArgumentError.

1. When the parameters come from the query string and contains invalid
UTF-8 characters. In this case we raise ArgumentError when trying to
match the key portion of parameters with a regexp.

2. When the parameters come from the request body and the query string
contains invalid % encoded string. In this case we raise ArgumentError
when calling URI.decode_www_form_component.

Now both cases raise a InvalidParameterError what inherit from TypeError
and we can catch this exception to show a bad request for users instead
of an internal server error.
-rw-r--r--lib/rack/utils.rb7
-rw-r--r--test/spec_request.rb12
-rw-r--r--test/spec_utils.rb6
3 files changed, 25 insertions, 0 deletions
diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb
index 27ac956f..7f30a55a 100644
--- a/lib/rack/utils.rb
+++ b/lib/rack/utils.rb
@@ -26,6 +26,11 @@ module Rack
     # parameters (parsed by parse_nested_query) contain conflicting types.
     class ParameterTypeError < TypeError; end
 
+    # InvalidParameterError is the error that is raised when incoming structural
+    # parameters (parsed by parse_nested_query) contain invalid format or byte
+    # sequence.
+    class InvalidParameterError < TypeError; end
+
     # URI escapes. (CGI style space to +)
     def escape(s)
       URI.encode_www_form_component(s)
@@ -106,6 +111,8 @@ module Rack
       end
 
       return params.to_params_hash
+    rescue ArgumentError => e
+      raise InvalidParameterError, e.message
     end
     module_function :parse_nested_query
 
diff --git a/test/spec_request.rb b/test/spec_request.rb
index e5ec254e..2b4b3c0b 100644
--- a/test/spec_request.rb
+++ b/test/spec_request.rb
@@ -177,6 +177,18 @@ describe Rack::Request do
     req.params.should.equal req.GET.merge(req.POST)
   end
 
+  should "raise if input params has invalid %-encoding" do
+    mr = Rack::MockRequest.env_for("/?foo=quux",
+      "REQUEST_METHOD" => 'POST',
+      :input => "a%=1"
+    )
+    req = Rack::Request.new mr
+
+    lambda { req.POST }.
+      should.raise(Rack::Utils::InvalidParameterError).
+      message.should.equal "invalid %-encoding (a%)"
+  end
+
   should "raise if rack.input is missing" do
     req = Rack::Request.new({})
     lambda { req.POST }.should.raise(RuntimeError)
diff --git a/test/spec_utils.rb b/test/spec_utils.rb
index 6391f951..4b989db7 100644
--- a/test/spec_utils.rb
+++ b/test/spec_utils.rb
@@ -223,6 +223,12 @@ describe Rack::Utils do
     lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }.
       should.raise(Rack::Utils::ParameterTypeError).
       message.should.equal "expected Array (got String) for param `y'"
+
+    if RUBY_VERSION.to_f > 1.9
+      lambda { Rack::Utils.parse_nested_query("foo%81E=1") }.
+        should.raise(Rack::Utils::InvalidParameterError).
+        message.should.equal "invalid byte sequence in UTF-8"
+    end
   end
 
   should "build query strings correctly" do