bpo-34226: fix cgi.parse_multipart without content_length (GH-8530)

In Python 3.7 the behavior of parse_multipart changed requiring CONTENT-LENGTH
header, this fix remove this header as required and fix FieldStorage
read_lines_to_outerboundary, by not using limit when it's negative,
since by default it's -1 if not content-length and keeps substracting what
was read from the file object.

Also added a test case for this problem.
This commit is contained in:
roger 2020-06-15 16:58:54 +02:00 committed by GitHub
parent e2d47a0568
commit d8cf3514dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 2 deletions

View File

@ -200,7 +200,10 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
ctype = "multipart/form-data; boundary={}".format(boundary) ctype = "multipart/form-data; boundary={}".format(boundary)
headers = Message() headers = Message()
headers.set_type(ctype) headers.set_type(ctype)
headers['Content-Length'] = pdict['CONTENT-LENGTH'] try:
headers['Content-Length'] = pdict['CONTENT-LENGTH']
except KeyError:
pass
fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors, 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}
@ -736,7 +739,8 @@ class FieldStorage:
last_line_lfend = True last_line_lfend = True
_read = 0 _read = 0
while 1: while 1:
if self.limit is not None and _read >= self.limit:
if self.limit is not None and 0 <= self.limit <= _read:
break break
line = self.fp.readline(1<<16) # bytes line = self.fp.readline(1<<16) # bytes
self.bytes_read += len(line) self.bytes_read += len(line)

View File

@ -128,6 +128,20 @@ 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_without_content_length(self):
POSTDATA = '''--JfISa01
Content-Disposition: form-data; name="submit-name"
just a string
--JfISa01--
'''
fp = BytesIO(POSTDATA.encode('latin1'))
env = {'boundary': 'JfISa01'.encode('latin1')}
result = cgi.parse_multipart(fp, env)
expected = {'submit-name': ['just a string\n']}
self.assertEqual(result, expected)
def test_parse_multipart_invalid_encoding(self): def test_parse_multipart_invalid_encoding(self):
BOUNDARY = "JfISa01" BOUNDARY = "JfISa01"
POSTDATA = """--JfISa01 POSTDATA = """--JfISa01

View File

@ -0,0 +1 @@
Fix `cgi.parse_multipart` without content_length. Patch by Roger Duran