bpo-42967: only use '&' as a query string separator (#24297) · python/cpython@fcbe0cb

@@ -115,7 +115,8 @@ def closelog():

115115

# 0 ==> unlimited input

116116

maxlen = 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

"""

138142

if fp is None:

139143

fp = sys.stdin

@@ -154,7 +158,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):

154158

if environ['REQUEST_METHOD'] == 'POST':

155159

ctype, pdict = parse_header(environ['CONTENT_TYPE'])

156160

if ctype == 'multipart/form-data':

157-

return parse_multipart(fp, pdict)

161+

return parse_multipart(fp, pdict, separator=separator)

158162

elif ctype == 'application/x-www-form-urlencoded':

159163

clength = int(environ['CONTENT_LENGTH'])

160164

if maxlen and clength > maxlen:

@@ -178,10 +182,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):

178182

qs = ""

179183

environ['QUERY_STRING'] = qs # XXX Shouldn't, really

180184

return 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"):

205209

except KeyError:

206210

pass

207211

fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,

208-

environ={'REQUEST_METHOD': 'POST'})

212+

environ={'REQUEST_METHOD': 'POST'}, separator=separator)

209213

return {k: fs.getlist(k) for k in fs}

210214211215

def _parseparam(s):

@@ -315,7 +319,7 @@ class FieldStorage:

315319

def __init__(self, fp=None, headers=None, outerboundary=b'',

316320

environ=os.environ, keep_blank_values=0, strict_parsing=0,

317321

limit=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'',

363367

self.keep_blank_values = keep_blank_values

364368

self.strict_parsing = strict_parsing

365369

self.max_num_fields = max_num_fields

370+

self.separator = separator

366371

if 'REQUEST_METHOD' in environ:

367372

method = environ['REQUEST_METHOD'].upper()

368373

self.qs_on_post = None

@@ -589,7 +594,7 @@ def read_urlencoded(self):

589594

query = urllib.parse.parse_qsl(

590595

qs, self.keep_blank_values, self.strict_parsing,

591596

encoding=self.encoding, errors=self.errors,

592-

max_num_fields=self.max_num_fields)

597+

max_num_fields=self.max_num_fields, separator=self.separator)

593598

self.list = [MiniFieldStorage(key, value) for key, value in query]

594599

self.skip_lines()

595600

@@ -605,7 +610,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):

605610

query = urllib.parse.parse_qsl(

606611

self.qs_on_post, self.keep_blank_values, self.strict_parsing,

607612

encoding=self.encoding, errors=self.errors,

608-

max_num_fields=self.max_num_fields)

613+

max_num_fields=self.max_num_fields, separator=self.separator)

609614

self.list.extend(MiniFieldStorage(key, value) for key, value in query)

610615611616

klass = self.FieldStorageClass or self.__class__

@@ -649,7 +654,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):

649654

else self.limit - self.bytes_read

650655

part = klass(self.fp, headers, ib, environ, keep_blank_values,

651656

strict_parsing, limit,

652-

self.encoding, self.errors, max_num_fields)

657+

self.encoding, self.errors, max_num_fields, self.separator)

653658654659

if max_num_fields is not None:

655660

max_num_fields -= 1