Skip to content

Commit 8cc9adb

Browse files
tsufekitimb07serhiy-storchaka
authored
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]>
1 parent 8123c34 commit 8cc9adb

File tree

4 files changed

+61
-5
lines changed

4 files changed

+61
-5
lines changed

Lib/email/_header_value_parser.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -566,12 +566,14 @@ def display_name(self):
566566
if res[0].token_type == 'cfws':
567567
res.pop(0)
568568
else:
569-
if res[0][0].token_type == 'cfws':
569+
if (isinstance(res[0], TokenList) and
570+
res[0][0].token_type == 'cfws'):
570571
res[0] = TokenList(res[0][1:])
571572
if res[-1].token_type == 'cfws':
572573
res.pop()
573574
else:
574-
if res[-1][-1].token_type == 'cfws':
575+
if (isinstance(res[-1], TokenList) and
576+
res[-1][-1].token_type == 'cfws'):
575577
res[-1] = TokenList(res[-1][:-1])
576578
return res.value
577579

@@ -586,9 +588,13 @@ def value(self):
586588
quote = True
587589
if len(self) != 0 and quote:
588590
pre = post = ''
589-
if self[0].token_type=='cfws' or self[0][0].token_type=='cfws':
591+
if (self[0].token_type == 'cfws' or
592+
isinstance(self[0], TokenList) and
593+
self[0][0].token_type == 'cfws'):
590594
pre = ' '
591-
if self[-1].token_type=='cfws' or self[-1][-1].token_type=='cfws':
595+
if (self[-1].token_type == 'cfws' or
596+
isinstance(self[-1], TokenList) and
597+
self[-1][-1].token_type == 'cfws'):
592598
post = ' '
593599
return pre+quote_string(self.display_name)+post
594600
else:
@@ -1772,7 +1778,10 @@ def get_name_addr(value):
17721778
raise errors.HeaderParseError(
17731779
"expected name-addr but found '{}'".format(token))
17741780
if leader is not None:
1775-
token[0][:0] = [leader]
1781+
if isinstance(token[0], TokenList):
1782+
token[0][:0] = [leader]
1783+
else:
1784+
token[:0] = [leader]
17761785
leader = None
17771786
name_addr.append(token)
17781787
token, value = get_angle_addr(value)

Lib/test/test_email/test__header_value_parser.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,32 @@ def test_get_name_addr_qs_name(self):
18051805
self.assertIsNone(name_addr.route)
18061806
self.assertEqual(name_addr.addr_spec, '[email protected]')
18071807

1808+
def test_get_name_addr_ending_with_dot_without_space(self):
1809+
name_addr = self._test_get_x(parser.get_name_addr,
1810+
'John X.<[email protected]>',
1811+
'John X.<[email protected]>',
1812+
'"John X."<[email protected]>',
1813+
[errors.ObsoleteHeaderDefect],
1814+
'')
1815+
self.assertEqual(name_addr.display_name, 'John X.')
1816+
self.assertEqual(name_addr.local_part, 'jxd')
1817+
self.assertEqual(name_addr.domain, 'example.com')
1818+
self.assertIsNone(name_addr.route)
1819+
self.assertEqual(name_addr.addr_spec, '[email protected]')
1820+
1821+
def test_get_name_addr_starting_with_dot(self):
1822+
name_addr = self._test_get_x(parser.get_name_addr,
1823+
'. Doe <[email protected]>',
1824+
'. Doe <[email protected]>',
1825+
'". Doe" <[email protected]>',
1826+
[errors.InvalidHeaderDefect, errors.ObsoleteHeaderDefect],
1827+
'')
1828+
self.assertEqual(name_addr.display_name, '. Doe')
1829+
self.assertEqual(name_addr.local_part, 'jxd')
1830+
self.assertEqual(name_addr.domain, 'example.com')
1831+
self.assertIsNone(name_addr.route)
1832+
self.assertEqual(name_addr.addr_spec, '[email protected]')
1833+
18081834
def test_get_name_addr_with_route(self):
18091835
name_addr = self._test_get_x(parser.get_name_addr,
18101836
'"Roy.A.Bear" <@two.example.com: [email protected]>',

Lib/test/test_email/test_headerregistry.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,26 @@ class TestAddressHeader(TestHeaderBase):
12371237
'example.com',
12381238
None),
12391239

1240+
'name_ending_with_dot_without_space':
1241+
('John X.<[email protected]>',
1242+
[errors.ObsoleteHeaderDefect],
1243+
'"John X." <[email protected]>',
1244+
'John X.',
1245+
1246+
'jxd',
1247+
'example.com',
1248+
None),
1249+
1250+
'name_starting_with_dot':
1251+
('. Doe <[email protected]>',
1252+
[errors.InvalidHeaderDefect, errors.ObsoleteHeaderDefect],
1253+
'". Doe" <[email protected]>',
1254+
'. Doe',
1255+
1256+
'jxd',
1257+
'example.com',
1258+
None),
1259+
12401260
}
12411261

12421262
# XXX: Need many more examples, and in particular some with names in
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix parsing of emails with invalid address headers having a leading or trailing dot. Patch by tsufeki.

0 commit comments

Comments
 (0)