gh-39128: Fix email.utils.unquote() parameter parsing

This commit is contained in:
Shamil Abdulaev 2025-11-18 13:05:27 +03:00
parent 630cd37bfa
commit 3fa13e8af5
No known key found for this signature in database
GPG key ID: F9F7726024C005E7
3 changed files with 43 additions and 2 deletions

View file

@ -357,8 +357,16 @@ def parseaddr(addr, *, strict=True):
def unquote(str): def unquote(str):
"""Remove quotes from a string.""" """Remove quotes from a string."""
if len(str) > 1: if len(str) > 1:
if str.startswith('"') and str.endswith('"'): if str.startswith('"'):
return str[1:-1].replace('\\\\', '\\').replace('\\"', '"') pos = 1
while pos < len(str):
if str[pos] == '\\' and pos + 1 < len(str):
pos += 2
elif str[pos] == '"':
content = str[1:pos]
return re.sub(r'\\(.)', r'\1', content)
else:
pos += 1
if str.startswith('<') and str.endswith('>'): if str.startswith('<') and str.endswith('>'):
return str[1:-1] return str[1:-1]
return str return str

View file

@ -186,5 +186,35 @@ def test_formatdate_with_localtime(self):
string = utils.formatdate(timeval, localtime=True) string = utils.formatdate(timeval, localtime=True)
self.assertEqual(string, 'Thu, 01 Dec 2011 18:00:00 +0300') self.assertEqual(string, 'Thu, 01 Dec 2011 18:00:00 +0300')
class UnquoteTests(unittest.TestCase):
def test_unquote_basic(self):
self.assertEqual(utils.unquote('"value"'), 'value')
def test_unquote_with_trailing_garbage(self):
self.assertEqual(utils.unquote('"bound"\n\tX-Priority: 3'), 'bound')
def test_unquote_with_escaped_quote(self):
self.assertEqual(utils.unquote(r'"val\"ue"'), 'val"ue')
def test_unquote_with_escaped_backslash(self):
self.assertEqual(utils.unquote(r'"val\\ue"'), r'val\ue')
def test_unquote_angle_brackets(self):
self.assertEqual(utils.unquote('<value>'), 'value')
def test_unquote_no_quotes(self):
self.assertEqual(utils.unquote('value'), 'value')
def test_unquote_single_char(self):
self.assertEqual(utils.unquote('v'), 'v')
def test_unquote_empty_quoted(self):
self.assertEqual(utils.unquote('""'), '')
def test_unquote_mixed_escapes(self):
self.assertEqual(utils.unquote(r'"a\\b\"c"'), r'a\b"c')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View file

@ -0,0 +1,3 @@
Fix :func:`email.utils.unquote` to properly handle quoted strings with
trailing garbage by extracting only content between quotes and using
single-pass unescaping for RFC 2822 compliance. Patched by Shamil Abdulaev.