From 749073af13fcb389059b182290f5cbc953222681 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Wed, 22 Jun 2011 13:47:53 -0400 Subject: #1874: detect invalid multipart CTE and report it as a defect. --- Lib/email/errors.py | 3 +++ Lib/email/feedparser.py | 5 +++++ Lib/test/test_email/test_email.py | 45 +++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 56 insertions(+) diff --git a/Lib/email/errors.py b/Lib/email/errors.py index c2ea7d4..c04deb4 100644 --- a/Lib/email/errors.py +++ b/Lib/email/errors.py @@ -55,3 +55,6 @@ class MalformedHeaderDefect(MessageDefect): class MultipartInvariantViolationDefect(MessageDefect): """A message claimed to be a multipart but no subparts were found.""" + +class InvalidMultipartContentTransferEncodingDefect(MessageDefect): + """An invalid content transfer encoding was set on the multipart itself.""" diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index 60de49e..e754d89 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -300,6 +300,11 @@ class FeedParser: lines.append(line) self._cur.set_payload(EMPTYSTRING.join(lines)) return + # Make sure a valid content type was specified per RFC 2045:6.4. + if (self._cur.get('content-transfer-encoding', '8bit').lower() + not in ('7bit', '8bit', 'binary')): + defect = errors.InvalidMultipartContentTransferEncodingDefect() + self.policy.handle_defect(self._cur, defect) # Create a line match predicate which matches the inter-part # boundary as well as the end-of-multipart boundary. Don't push # this onto the input stream until we've scanned past the diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 17451f3..121c939 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -1809,6 +1809,51 @@ class TestNonConformantBase: unless(isinstance(self.get_defects(msg)[1], errors.MultipartInvariantViolationDefect)) + multipart_msg = textwrap.dedent("""\ + Date: Wed, 14 Nov 2007 12:56:23 GMT + From: foo@bar.invalid + To: foo@bar.invalid + Subject: Content-Transfer-Encoding: base64 and multipart + MIME-Version: 1.0 + Content-Type: multipart/mixed; + boundary="===============3344438784458119861=="{} + + --===============3344438784458119861== + Content-Type: text/plain + + Test message + + --===============3344438784458119861== + Content-Type: application/octet-stream + Content-Transfer-Encoding: base64 + + YWJj + + --===============3344438784458119861==-- + """) + + def test_multipart_invalid_cte(self): + msg = email.message_from_string( + self.multipart_msg.format("\nContent-Transfer-Encoding: base64"), + policy = self.policy) + self.assertEqual(len(self.get_defects(msg)), 1) + self.assertIsInstance(self.get_defects(msg)[0], + errors.InvalidMultipartContentTransferEncodingDefect) + + def test_multipart_no_cte_no_defect(self): + msg = email.message_from_string( + self.multipart_msg.format(''), + policy = self.policy) + self.assertEqual(len(self.get_defects(msg)), 0) + + def test_multipart_valid_cte_no_defect(self): + for cte in ('7bit', '8bit', 'BINary'): + msg = email.message_from_string( + self.multipart_msg.format( + "\nContent-Transfer-Encoding: {}".format(cte)), + policy = self.policy) + self.assertEqual(len(self.get_defects(msg)), 0) + def test_invalid_content_type(self): eq = self.assertEqual neq = self.ndiffAssertEqual diff --git a/Misc/NEWS b/Misc/NEWS index 272141f..fc1fa87 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -196,6 +196,9 @@ Core and Builtins Library ------- +- Issue #1874: email now detects and reports as a defect the presence of + any CTE other than 7bit, 8bit, or binary on a multipart. + - Issue #12383: Fix subprocess module with env={}: don't copy the environment variables, start with an empty environment. -- cgit v0.12