From 59d9ba903fdb50cf8db708c8263a7b2a79de83fb Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 13 Mar 2023 17:50:30 +1300 Subject: [PATCH] Add `QueryParser#missing_value` for handling missing values + tests. (#2052) --- lib/rack.rb | 1 + lib/rack/query_parser.rb | 15 ++++++++++++--- test/spec_query_parser.rb | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 test/spec_query_parser.rb diff --git a/lib/rack.rb b/lib/rack.rb index 69780545e..d00b96667 100644 --- a/lib/rack.rb +++ b/lib/rack.rb @@ -41,6 +41,7 @@ module Rack autoload :MethodOverride, "rack/method_override" autoload :Mime, "rack/mime" autoload :NullLogger, "rack/null_logger" + autoload :QueryParser, "rack/query_parser" autoload :Recursive, "rack/recursive" autoload :Reloader, "rack/reloader" autoload :RewindableInput, "rack/rewindable_input" diff --git a/lib/rack/query_parser.rb b/lib/rack/query_parser.rb index 1c05ae828..525900f7b 100644 --- a/lib/rack/query_parser.rb +++ b/lib/rack/query_parser.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative 'bad_request' +require 'uri' module Rack class QueryParser @@ -111,6 +112,14 @@ def normalize_params(params, name, v, _depth=nil) _normalize_params(params, name, v, 0) end + # This value is used by default when a parameter is missing (nil). This + # usually happens when a parameter is specified without an `=value` part. + # The default value is an empty string, but this can be overridden by + # subclasses. + def missing_value + String.new + end + private def _normalize_params(params, name, v, depth) raise ParamsTooDeepError if depth >= param_depth_limit @@ -145,7 +154,7 @@ def normalize_params(params, name, v, _depth=nil) return if k.empty? - v ||= String.new + v ||= missing_value if after == '' if k == '[]' && depth != 0 @@ -207,8 +216,8 @@ def params_hash_has_key?(hash, key) true end - def unescape(s) - Utils.unescape(s) + def unescape(string, encoding = Encoding::UTF_8) + URI.decode_www_form_component(string, encoding) end class Params < Hash diff --git a/test/spec_query_parser.rb b/test/spec_query_parser.rb new file mode 100644 index 000000000..5f4708186 --- /dev/null +++ b/test/spec_query_parser.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require_relative 'helper' + +separate_testing do + require_relative '../lib/rack/query_parser' +end + +describe Rack::QueryParser do + def query_parser + @query_parser ||= Rack::QueryParser.new(Rack::QueryParser::Params, 8) + end + + it "has a default value" do + assert_equal "", query_parser.missing_value + end + + it "can normalize values with missing values" do + query_parser.parse_nested_query("a=a").must_equal({"a" => "a"}) + query_parser.parse_nested_query("a=").must_equal({"a" => ""}) + query_parser.parse_nested_query("a").must_equal({"a" => ""}) + end + + it "can override default missing value" do + def query_parser.missing_value + nil + end + + query_parser.parse_nested_query("a=a").must_equal({"a" => "a"}) + query_parser.parse_nested_query("a=").must_equal({"a" => ""}) + query_parser.parse_nested_query("a").must_equal({"a" => nil}) + end +end