]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-43323: Fix UnicodeEncodeError in the email module (GH-32137)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 30 Apr 2022 12:31:37 +0000 (05:31 -0700)
committerGitHub <noreply@github.com>
Sat, 30 Apr 2022 12:31:37 +0000 (05:31 -0700)
It was raised if the charset itself contains characters not encodable
in UTF-8 (in particular \udcxx characters representing non-decodable
bytes in the source).
(cherry picked from commit e91dee87edcf6dee5dd78053004d76e5f05456d4)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Lib/email/_encoded_words.py
Lib/email/_header_value_parser.py
Lib/test/test_email/test__encoded_words.py
Lib/test/test_email/test_email.py
Lib/test/test_email/test_headerregistry.py
Misc/NEWS.d/next/Library/2022-03-27-12-40-16.bpo-43323.9mFPuI.rst [new file with mode: 0644]

index 295ae7eb21237c6d9dd3be3bdcdc24f378b7d64a..6795a606de037e2e428f95087e394e9e16a5ebbb 100644 (file)
@@ -179,15 +179,15 @@ def decode(ew):
     # Turn the CTE decoded bytes into unicode.
     try:
         string = bstring.decode(charset)
-    except UnicodeError:
+    except UnicodeDecodeError:
         defects.append(errors.UndecodableBytesDefect("Encoded word "
-            "contains bytes not decodable using {} charset".format(charset)))
+            f"contains bytes not decodable using {charset!r} charset"))
         string = bstring.decode(charset, 'surrogateescape')
-    except LookupError:
+    except (LookupError, UnicodeEncodeError):
         string = bstring.decode('ascii', 'surrogateescape')
         if charset.lower() != 'unknown-8bit':
-            defects.append(errors.CharsetError("Unknown charset {} "
-                "in encoded word; decoded as unknown bytes".format(charset)))
+            defects.append(errors.CharsetError(f"Unknown charset {charset!r} "
+                f"in encoded word; decoded as unknown bytes"))
     return string, charset, lang, defects
 
 
index 51d355fbb0abc5460835414998983717256e9364..8a8fb8bc42a954038aa135957718914815e87d25 100644 (file)
@@ -781,7 +781,7 @@ class MimeParameters(TokenList):
                     else:
                         try:
                             value = value.decode(charset, 'surrogateescape')
-                        except LookupError:
+                        except (LookupError, UnicodeEncodeError):
                             # XXX: there should really be a custom defect for
                             # unknown character set to make it easy to find,
                             # because otherwise unknown charset is a silent
index 0b8b1de3359aa6e68e04110e6b40de4dcd94f6a8..1713962f94caef24515b2d49fb39811cc7d9944a 100644 (file)
@@ -130,6 +130,13 @@ class TestDecode(TestEmailBase):
                    # XXX Should this be a new Defect instead?
                    defects = [errors.CharsetError])
 
+    def test_invalid_character_in_charset(self):
+        self._test('=?utf-8\udce2\udc80\udc9d?q?foo=ACbar?=',
+                   b'foo\xacbar'.decode('ascii', 'surrogateescape'),
+                   charset = 'utf-8\udce2\udc80\udc9d',
+                   # XXX Should this be a new Defect instead?
+                   defects = [errors.CharsetError])
+
     def test_q_nonascii(self):
         self._test('=?utf-8?q?=C3=89ric?=',
                    'Éric',
index 489cd05be4dd5823953ab3d9ec2520910f15eaf3..761ea90b78f15330029b148076d4d379bef303c9 100644 (file)
@@ -5323,6 +5323,15 @@ Content-Disposition: inline;
 Content-Transfer-Encoding: 8bit
 Content-Disposition: inline; filename*=X-UNKNOWN''myfile.txt
 
+"""
+        msg = email.message_from_string(m)
+        self.assertEqual(msg.get_filename(), 'myfile.txt')
+
+    def test_rfc2231_bad_character_in_encoding(self):
+        m = """\
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline; filename*=utf-8\udce2\udc80\udc9d''myfile.txt
+
 """
         msg = email.message_from_string(m)
         self.assertEqual(msg.get_filename(), 'myfile.txt')
index 68bbc9561c4aff1f238b362df0f2ef1a1a30952e..9a512fdb9d7785136e3403d13ccbb29763d13272 100644 (file)
@@ -698,6 +698,18 @@ class TestContentTypeHeader(TestHeaderBase):
             " charset*=unknown-8bit''utf-8%E2%80%9D\n",
             ),
 
+        'rfc2231_nonascii_in_charset_of_charset_parameter_value': (
+            "text/plain; charset*=utf-8”''utf-8%E2%80%9D",
+            'text/plain',
+            'text',
+            'plain',
+            {'charset': 'utf-8”'},
+            [],
+            'text/plain; charset="utf-8”"',
+            "Content-Type: text/plain;"
+            " charset*=utf-8''utf-8%E2%80%9D\n",
+            ),
+
         'rfc2231_encoded_then_unencoded_segments': (
             ('application/x-foo;'
                 '\tname*0*="us-ascii\'en-us\'My";'
diff --git a/Misc/NEWS.d/next/Library/2022-03-27-12-40-16.bpo-43323.9mFPuI.rst b/Misc/NEWS.d/next/Library/2022-03-27-12-40-16.bpo-43323.9mFPuI.rst
new file mode 100644 (file)
index 0000000..98d7310
--- /dev/null
@@ -0,0 +1,2 @@
+Fix errors in the :mod:`email` module if the charset itself contains
+undecodable/unencodable characters.