bpo-33497: Add errors param to cgi.parse_multipart and make an encoding in FieldStorage use the given errors (GH-6804) (GH-6837)
(cherry picked from commit 545c955be9
)
Co-authored-by: Amber Brown <hawkowl@atleastfornow.net>
This commit is contained in:
parent
8e633a4035
commit
e8f968dcde
|
@ -296,7 +296,7 @@ algorithms implemented in this module in other circumstances.
|
||||||
instead. It is maintained here only for backward compatibility.
|
instead. It is maintained here only for backward compatibility.
|
||||||
|
|
||||||
|
|
||||||
.. function:: parse_multipart(fp, pdict, encoding="utf-8")
|
.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
Parse input of type :mimetype:`multipart/form-data` (for file uploads).
|
Parse input of type :mimetype:`multipart/form-data` (for file uploads).
|
||||||
Arguments are *fp* for the input file, *pdict* for a dictionary containing
|
Arguments are *fp* for the input file, *pdict* for a dictionary containing
|
||||||
|
@ -312,8 +312,8 @@ algorithms implemented in this module in other circumstances.
|
||||||
which is much more flexible.
|
which is much more flexible.
|
||||||
|
|
||||||
.. versionchanged:: 3.7
|
.. versionchanged:: 3.7
|
||||||
Added the *encoding* parameter. For non-file fields, the value is now
|
Added the *encoding* and *errors* parameters. For non-file fields, the
|
||||||
a list of strings, not bytes.
|
value is now a list of strings, not bytes.
|
||||||
|
|
||||||
|
|
||||||
.. function:: parse_header(string)
|
.. function:: parse_header(string)
|
||||||
|
|
10
Lib/cgi.py
10
Lib/cgi.py
|
@ -198,13 +198,14 @@ def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
|
||||||
DeprecationWarning, 2)
|
DeprecationWarning, 2)
|
||||||
return urllib.parse.parse_qsl(qs, keep_blank_values, strict_parsing)
|
return urllib.parse.parse_qsl(qs, keep_blank_values, strict_parsing)
|
||||||
|
|
||||||
def parse_multipart(fp, pdict, encoding="utf-8"):
|
def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
|
||||||
"""Parse multipart input.
|
"""Parse multipart input.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
fp : input file
|
fp : input file
|
||||||
pdict: dictionary containing other parameters of content-type header
|
pdict: dictionary containing other parameters of content-type header
|
||||||
encoding: request encoding
|
encoding, errors: request encoding and error handler, passed to
|
||||||
|
FieldStorage
|
||||||
|
|
||||||
Returns a dictionary just like parse_qs(): keys are the field names, each
|
Returns a dictionary just like parse_qs(): keys are the field names, each
|
||||||
value is a list of values for that field. For non-file fields, the value
|
value is a list of values for that field. For non-file fields, the value
|
||||||
|
@ -217,7 +218,7 @@ def parse_multipart(fp, pdict, encoding="utf-8"):
|
||||||
headers = Message()
|
headers = Message()
|
||||||
headers.set_type(ctype)
|
headers.set_type(ctype)
|
||||||
headers['Content-Length'] = pdict['CONTENT-LENGTH']
|
headers['Content-Length'] = pdict['CONTENT-LENGTH']
|
||||||
fs = FieldStorage(fp, headers=headers, encoding=encoding,
|
fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,
|
||||||
environ={'REQUEST_METHOD': 'POST'})
|
environ={'REQUEST_METHOD': 'POST'})
|
||||||
return {k: fs.getlist(k) for k in fs}
|
return {k: fs.getlist(k) for k in fs}
|
||||||
|
|
||||||
|
@ -458,7 +459,8 @@ class FieldStorage:
|
||||||
self.type = ctype
|
self.type = ctype
|
||||||
self.type_options = pdict
|
self.type_options = pdict
|
||||||
if 'boundary' in pdict:
|
if 'boundary' in pdict:
|
||||||
self.innerboundary = pdict['boundary'].encode(self.encoding)
|
self.innerboundary = pdict['boundary'].encode(self.encoding,
|
||||||
|
self.errors)
|
||||||
else:
|
else:
|
||||||
self.innerboundary = b""
|
self.innerboundary = b""
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,24 @@ class CgiTests(unittest.TestCase):
|
||||||
'file': [b'Testing 123.\n'], 'title': ['']}
|
'file': [b'Testing 123.\n'], 'title': ['']}
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_parse_multipart_invalid_encoding(self):
|
||||||
|
BOUNDARY = "JfISa01"
|
||||||
|
POSTDATA = """--JfISa01
|
||||||
|
Content-Disposition: form-data; name="submit-name"
|
||||||
|
Content-Length: 3
|
||||||
|
|
||||||
|
\u2603
|
||||||
|
--JfISa01"""
|
||||||
|
fp = BytesIO(POSTDATA.encode('utf8'))
|
||||||
|
env = {'boundary': BOUNDARY.encode('latin1'),
|
||||||
|
'CONTENT-LENGTH': str(len(POSTDATA.encode('utf8')))}
|
||||||
|
result = cgi.parse_multipart(fp, env, encoding="ascii",
|
||||||
|
errors="surrogateescape")
|
||||||
|
expected = {'submit-name': ["\udce2\udc98\udc83"]}
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
self.assertEqual("\u2603".encode('utf8'),
|
||||||
|
result["submit-name"][0].encode('utf8', 'surrogateescape'))
|
||||||
|
|
||||||
def test_fieldstorage_properties(self):
|
def test_fieldstorage_properties(self):
|
||||||
fs = cgi.FieldStorage()
|
fs = cgi.FieldStorage()
|
||||||
self.assertFalse(fs)
|
self.assertFalse(fs)
|
||||||
|
|
Loading…
Reference in New Issue