From 5dc8c7bc039a39a3f2e52afb4cc9bf100e65965b Mon Sep 17 00:00:00 2001 From: Jean byroot Boussier Date: Wed, 11 Jan 2023 11:56:00 +0100 Subject: [PATCH 1/4] Rack::MethodOverride handle QueryParser::ParamsTooDeepError (#2006) This middleware already handle two types of parsing issues but somehow not this one. Co-authored-by: Jean Boussier --- lib/rack/method_override.rb | 2 +- test/spec_method_override.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) 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/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 From af9cbb88a3d873c6dabe08554cbb78b9eeb2b8b1 Mon Sep 17 00:00:00 2001 From: Jean byroot Boussier Date: Wed, 11 Jan 2023 22:01:41 +0100 Subject: [PATCH 2/4] Fix Rack::Lint error message for HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH (#2007) Currently it's printing: ``` Rack::Lint::LintError: env contains HTTP_CONTENT_TYPE, must use ``` Which had me puzzled for quite a while. Co-authored-by: Jean Boussier --- lib/rack/lint.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 } From 401ca8248e642a9b3b11895f2957d12d448c5d55 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 16 Jan 2023 14:04:04 -0800 Subject: [PATCH 3/4] `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. --- lib/rack/constants.rb | 1 + lib/rack/request.rb | 47 ++++++++++++++++++++++++++----------------- 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 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/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/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 = < Date: Tue, 17 Jan 2023 11:33:44 +1300 Subject: [PATCH 4/4] Bump patch version. --- CHANGELOG.md | 6 ++++++ lib/rack/version.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) 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/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