mirror of
https://github.com/python/cpython.git
synced 2026-05-06 04:37:33 -04:00
gh-148518 fix index error in local part attribute (#148522)
As part of fixing bpo-27931 code was introduced to get_bare_quoted_string that added an empty Terminal if the quoted string was empty. This isn't the best answer in terms of the parse tree; we really want the token list to be empty in that case. But having it be empty resulted in local_part raising the index error. We find that same problem if we try to parse an address consisting of a single dquote. By fixing local_part to not raise on an empty token list, we can have the bare_quoted_string code correctly return an empty token list for the empty string cases (two dquotes or a single dquote as the entire addrespec, at the end of a line).
This commit is contained in:
@@ -639,11 +639,11 @@ class LocalPart(TokenList):
|
||||
for tok in self[0] + [DOT]:
|
||||
if tok.token_type == 'cfws':
|
||||
continue
|
||||
if (last_is_tl and tok.token_type == 'dot' and
|
||||
if (last_is_tl and tok.token_type == 'dot' and last and
|
||||
last[-1].token_type == 'cfws'):
|
||||
res[-1] = TokenList(last[:-1])
|
||||
is_tl = isinstance(tok, TokenList)
|
||||
if (is_tl and last.token_type == 'dot' and
|
||||
if (is_tl and last.token_type == 'dot' and tok and
|
||||
tok[0].token_type == 'cfws'):
|
||||
res.append(TokenList(tok[1:]))
|
||||
else:
|
||||
@@ -1249,8 +1249,7 @@ def get_bare_quoted_string(value):
|
||||
bare_quoted_string = BareQuotedString()
|
||||
value = value[1:]
|
||||
if value and value[0] == '"':
|
||||
token, value = get_qcontent(value)
|
||||
bare_quoted_string.append(token)
|
||||
return bare_quoted_string, value[1:]
|
||||
while value and value[0] != '"':
|
||||
if value[0] in WSP:
|
||||
token, value = get_fws(value)
|
||||
|
||||
@@ -1271,12 +1271,12 @@ class TestAddressHeader(TestHeaderBase):
|
||||
'example.com',
|
||||
None),
|
||||
|
||||
}
|
||||
|
||||
# XXX: Need many more examples, and in particular some with names in
|
||||
# trailing comments, which aren't currently handled. comments in
|
||||
# general are not handled yet.
|
||||
|
||||
}
|
||||
|
||||
def example_as_address(self, source, defects, decoded, display_name,
|
||||
addr_spec, username, domain, comment):
|
||||
h = self.make_header('sender', source)
|
||||
@@ -1294,6 +1294,43 @@ class TestAddressHeader(TestHeaderBase):
|
||||
# XXX: we have no comment support yet.
|
||||
#self.assertEqual(a.comment, comment)
|
||||
|
||||
example_broken_header_params = {
|
||||
|
||||
'just_dquote':
|
||||
('"',
|
||||
[errors.InvalidHeaderDefect]*2,
|
||||
'<>',
|
||||
'',
|
||||
'<>',
|
||||
'',
|
||||
'',
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
def example_broken_header_as_address(
|
||||
self,
|
||||
source,
|
||||
defects,
|
||||
decoded,
|
||||
display_name,
|
||||
addr_spec,
|
||||
username,
|
||||
domain,
|
||||
):
|
||||
h = self.make_header('sender', source)
|
||||
self.assertEqual(h, decoded)
|
||||
self.assertDefectsEqual(h.defects, defects)
|
||||
a = h.address
|
||||
self.assertEqual(str(a), decoded)
|
||||
self.assertEqual(len(h.groups), 1)
|
||||
self.assertEqual([a], list(h.groups[0].addresses))
|
||||
self.assertEqual([a], list(h.addresses))
|
||||
self.assertEqual(a.display_name, display_name)
|
||||
self.assertEqual(a.addr_spec, addr_spec)
|
||||
self.assertEqual(a.username, username)
|
||||
self.assertEqual(a.domain, domain)
|
||||
|
||||
def example_as_group(self, source, defects, decoded, display_name,
|
||||
addr_spec, username, domain, comment):
|
||||
source = 'foo: {};'.format(source)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
If an email containing an address header that ended in an open double quote
|
||||
was parsed with a non-``compat32`` policy, accessing the ``username`` attribute
|
||||
of the mailbox accessed through that header object would result in an
|
||||
``IndexError``. It now correctly returns an empty string as the result.
|
||||
Reference in New Issue
Block a user