diff --git a/CHANGELOG.md b/CHANGELOG.md
index 469e4104a..2edd32c0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file. For info on how to format all future additions to this file please reference [Keep A Changelog](https://keepachangelog.com/en/1.0.0/).
+## [3.0.4] - 2022-01-17
+
+- `Rack::Request#POST` should consistently raise errors. Cache errors that occur when invoking `Rack::Request#POST` so they can be raised again later. ([#2010](https://github.com/rack/rack/pull/2010), [@ioquatix])
+- Fix `Rack::Lint` error message for `HTTP_CONTENT_TYPE` and `HTTP_CONTENT_LENGTH`. ([#2007](https://github.com/rack/rack/pull/2007), [@byroot](https://github.com/byroot))
+- Extend `Rack::MethodOverride` to handle `QueryParser::ParamsTooDeepError` error. ([#2006](https://github.com/rack/rack/pull/2006), [@byroot](https://github.com/byroot))
+
## [3.0.3] - 2022-12-27
### Fixed
diff --git a/lib/rack/constants.rb b/lib/rack/constants.rb
index 6aa9281f6..13365935b 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/lint.rb b/lib/rack/lint.rb
index ed3c7f421..ee3ec7161 100755
--- a/lib/rack/lint.rb
+++ b/lib/rack/lint.rb
@@ -303,7 +303,7 @@ def check_environment(env)
## (use the versions without HTTP_).
%w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header|
if env.include? header
- raise LintError, "env contains #{header}, must use #{header[5, -1]}"
+ raise LintError, "env contains #{header}, must use #{header[5..-1]}"
end
}
diff --git a/lib/rack/method_override.rb b/lib/rack/method_override.rb
index 61df3fc5e..6125b1916 100644
--- a/lib/rack/method_override.rb
+++ b/lib/rack/method_override.rb
@@ -47,7 +47,7 @@ def allowed_methods
def method_override_param(req)
req.POST[METHOD_OVERRIDE_PARAM_KEY] if req.form_data? || req.parseable_data?
- rescue Utils::InvalidParameterError, Utils::ParameterTypeError
+ rescue Utils::InvalidParameterError, Utils::ParameterTypeError, QueryParser::ParamsTooDeepError
req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params"
rescue EOFError
req.get_header(RACK_ERRORS).puts "Bad request content body"
diff --git a/lib/rack/request.rb b/lib/rack/request.rb
index 6641b5fcd..40922a219 100644
--- a/lib/rack/request.rb
+++ b/lib/rack/request.rb
@@ -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
diff --git a/lib/rack/version.rb b/lib/rack/version.rb
index 27691d821..f1b2710a6 100644
--- a/lib/rack/version.rb
+++ b/lib/rack/version.rb
@@ -25,7 +25,7 @@ def self.version
VERSION
end
- RELEASE = "3.0.3"
+ RELEASE = "3.0.4"
# Return the Rack release as a dotted string.
def self.release
diff --git a/test/spec_method_override.rb b/test/spec_method_override.rb
index d77690f44..f3b8ad729 100644
--- a/test/spec_method_override.rb
+++ b/test/spec_method_override.rb
@@ -106,6 +106,13 @@ def app
env[Rack::RACK_ERRORS].read.must_include 'Bad request content body'
end
+ it "not modify REQUEST_METHOD for POST requests when the params are unparseable because too deep" do
+ env = Rack::MockRequest.env_for("/", method: "POST", input: ("[a]" * 36) + "=1")
+ app.call env
+
+ env["REQUEST_METHOD"].must_equal "POST"
+ end
+
it "not modify REQUEST_METHOD for POST requests when the params are unparseable" do
env = Rack::MockRequest.env_for("/", method: "POST", input: "(%bad-params%)")
app.call env
diff --git a/test/spec_request.rb b/test/spec_request.rb
index 750639deb..9fed5029a 100644
--- a/test/spec_request.rb
+++ b/test/spec_request.rb
@@ -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 = <