Skip to content

Commit

Permalink
Rack::Request#POST should consistently raise errors. (#2010)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ioquatix committed Jan 16, 2023
1 parent 8e28099 commit 4da13a7
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 19 deletions.
1 change: 1 addition & 0 deletions lib/rack/constants.rb
Expand Up @@ -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'
Expand Down
47 changes: 28 additions & 19 deletions lib/rack/request.rb
Expand Up @@ -496,26 +496,35 @@ def GET
# 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

Expand Down
16 changes: 16 additions & 0 deletions test/spec_request.rb
Expand Up @@ -1218,6 +1218,22 @@ def initialize(*)
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
Expand Down

0 comments on commit 4da13a7

Please sign in to comment.