From 100745eeb069578aba2ab18969bfb845e880ab8e Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Thu, 23 Jun 2016 11:47:12 +0800 Subject: Try harder when deciding whether to add a new array element Only move to a new entry if the end key is taken; checking only the top-level key is insufficient. --- lib/rack/query_parser.rb | 15 +++++++++++++-- test/spec_utils.rb | 12 ++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/rack/query_parser.rb b/lib/rack/query_parser.rb index 17b77128..be74bc06 100644 --- a/lib/rack/query_parser.rb +++ b/lib/rack/query_parser.rb @@ -102,8 +102,7 @@ module Rack child_key = $1 params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) - first_key = child_key.gsub(/[\[\]]/, ' ').split.first - if params_hash_type?(params[k].last) && !params[k].last.key?(first_key) + if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key) normalize_params(params[k].last, child_key, v, depth - 1) else params[k] << normalize_params(make_params, child_key, v, depth - 1) @@ -135,6 +134,18 @@ module Rack obj.kind_of?(@params_class) end + def params_hash_has_key?(hash, key) + return false if key =~ /\[\]/ + + key.split(/[\[\]]+/).inject(hash) do |h, part| + next h if part == '' + return false unless params_hash_type?(h) && h.key?(part) + h[part] + end + + true + end + def unescape(s) Utils.unescape(s) end diff --git a/test/spec_utils.rb b/test/spec_utils.rb index b24762c9..e5d4d244 100644 --- a/test/spec_utils.rb +++ b/test/spec_utils.rb @@ -231,6 +231,18 @@ describe Rack::Utils do message.must_equal "invalid byte sequence in UTF-8" end + it "only moves to a new array when the full key has been seen" do + Rack::Utils.parse_nested_query("x[][y][][z]=1&x[][y][][w]=2"). + must_equal "x" => [{"y" => [{"z" => "1", "w" => "2"}]}] + + Rack::Utils.parse_nested_query( + "x[][id]=1&x[][y][a]=5&x[][y][b]=7&x[][z][id]=3&x[][z][w]=0&x[][id]=2&x[][y][a]=6&x[][y][b]=8&x[][z][id]=4&x[][z][w]=0" + ).must_equal "x" => [ + {"id" => "1", "y" => {"a" => "5", "b" => "7"}, "z" => {"id" => "3", "w" => "0"}}, + {"id" => "2", "y" => {"a" => "6", "b" => "8"}, "z" => {"id" => "4", "w" => "0"}}, + ] + end + it "allow setting the params hash class to use for parsing query strings" do begin default_parser = Rack::Utils.default_query_parser -- cgit v1.2.3-24-ge0c7