From 6b102f251f086feb058ed9aac8072bbafe362372 Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Wed, 23 Jan 2013 02:50:15 -0800 Subject: [PATCH] Issue #12411: Fix to cgi.parse_multipart to correctly use bytes boundaries and bytes data. Patch by Jonas Wagner. --- Lib/cgi.py | 18 +++++++++--------- Lib/test/test_cgi.py | 21 ++++++++++++++++++++- Misc/NEWS | 3 +++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Lib/cgi.py b/Lib/cgi.py index 90a33450bc0..ad6b1f88a9f 100755 --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -214,17 +214,17 @@ def parse_multipart(fp, pdict): """ import http.client - boundary = "" + boundary = b"" if 'boundary' in pdict: boundary = pdict['boundary'] if not valid_boundary(boundary): raise ValueError('Invalid boundary in multipart form: %r' % (boundary,)) - nextpart = "--" + boundary - lastpart = "--" + boundary + "--" + nextpart = b"--" + boundary + lastpart = b"--" + boundary + b"--" partdict = {} - terminator = "" + terminator = b"" while terminator != lastpart: bytes = -1 @@ -243,7 +243,7 @@ def parse_multipart(fp, pdict): raise ValueError('Maximum content length exceeded') data = fp.read(bytes) else: - data = "" + data = b"" # Read lines until end of part. lines = [] while 1: @@ -251,7 +251,7 @@ def parse_multipart(fp, pdict): if not line: terminator = lastpart # End outer loop break - if line.startswith("--"): + if line.startswith(b"--"): terminator = line.rstrip() if terminator in (nextpart, lastpart): break @@ -263,12 +263,12 @@ def parse_multipart(fp, pdict): if lines: # Strip final line terminator line = lines[-1] - if line[-2:] == "\r\n": + if line[-2:] == b"\r\n": line = line[:-2] - elif line[-1:] == "\n": + elif line[-1:] == b"\n": line = line[:-1] lines[-1] = line - data = "".join(lines) + data = b"".join(lines) line = headers['content-disposition'] if not line: continue diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py index 3031fb38262..07e760b8e31 100644 --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -4,6 +4,7 @@ import os import sys import tempfile import unittest +from collections import namedtuple from io import StringIO, BytesIO class HackedSysModule: @@ -118,6 +119,23 @@ def gen_result(data, environ): class CgiTests(unittest.TestCase): + def test_parse_multipart(self): + fp = BytesIO(POSTDATA.encode('latin1')) + env = {'boundary': BOUNDARY.encode('latin1'), + 'CONTENT-LENGTH': '558'} + result = cgi.parse_multipart(fp, env) + expected = {'submit': [b' Add '], 'id': [b'1234'], + 'file': [b'Testing 123.\n'], 'title': [b'']} + self.assertEqual(result, expected) + + def test_fieldstorage_properties(self): + fs = cgi.FieldStorage() + self.assertFalse(fs) + self.assertIn("FieldStorage", repr(fs)) + self.assertEqual(list(fs), list(fs.keys())) + fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue')) + self.assertTrue(fs) + def test_escape(self): self.assertEqual("test & string", cgi.escape("test & string")) self.assertEqual("<test string>", cgi.escape("")) @@ -151,7 +169,8 @@ class CgiTests(unittest.TestCase): def test_log(self): cgi.log("Testing") - + cgi.logfile = "fail/" + cgi.initlog("%s", "Testing initlog") cgi.logfp = StringIO() cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") diff --git a/Misc/NEWS b/Misc/NEWS index c8045167b36..147b57c0ced 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -202,6 +202,9 @@ Core and Builtins Library ------- +- Issue #12411: Fix to cgi.parse_multipart to correctly use bytes boundaries + and bytes data. Patch by Jonas Wagner. + - Issue #1159051: GzipFile now raises EOFError when reading a corrupted file with truncated header or footer.