@@ -76,13 +76,13 @@ def load_parameters
7676 get_vals << v ; true
7777 end
7878 end
79- store_parameter ( key , get_vals , query_hash )
80- store_parameter ( key , post_vals , form_hash )
79+ store_parameter ( query_hash , key , get_vals )
80+ store_parameter ( form_hash , key , post_vals )
8181 else
82- store_parameter ( key , val , query_hash )
82+ store_parameter ( query_hash , key , val )
8383 end
8484 else # POST param :
85- store_parameter ( key , val , form_hash )
85+ store_parameter ( form_hash , key , val )
8686 end
8787 end
8888 # Rack::Request#GET
@@ -112,9 +112,10 @@ def [](key)
112112 #
113113 # @param key the param name
114114 # @param val the value(s) in a array-like structure
115- # @param hash the Hash to store the name, value pair
116- def store_parameter ( key , val , hash )
115+ # @param params the Hash to store the name, value pair
116+ def store_parameter2 ( params , key , val , depth = 0 )
117117 # emulating Rack::Utils.parse_nested_query behavior
118+ raise ::Rack ::Utils ::ParamsTooDeepError if depth >= 32
118119
119120 if match = key . match ( KEY_SEP )
120121 n_key = match [ 1 ] ; sub = match [ 2 ]
@@ -124,25 +125,108 @@ def store_parameter(key, val, hash)
124125
125126 if sub
126127 if sub . empty? # e.g. foo[]=1&foo[]=2
127- if arr = hash [ n_key ]
128+ if arr = params [ n_key ]
128129 return mark_parameter_error "expected Array (got #{ arr . class } ) for param `#{ n_key } '" unless arr . is_a? ( Array )
129- hash [ n_key ] = arr + val . to_a ; return
130+ params [ n_key ] = arr + val . to_a ; return
130131 end
131- hash [ n_key ] = val . to_a # String[]
132+ params [ n_key ] = val . to_a # String[]
132133 else # foo[bar]=rrr&foo[baz]=zzz
133- if hsh = hash [ n_key ]
134+ if hsh = params [ n_key ]
134135 return mark_parameter_error "expected Hash (got #{ hsh . class } ) for param `#{ n_key } '" unless hsh . is_a? ( Hash )
135- store_parameter ( sub , val , hsh )
136+ store_parameter2 ( hsh , sub , val , depth + 1 )
136137 else
137- hash [ n_key ] = { sub => val [ val . length - 1 ] }
138+ params [ n_key ] = { sub => val [ val . length - 1 ] }
138139 end
139140 end
140141 else
141142 # for 'foo=bad&foo=bar' does { 'foo' => 'bar' }
142- hash [ n_key ] = val [ val . length - 1 ] # last
143+ params [ n_key ] = val [ val . length - 1 ] # last
143144 end
144145 end
145146
147+ def store_parameter3 ( params , key , val , depth = 0 )
148+ raise ::Rack ::Utils ::ParamsTooDeepError if depth >= 32
149+
150+ if !key
151+ # nil name, treat same as empty string (required by tests)
152+ n_key = after = ''
153+ elsif depth == 0
154+ # Start of parsing, don't treat [] or [ at start of string specially
155+ if start = key . index ( '[' , 1 )
156+ # Start of parameter nesting, use part before brackets as key
157+ n_key = key [ 0 , start ]
158+ after = key [ start , key . length ]
159+ else
160+ # Plain parameter with no nesting
161+ n_key = key
162+ after = ''
163+ end
164+ elsif key . start_with? ( '[]' )
165+ # Array nesting
166+ n_key = '[]'
167+ after = key [ 2 , key . length ]
168+ elsif key . start_with? ( '[' ) && ( start = key . index ( ']' , 1 ) )
169+ # Hash nesting, use the part inside brackets as the key
170+ n_key = key [ 1 , start -1 ]
171+ after = key [ start +1 , key . length ]
172+ else
173+ # Probably malformed input, nested but not starting with [
174+ # treat full name as key for backwards compatibility.
175+ n_key = key
176+ after = ''
177+ end
178+
179+ return if n_key . empty?
180+
181+ if after == ''
182+ if n_key == '[]' && depth != 0
183+ return [ val ]
184+ else
185+ params [ n_key ] = val
186+ end
187+ elsif after == "["
188+ params [ key ] = val
189+ elsif after == "[]"
190+ params [ n_key ] ||= [ ]
191+ return mark_parameter_error "expected Array (got #{ params [ n_key ] . class . name } ) for param `#{ n_key } '" unless params [ n_key ] . is_a? ( Array )
192+ params [ n_key ] << val
193+ elsif after . start_with? ( '[]' )
194+ # Recognize x[][y] (hash inside array) parameters
195+ unless after [ 2 ] == '[' && after . end_with? ( ']' ) && ( child_key = after [ 3 , after . length -4 ] ) && !child_key . empty? && !child_key . index ( '[' ) && !child_key . index ( ']' )
196+ # Handle other nested array parameters
197+ child_key = after [ 2 , after . length ]
198+ end
199+ params [ n_key ] ||= [ ]
200+ return mark_parameter_error "expected Array (got #{ params [ n_key ] . class . name } ) for param `#{ n_key } '" unless params [ n_key ] . is_a? ( Array )
201+
202+ if params [ n_key ] . last . is_a? ( Hash ) && !params_hash_has_key? ( params [ n_key ] . last , child_key )
203+ store_parameter3 ( params [ n_key ] . last , child_key , val , depth + 1 )
204+ else
205+ params [ n_key ] << store_parameter3 ( { } , child_key , val , depth + 1 )
206+ end
207+ else
208+ params [ n_key ] ||= { }
209+ return mark_parameter_error "expected Hash (got #{ params [ n_key ] . class . name } ) for param `#{ n_key } '" unless params [ n_key ] . is_a? ( Hash )
210+ params [ n_key ] = store_parameter3 ( params [ n_key ] , after , val , depth + 1 )
211+ end
212+
213+ params
214+ end
215+
216+ def params_hash_has_key? ( hash , key )
217+ return false if /\[ \] / . match? ( key )
218+
219+ key . split ( /[\[ \] ]+/ ) . inject ( hash ) do |h , part |
220+ next h if part == ''
221+ return false unless h . is_a? ( Hash ) && h . key? ( part )
222+ h [ part ]
223+ end
224+
225+ true
226+ end
227+
228+ alias_method :store_parameter , ( Rack . release >= '3' ? :store_parameter3 : :store_parameter2 )
229+
146230 COOKIE_STRING = "rack.request.cookie_string" . freeze
147231 COOKIE_HASH = "rack.request.cookie_hash" . freeze
148232
0 commit comments