diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index 7c07ca86457a2a..8e945ac26bf169 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -189,6 +189,7 @@ def close(self): assert not self._msgstack # Look for final set of defects if root.get_content_maintype() == 'multipart' \ + and not self._headersonly \ and not root.is_multipart(): defect = errors.MultipartInvariantViolationDefect() self.policy.handle_defect(root, defect) diff --git a/Lib/http/client.py b/Lib/http/client.py index 5aa178d7b127d9..74825ba0b99540 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -211,7 +211,7 @@ def parse_headers(fp, _class=HTTPMessage): if line in (b'\r\n', b'\n', b''): break hstring = b''.join(headers).decode('iso-8859-1') - return email.parser.Parser(_class=_class).parsestr(hstring) + return email.parser.Parser(_class=_class).parsestr(hstring, headersonly=True) class HTTPResponse(io.BufferedIOBase): diff --git a/Lib/test/test_email/test_parser.py b/Lib/test/test_email/test_parser.py index 06c86408ab52b9..45a6d861580a94 100644 --- a/Lib/test/test_email/test_parser.py +++ b/Lib/test/test_email/test_parser.py @@ -5,6 +5,12 @@ from email.policy import default from test.test_email import TestEmailBase +class TestFeedParser(TestEmailBase): + def test_multipart_message_with_headers_only(self): + import email.parser + header = 'Content-Type: multipart/related; boundary="==="\r\n\r\n' + msg = email.parser.Parser().parsestr(header, headersonly=True) + self.assertDefectsEqual(msg.defects, []) class TestCustomMessage(TestEmailBase): diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index f816eac83b682d..7c7446c42ac8fc 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -359,6 +359,11 @@ def test_headers_debuglevel(self): self.assertEqual(lines[1], "header: First: val") self.assertEqual(lines[2], "header: Second: val") + def test_parse_valid_multipart_header(self): + header = b'Content-Type: multipart/related; boundary="==="\r\n\r\n' + fp = io.BytesIO(header) + message = client.parse_headers(fp) + self.assertListEqual(message.defects, []) class TransferEncodingTest(TestCase): expected_body = b"It's just a flesh wound" diff --git a/Misc/NEWS.d/next/Library/2019-09-05-12-13-11.bpo-36226.J5mcDO.rst b/Misc/NEWS.d/next/Library/2019-09-05-12-13-11.bpo-36226.J5mcDO.rst new file mode 100644 index 00000000000000..7ab68b926cc83d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-05-12-13-11.bpo-36226.J5mcDO.rst @@ -0,0 +1,2 @@ +Fixes false MultipartInvariantViolationDefects which were triggered when +only headers of a multipart message were parsed. diff --git a/Misc/NEWS.d/next/Library/2019-09-05-12-14-30.bpo-36226.KJV4rP.rst b/Misc/NEWS.d/next/Library/2019-09-05-12-14-30.bpo-36226.KJV4rP.rst new file mode 100644 index 00000000000000..98270ea2dba595 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-05-12-14-30.bpo-36226.KJV4rP.rst @@ -0,0 +1,2 @@ +Fixes false StartBoundaryNotFoundDefects which were triggered by +parse_headers not forwarding the headersonly to the email parser.