From 586cfba23fc0365b252fd0f16317c7d3cf7211cd Mon Sep 17 00:00:00 2001 From: Rafael Mendonça França Date: Fri, 18 Jul 2014 17:25:49 -0300 Subject: 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. --- lib/rack/utils.rb | 7 +++++++ test/spec_request.rb | 12 ++++++++++++ test/spec_utils.rb | 6 ++++++ 3 files changed, 25 insertions(+) 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 -- cgit v1.2.3-24-ge0c7