bpo-42967: only use '&' as a query string separator (#24297) · python/cpython@fcbe0cb
@@ -115,7 +115,8 @@ def closelog():
115115# 0 ==> unlimited input
116116maxlen = 0
117117118-def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
118+def parse(fp=None, environ=os.environ, keep_blank_values=0,
119+strict_parsing=0, separator='&'):
119120"""Parse a query in the environment or from a file (default stdin)
120121121122 Arguments, all optional:
@@ -134,6 +135,9 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
134135 strict_parsing: flag indicating what to do with parsing errors.
135136 If false (the default), errors are silently ignored.
136137 If true, errors raise a ValueError exception.
138+139+ separator: str. The symbol to use for separating the query arguments.
140+ Defaults to &.
137141 """
138142if fp is None:
139143fp = sys.stdin
@@ -154,7 +158,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
154158if environ['REQUEST_METHOD'] == 'POST':
155159ctype, pdict = parse_header(environ['CONTENT_TYPE'])
156160if ctype == 'multipart/form-data':
157-return parse_multipart(fp, pdict)
161+return parse_multipart(fp, pdict, separator=separator)
158162elif ctype == 'application/x-www-form-urlencoded':
159163clength = int(environ['CONTENT_LENGTH'])
160164if maxlen and clength > maxlen:
@@ -178,10 +182,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
178182qs = ""
179183environ['QUERY_STRING'] = qs # XXX Shouldn't, really
180184return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing,
181-encoding=encoding)
185+encoding=encoding, separator=separator)
182186183187184-def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
188+def parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator='&'):
185189"""Parse multipart input.
186190187191 Arguments:
@@ -205,7 +209,7 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
205209except KeyError:
206210pass
207211fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,
208-environ={'REQUEST_METHOD': 'POST'})
212+environ={'REQUEST_METHOD': 'POST'}, separator=separator)
209213return {k: fs.getlist(k) for k in fs}
210214211215def _parseparam(s):
@@ -315,7 +319,7 @@ class FieldStorage:
315319def __init__(self, fp=None, headers=None, outerboundary=b'',
316320environ=os.environ, keep_blank_values=0, strict_parsing=0,
317321limit=None, encoding='utf-8', errors='replace',
318-max_num_fields=None):
322+max_num_fields=None, separator='&'):
319323"""Constructor. Read multipart/* until last part.
320324321325 Arguments, all optional:
@@ -363,6 +367,7 @@ def __init__(self, fp=None, headers=None, outerboundary=b'',
363367self.keep_blank_values = keep_blank_values
364368self.strict_parsing = strict_parsing
365369self.max_num_fields = max_num_fields
370+self.separator = separator
366371if 'REQUEST_METHOD' in environ:
367372method = environ['REQUEST_METHOD'].upper()
368373self.qs_on_post = None
@@ -589,7 +594,7 @@ def read_urlencoded(self):
589594query = urllib.parse.parse_qsl(
590595qs, self.keep_blank_values, self.strict_parsing,
591596encoding=self.encoding, errors=self.errors,
592-max_num_fields=self.max_num_fields)
597+max_num_fields=self.max_num_fields, separator=self.separator)
593598self.list = [MiniFieldStorage(key, value) for key, value in query]
594599self.skip_lines()
595600@@ -605,7 +610,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):
605610query = urllib.parse.parse_qsl(
606611self.qs_on_post, self.keep_blank_values, self.strict_parsing,
607612encoding=self.encoding, errors=self.errors,
608-max_num_fields=self.max_num_fields)
613+max_num_fields=self.max_num_fields, separator=self.separator)
609614self.list.extend(MiniFieldStorage(key, value) for key, value in query)
610615611616klass = self.FieldStorageClass or self.__class__
@@ -649,7 +654,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):
649654else self.limit - self.bytes_read
650655part = klass(self.fp, headers, ib, environ, keep_blank_values,
651656strict_parsing, limit,
652-self.encoding, self.errors, max_num_fields)
657+self.encoding, self.errors, max_num_fields, self.separator)
653658654659if max_num_fields is not None:
655660max_num_fields -= 1