@@ -184,11 +184,12 @@ def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
184184 return urlparse .parse_qs (qs , keep_blank_values , strict_parsing )
185185
186186
187- def parse_qsl (qs , keep_blank_values = 0 , strict_parsing = 0 ):
187+ def parse_qsl (qs , keep_blank_values = 0 , strict_parsing = 0 , max_num_fields = None ):
188188 """Parse a query given as a string argument."""
189189 warn ("cgi.parse_qsl is deprecated, use urlparse.parse_qsl instead" ,
190190 PendingDeprecationWarning , 2 )
191- return urlparse .parse_qsl (qs , keep_blank_values , strict_parsing )
191+ return urlparse .parse_qsl (qs , keep_blank_values , strict_parsing ,
192+ max_num_fields )
192193
193194def parse_multipart (fp , pdict ):
194195 """Parse multipart input.
@@ -393,7 +394,8 @@ class FieldStorage:
393394 """
394395
395396 def __init__ (self , fp = None , headers = None , outerboundary = "" ,
396- environ = os .environ , keep_blank_values = 0 , strict_parsing = 0 ):
397+ environ = os .environ , keep_blank_values = 0 , strict_parsing = 0 ,
398+ max_num_fields = None ):
397399 """Constructor. Read multipart/* until last part.
398400
399401 Arguments, all optional:
@@ -420,10 +422,14 @@ def __init__(self, fp=None, headers=None, outerboundary="",
420422 If false (the default), errors are silently ignored.
421423 If true, errors raise a ValueError exception.
422424
425+ max_num_fields: int. If set, then __init__ throws a ValueError
426+ if there are more than n fields read by parse_qsl().
427+
423428 """
424429 method = 'GET'
425430 self .keep_blank_values = keep_blank_values
426431 self .strict_parsing = strict_parsing
432+ self .max_num_fields = max_num_fields
427433 if 'REQUEST_METHOD' in environ :
428434 method = environ ['REQUEST_METHOD' ].upper ()
429435 self .qs_on_post = None
@@ -606,10 +612,9 @@ def read_urlencoded(self):
606612 qs = self .fp .read (self .length )
607613 if self .qs_on_post :
608614 qs += '&' + self .qs_on_post
609- self .list = list = []
610- for key , value in urlparse .parse_qsl (qs , self .keep_blank_values ,
611- self .strict_parsing ):
612- list .append (MiniFieldStorage (key , value ))
615+ query = urlparse .parse_qsl (qs , self .keep_blank_values ,
616+ self .strict_parsing , self .max_num_fields )
617+ self .list = [MiniFieldStorage (key , value ) for key , value in query ]
613618 self .skip_lines ()
614619
615620 FieldStorageClass = None
@@ -621,19 +626,38 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):
621626 raise ValueError , 'Invalid boundary in multipart form: %r' % (ib ,)
622627 self .list = []
623628 if self .qs_on_post :
624- for key , value in urlparse .parse_qsl (self .qs_on_post ,
625- self .keep_blank_values , self .strict_parsing ):
626- self .list .append (MiniFieldStorage (key , value ))
629+ query = urlparse .parse_qsl (self .qs_on_post ,
630+ self .keep_blank_values ,
631+ self .strict_parsing ,
632+ self .max_num_fields )
633+ self .list .extend (MiniFieldStorage (key , value )
634+ for key , value in query )
627635 FieldStorageClass = None
628636
637+ # Propagate max_num_fields into the sub class appropriately
638+ max_num_fields = self .max_num_fields
639+ if max_num_fields is not None :
640+ max_num_fields -= len (self .list )
641+
629642 klass = self .FieldStorageClass or self .__class__
630643 part = klass (self .fp , {}, ib ,
631- environ , keep_blank_values , strict_parsing )
644+ environ , keep_blank_values , strict_parsing ,
645+ max_num_fields )
646+
632647 # Throw first part away
633648 while not part .done :
634649 headers = rfc822 .Message (self .fp )
635650 part = klass (self .fp , headers , ib ,
636- environ , keep_blank_values , strict_parsing )
651+ environ , keep_blank_values , strict_parsing ,
652+ max_num_fields )
653+
654+ if max_num_fields is not None :
655+ max_num_fields -= 1
656+ if part .list :
657+ max_num_fields -= len (part .list )
658+ if max_num_fields < 0 :
659+ raise ValueError ('Max number of fields exceeded' )
660+
637661 self .list .append (part )
638662 self .skip_lines ()
639663
0 commit comments