diff options
author | Samuel Williams <samuel.williams@oriontransfer.co.nz> | 2023-01-16 14:04:04 -0800 |
---|---|---|
committer | Samuel Williams <samuel.williams@oriontransfer.co.nz> | 2023-01-17 11:29:01 +1300 |
commit | 401ca8248e642a9b3b11895f2957d12d448c5d55 (patch) | |
tree | 66f11d318285b8e601a67fd2a67de131eef28751 | |
parent | af9cbb88a3d873c6dabe08554cbb78b9eeb2b8b1 (diff) | |
download | rack-401ca8248e642a9b3b11895f2957d12d448c5d55.tar.gz |
`Rack::Request#POST` should consistently raise errors. (#2010)
Cache errors that occur when invoking `Rack::Request#POST` so they can be
raised again later.
* Don't throw exactly the same error - so we have the correct backtrace.
-rw-r--r-- | lib/rack/constants.rb | 1 | ||||
-rw-r--r-- | lib/rack/request.rb | 47 | ||||
-rw-r--r-- | test/spec_request.rb | 16 |
3 files changed, 45 insertions, 19 deletions
diff --git a/lib/rack/constants.rb b/lib/rack/constants.rb index 6aa9281f..13365935 100644 --- a/lib/rack/constants.rb +++ b/lib/rack/constants.rb @@ -55,6 +55,7 @@ module Rack RACK_REQUEST_FORM_INPUT = 'rack.request.form_input' RACK_REQUEST_FORM_HASH = 'rack.request.form_hash' RACK_REQUEST_FORM_VARS = 'rack.request.form_vars' + RACK_REQUEST_FORM_ERROR = 'rack.request.form_error' RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash' RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string' RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash' diff --git a/lib/rack/request.rb b/lib/rack/request.rb index 6641b5fc..40922a21 100644 --- a/lib/rack/request.rb +++ b/lib/rack/request.rb @@ -496,26 +496,35 @@ module Rack # This method support both application/x-www-form-urlencoded and # multipart/form-data. def POST - if get_header(RACK_INPUT).nil? - raise "Missing rack.input" - elsif get_header(RACK_REQUEST_FORM_INPUT) == get_header(RACK_INPUT) - get_header(RACK_REQUEST_FORM_HASH) - elsif form_data? || parseable_data? - unless set_header(RACK_REQUEST_FORM_HASH, parse_multipart) - form_vars = get_header(RACK_INPUT).read - - # Fix for Safari Ajax postings that always append \0 - # form_vars.sub!(/\0\z/, '') # performance replacement: - form_vars.slice!(-1) if form_vars.end_with?("\0") - - set_header RACK_REQUEST_FORM_VARS, form_vars - set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&') + if error = get_header(RACK_REQUEST_FORM_ERROR) + raise error.class, error.message, cause: error.cause + end + + begin + if get_header(RACK_INPUT).nil? + raise "Missing rack.input" + elsif get_header(RACK_REQUEST_FORM_INPUT) == get_header(RACK_INPUT) + get_header(RACK_REQUEST_FORM_HASH) + elsif form_data? || parseable_data? + unless set_header(RACK_REQUEST_FORM_HASH, parse_multipart) + form_vars = get_header(RACK_INPUT).read + + # Fix for Safari Ajax postings that always append \0 + # form_vars.sub!(/\0\z/, '') # performance replacement: + form_vars.slice!(-1) if form_vars.end_with?("\0") + + set_header RACK_REQUEST_FORM_VARS, form_vars + set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&') + end + set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT) + get_header RACK_REQUEST_FORM_HASH + else + set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT) + set_header(RACK_REQUEST_FORM_HASH, {}) end - set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT) - get_header RACK_REQUEST_FORM_HASH - else - set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT) - set_header(RACK_REQUEST_FORM_HASH, {}) + rescue => error + set_header(RACK_REQUEST_FORM_ERROR, error) + raise end end diff --git a/test/spec_request.rb b/test/spec_request.rb index 750639de..9fed5029 100644 --- a/test/spec_request.rb +++ b/test/spec_request.rb @@ -1218,6 +1218,22 @@ class RackRequestTest < Minitest::Spec req.media_type_params['weird'].must_equal 'lol"' end + it "returns the same error for invalid post inputs" do + env = { + 'REQUEST_METHOD' => 'POST', + 'PATH_INFO' => '/foo', + 'rack.input' => StringIO.new('invalid=bar&invalid[foo]=bar'), + 'HTTP_CONTENT_TYPE' => "application/x-www-form-urlencoded", + } + + 2.times do + # The actual exception type here is unimportant - just that it fails. + assert_raises(Rack::Utils::ParameterTypeError) do + Rack::Request.new(env).POST + end + end + end + it "parse with junk before boundary" do # Adapted from RFC 1867. input = <<EOF |