https://github.com/python/cpython/commit/8cc9adbfddc8e37cf7d621b12754eecb0584f5da
commit: 8cc9adbfddc8e37cf7d621b12754eecb0584f5da
branch: main
author: tsufeki <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2024-04-17T10:39:15+03:00
summary:

gh-75171: Fix parsing invalid email address headers starting or ending with a 
dot (GH-15600)

Co-authored-by: Tim Bell <[email protected]>
Co-authored-by: Serhiy Storchaka <[email protected]>

files:
A Misc/NEWS.d/next/Library/2019-08-29-20-26-08.bpo-30988.b-_h5O.rst
M Lib/email/_header_value_parser.py
M Lib/test/test_email/test__header_value_parser.py
M Lib/test/test_email/test_headerregistry.py

diff --git a/Lib/email/_header_value_parser.py 
b/Lib/email/_header_value_parser.py
index e4a342d446f6a3..0cf23fc9f656b1 100644
--- a/Lib/email/_header_value_parser.py
+++ b/Lib/email/_header_value_parser.py
@@ -566,12 +566,14 @@ def display_name(self):
         if res[0].token_type == 'cfws':
             res.pop(0)
         else:
-            if res[0][0].token_type == 'cfws':
+            if (isinstance(res[0], TokenList) and
+                    res[0][0].token_type == 'cfws'):
                 res[0] = TokenList(res[0][1:])
         if res[-1].token_type == 'cfws':
             res.pop()
         else:
-            if res[-1][-1].token_type == 'cfws':
+            if (isinstance(res[-1], TokenList) and
+                    res[-1][-1].token_type == 'cfws'):
                 res[-1] = TokenList(res[-1][:-1])
         return res.value
 
@@ -586,9 +588,13 @@ def value(self):
                     quote = True
         if len(self) != 0 and quote:
             pre = post = ''
-            if self[0].token_type=='cfws' or self[0][0].token_type=='cfws':
+            if (self[0].token_type == 'cfws' or
+                isinstance(self[0], TokenList) and
+                self[0][0].token_type == 'cfws'):
                 pre = ' '
-            if self[-1].token_type=='cfws' or self[-1][-1].token_type=='cfws':
+            if (self[-1].token_type == 'cfws' or
+                isinstance(self[-1], TokenList) and
+                self[-1][-1].token_type == 'cfws'):
                 post = ' '
             return pre+quote_string(self.display_name)+post
         else:
@@ -1772,7 +1778,10 @@ def get_name_addr(value):
             raise errors.HeaderParseError(
                 "expected name-addr but found '{}'".format(token))
         if leader is not None:
-            token[0][:0] = [leader]
+            if isinstance(token[0], TokenList):
+                token[0][:0] = [leader]
+            else:
+                token[:0] = [leader]
             leader = None
         name_addr.append(token)
     token, value = get_angle_addr(value)
diff --git a/Lib/test/test_email/test__header_value_parser.py 
b/Lib/test/test_email/test__header_value_parser.py
index f7e80749c456f8..dd1af9954c61da 100644
--- a/Lib/test/test_email/test__header_value_parser.py
+++ b/Lib/test/test_email/test__header_value_parser.py
@@ -1805,6 +1805,32 @@ def test_get_name_addr_qs_name(self):
         self.assertIsNone(name_addr.route)
         self.assertEqual(name_addr.addr_spec, '[email protected]')
 
+    def test_get_name_addr_ending_with_dot_without_space(self):
+        name_addr = self._test_get_x(parser.get_name_addr,
+            'John X.<[email protected]>',
+            'John X.<[email protected]>',
+            '"John X."<[email protected]>',
+            [errors.ObsoleteHeaderDefect],
+            '')
+        self.assertEqual(name_addr.display_name, 'John X.')
+        self.assertEqual(name_addr.local_part, 'jxd')
+        self.assertEqual(name_addr.domain, 'example.com')
+        self.assertIsNone(name_addr.route)
+        self.assertEqual(name_addr.addr_spec, '[email protected]')
+
+    def test_get_name_addr_starting_with_dot(self):
+        name_addr = self._test_get_x(parser.get_name_addr,
+            '. Doe <[email protected]>',
+            '. Doe <[email protected]>',
+            '". Doe" <[email protected]>',
+            [errors.InvalidHeaderDefect, errors.ObsoleteHeaderDefect],
+            '')
+        self.assertEqual(name_addr.display_name, '. Doe')
+        self.assertEqual(name_addr.local_part, 'jxd')
+        self.assertEqual(name_addr.domain, 'example.com')
+        self.assertIsNone(name_addr.route)
+        self.assertEqual(name_addr.addr_spec, '[email protected]')
+
     def test_get_name_addr_with_route(self):
         name_addr = self._test_get_x(parser.get_name_addr,
             '"Roy.A.Bear" <@two.example.com: [email protected]>',
diff --git a/Lib/test/test_email/test_headerregistry.py 
b/Lib/test/test_email/test_headerregistry.py
index 25347ef13c2147..bb7ca8dfd8c52c 100644
--- a/Lib/test/test_email/test_headerregistry.py
+++ b/Lib/test/test_email/test_headerregistry.py
@@ -1237,6 +1237,26 @@ class TestAddressHeader(TestHeaderBase):
             'example.com',
             None),
 
+        'name_ending_with_dot_without_space':
+            ('John X.<[email protected]>',
+             [errors.ObsoleteHeaderDefect],
+             '"John X." <[email protected]>',
+             'John X.',
+             '[email protected]',
+             'jxd',
+             'example.com',
+             None),
+
+        'name_starting_with_dot':
+            ('. Doe <[email protected]>',
+             [errors.InvalidHeaderDefect, errors.ObsoleteHeaderDefect],
+             '". Doe" <[email protected]>',
+             '. Doe',
+             '[email protected]',
+             'jxd',
+             'example.com',
+             None),
+
         }
 
         # XXX: Need many more examples, and in particular some with names in
diff --git a/Misc/NEWS.d/next/Library/2019-08-29-20-26-08.bpo-30988.b-_h5O.rst 
b/Misc/NEWS.d/next/Library/2019-08-29-20-26-08.bpo-30988.b-_h5O.rst
new file mode 100644
index 00000000000000..c776c73ba160e0
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-08-29-20-26-08.bpo-30988.b-_h5O.rst
@@ -0,0 +1 @@
+Fix parsing of emails with invalid address headers having a leading or 
trailing dot. Patch by tsufeki.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to