bpo-33529, email: Fix infinite loop in email header encoding (GH-12020)

This commit is contained in:
Krzysztof Wojcik 2019-05-14 18:55:23 +02:00 committed by Victor Stinner
parent 4d45a3b110
commit c1f5667be1
4 changed files with 27 additions and 14 deletions

View File

@ -2723,16 +2723,19 @@ def _fold_as_ew(to_encode, lines, maxlen, last_ew, ew_combine_allowed, charset):
lines.append(' ')
# XXX We'll get an infinite loop here if maxlen is <= 7
continue
first_part = to_encode[:text_space]
ew = _ew.encode(first_part, charset=encode_as)
excess = len(ew) - remaining_space
if excess > 0:
# encode always chooses the shortest encoding, so this
# is guaranteed to fit at this point.
first_part = first_part[:-excess]
ew = _ew.encode(first_part)
lines[-1] += ew
to_encode = to_encode[len(first_part):]
to_encode_word = to_encode[:text_space]
encoded_word = _ew.encode(to_encode_word, charset=encode_as)
excess = len(encoded_word) - remaining_space
while excess > 0:
# Since the chunk to encode is guaranteed to fit into less than 100 characters,
# shrinking it by one at a time shouldn't take long.
to_encode_word = to_encode_word[:-1]
encoded_word = _ew.encode(to_encode_word, charset=encode_as)
excess = len(encoded_word) - remaining_space
lines[-1] += encoded_word
to_encode = to_encode[len(to_encode_word):]
if to_encode:
lines.append(' ')
new_last_ew = len(lines[-1])

View File

@ -1643,10 +1643,10 @@ class TestFolding(TestHeaderBase):
self.assertEqual(
h.fold(policy=policy.default),
'X-Report-Abuse: =?utf-8?q?=3Chttps=3A//www=2Emailitapp=2E'
'com/report=5F?=\n'
' =?utf-8?q?abuse=2Ephp=3Fmid=3Dxxx-xxx-xxxx'
'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-?=\n'
' =?utf-8?q?xx-xx=3E?=\n')
'com/report=5Fabuse?=\n'
' =?utf-8?q?=2Ephp=3Fmid=3Dxxx-xxx-xxxx'
'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-xx-xx?=\n'
' =?utf-8?q?=3E?=\n')
if __name__ == '__main__':

View File

@ -237,6 +237,14 @@ class PolicyAPITests(unittest.TestCase):
email.policy.EmailPolicy.header_factory)
self.assertEqual(newpolicy.__dict__, {'raise_on_defect': True})
def test_non_ascii_chars_do_not_cause_inf_loop(self):
policy = email.policy.default.clone(max_line_length=20)
actual = policy.fold('Subject', 'ą' * 12)
self.assertEqual(
actual,
'Subject: \n' +
12 * ' =?utf-8?q?=C4=85?=\n')
# XXX: Need subclassing tests.
# For adding subclassed objects, make sure the usual rules apply (subclass
# wins), but that the order still works (right overrides left).

View File

@ -0,0 +1,2 @@
Prevent fold function used in email header encoding from entering infinite
loop when there are too many non-ASCII characters in a header.