@@ -90,6 +90,8 @@ defmodule Plug.Conn.Query do
9090 @ typedoc since: "1.16.0"
9191 @ opaque decoder ( ) :: map ( )
9292
93+ @ max_nesting 32
94+
9395 @ doc """
9496 Decodes the given `query`.
9597
@@ -204,32 +206,48 @@ defmodule Plug.Conn.Query do
204206 value = binary_part ( key , 0 , pos )
205207 pos = pos + 1
206208 rest = binary_part ( key , pos , byte_size ( key ) - pos )
207- split_keys ( rest , key , pos , pos , value , [ { :root , value } ] )
209+ split_keys ( rest , key , pos , pos , value , [ { :root , value } ] , 1 )
208210 else
209211 _ -> [ { :root , key } ]
210212 end
211213
212214 insert_keys ( keys , value , map )
213215 end
214216
215- defp split_keys ( << ?] , ?[ , rest :: binary >> , binary , current_pos , start_pos , level , acc ) do
217+ defp split_keys ( << ?] , ?[ , rest :: binary >> , binary , current_pos , start_pos , level , acc , count ) do
218+ count = count + 1
219+ check_nesting! ( count )
220+
216221 value = split_key ( binary , current_pos , start_pos )
217222 next_level = binary_part ( binary , 0 , current_pos + 1 )
218- split_keys ( rest , binary , current_pos + 2 , current_pos + 2 , next_level , [ { level , value } | acc ] )
223+ current_pos = current_pos + 2
224+ acc = [ { level , value } | acc ]
225+ split_keys ( rest , binary , current_pos , current_pos , next_level , acc , count )
219226 end
220227
221- defp split_keys ( << ?] >> , binary , current_pos , start_pos , level , acc ) do
228+ defp split_keys ( << ?] >> , binary , current_pos , start_pos , level , acc , count ) do
229+ count = count + 1
230+ check_nesting! ( count )
231+
222232 value = split_key ( binary , current_pos , start_pos )
223233 [ { level , value } | acc ]
224234 end
225235
226- defp split_keys ( << _ , rest :: binary >> , binary , current_pos , start_pos , level , acc ) do
227- split_keys ( rest , binary , current_pos + 1 , start_pos , level , acc )
236+ defp split_keys ( << _ , rest :: binary >> , binary , current_pos , start_pos , level , acc , count ) do
237+ check_nesting! ( count )
238+ split_keys ( rest , binary , current_pos + 1 , start_pos , level , acc , count )
228239 end
229240
230241 defp split_key ( _binary , start , start ) , do: nil
231242 defp split_key ( binary , current , start ) , do: binary_part ( binary , start , current - start )
232243
244+ defp check_nesting! ( count ) when count > @ max_nesting do
245+ message = "maximum query nesting is #{ @ max_nesting } , got a query with #{ count } keys"
246+ raise Plug.Conn.InvalidQueryError , message: message
247+ end
248+
249+ defp check_nesting! ( _count ) , do: :ok
250+
233251 defp insert_keys ( [ { level , key } | rest ] , value , map ) do
234252 case map do
235253 % { ^ level => entries } -> % { map | level => [ { key , value } | entries ] }
@@ -312,56 +330,67 @@ defmodule Plug.Conn.Query do
312330 #
313331 # users[address][street #=> [ "users", "address][street" ]
314332 #
315- assign_split ( :binary . split ( subkey , "[" ) , value , acc , :binary . compile_pattern ( "][" ) )
333+ pattern = :binary . compile_pattern ( "][" )
334+ parts = :binary . split ( subkey , "[" )
335+ assign_split ( parts , value , acc , pattern , 1 )
316336 else
317337 assign_map ( acc , key , value )
318338 end
319339 end
320340
321- defp assign_split ( [ "" , rest ] , value , acc , pattern ) do
341+ defp assign_split ( [ "" , rest ] , value , acc , pattern , count ) do
342+ check_nesting! ( count )
322343 parts = :binary . split ( rest , pattern )
323344
324345 case acc do
325- [ _ | _ ] -> [ assign_split ( parts , value , :none , pattern ) | acc ]
326- :none -> [ assign_split ( parts , value , :none , pattern ) ]
346+ [ _ | _ ] -> [ assign_split ( parts , value , :none , pattern , count + 1 ) | acc ]
347+ :none -> [ assign_split ( parts , value , :none , pattern , count + 1 ) ]
327348 _ -> acc
328349 end
329350 end
330351
331- defp assign_split ( [ key , rest ] , value , acc , pattern ) do
352+ defp assign_split ( [ key , rest ] , value , acc , pattern , count ) do
353+ check_nesting! ( count )
332354 parts = :binary . split ( rest , pattern )
333355
334356 case acc do
335357 % { ^ key => current } when is_list ( current ) or is_map ( current ) ->
336- Map . put ( acc , key , assign_split ( parts , value , current , pattern ) )
358+ value = assign_split ( parts , value , current , pattern , count + 1 )
359+ Map . put ( acc , key , value )
337360
338361 % { ^ key => _ } ->
339362 acc
340363
341364 % { } ->
342- Map . put ( acc , key , assign_split ( parts , value , :none , pattern ) )
365+ value = assign_split ( parts , value , :none , pattern , count + 1 )
366+ Map . put ( acc , key , value )
343367
344368 _ ->
345- % { key => assign_split ( parts , value , :none , pattern ) }
369+ % { key => assign_split ( parts , value , :none , pattern , count + 1 ) }
346370 end
347371 end
348372
349- defp assign_split ( [ "" ] , nil , acc , _pattern ) do
373+ defp assign_split ( [ "" ] , nil , acc , _pattern , count ) do
374+ check_nesting! ( count )
375+
350376 case acc do
351377 [ _ | _ ] -> acc
352378 _ -> [ ]
353379 end
354380 end
355381
356- defp assign_split ( [ "" ] , value , acc , _pattern ) do
382+ defp assign_split ( [ "" ] , value , acc , _pattern , count ) do
383+ check_nesting! ( count )
384+
357385 case acc do
358386 [ _ | _ ] -> [ value | acc ]
359387 :none -> [ value ]
360388 _ -> acc
361389 end
362390 end
363391
364- defp assign_split ( [ key ] , value , acc , _pattern ) do
392+ defp assign_split ( [ key ] , value , acc , _pattern , count ) do
393+ check_nesting! ( count )
365394 assign_map ( acc , key , value )
366395 end
367396
0 commit comments