Skip to content

Commit b47b956

Browse files
authored
Merge branch '3.10' into backport-5aaf416-3.10
2 parents f35f5c0 + cfaee20 commit b47b956

File tree

9 files changed

+474
-165
lines changed

9 files changed

+474
-165
lines changed

Lib/email/_header_value_parser.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ def get_fws(value):
10451045
fws = WhiteSpaceTerminal(value[:len(value)-len(newvalue)], 'fws')
10461046
return fws, newvalue
10471047

1048-
def get_encoded_word(value):
1048+
def get_encoded_word(value, terminal_type='vtext'):
10491049
""" encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
10501050
10511051
"""
@@ -1084,7 +1084,7 @@ def get_encoded_word(value):
10841084
ew.append(token)
10851085
continue
10861086
chars, *remainder = _wsp_splitter(text, 1)
1087-
vtext = ValueTerminal(chars, 'vtext')
1087+
vtext = ValueTerminal(chars, terminal_type)
10881088
_validate_xtext(vtext)
10891089
ew.append(vtext)
10901090
text = ''.join(remainder)
@@ -1126,7 +1126,7 @@ def get_unstructured(value):
11261126
valid_ew = True
11271127
if value.startswith('=?'):
11281128
try:
1129-
token, value = get_encoded_word(value)
1129+
token, value = get_encoded_word(value, 'utext')
11301130
except _InvalidEwError:
11311131
valid_ew = False
11321132
except errors.HeaderParseError:
@@ -1155,7 +1155,7 @@ def get_unstructured(value):
11551155
# the parser to go in an infinite loop.
11561156
if valid_ew and rfc2047_matcher.search(tok):
11571157
tok, *remainder = value.partition('=?')
1158-
vtext = ValueTerminal(tok, 'vtext')
1158+
vtext = ValueTerminal(tok, 'utext')
11591159
_validate_xtext(vtext)
11601160
unstructured.append(vtext)
11611161
value = ''.join(remainder)
@@ -2789,7 +2789,7 @@ def _refold_parse_tree(parse_tree, *, policy):
27892789
continue
27902790
tstr = str(part)
27912791
if not want_encoding:
2792-
if part.token_type == 'ptext':
2792+
if part.token_type in ('ptext', 'vtext'):
27932793
# Encode if tstr contains special characters.
27942794
want_encoding = not SPECIALSNL.isdisjoint(tstr)
27952795
else:

Lib/test/test_email/test__header_value_parser.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2973,6 +2973,31 @@ def test_address_list_with_specials_in_long_quoted_string(self):
29732973
with self.subTest(to=to):
29742974
self._test(parser.get_address_list(to)[0], folded, policy=policy)
29752975

2976+
def test_address_list_with_specials_in_encoded_word(self):
2977+
# An encoded-word parsed from a structured header must remain
2978+
# encoded when it contains specials. Regression for gh-121284.
2979+
policy = self.policy.clone(max_line_length=40)
2980+
cases = [
2981+
# (to, folded)
2982+
('=?utf-8?q?A_v=C3=A9ry_long_name_with=2C_comma?= <to@example.com>',
2983+
'A =?utf-8?q?v=C3=A9ry_long_name_with?=\n'
2984+
' =?utf-8?q?=2C?= comma <to@example.com>\n'),
2985+
('=?utf-8?q?This_long_name_does_not_need_encoded=2Dword?= <to@example.com>',
2986+
'This long name does not need\n'
2987+
' encoded-word <to@example.com>\n'),
2988+
('"A véry long name with, comma" <to@example.com>',
2989+
# (This isn't the best fold point, but it's not invalid.)
2990+
'A =?utf-8?q?v=C3=A9ry_long_name_with?=\n'
2991+
' =?utf-8?q?=2C?= comma <to@example.com>\n'),
2992+
('"A véry long name containing a, comma" <to@example.com>',
2993+
'A =?utf-8?q?v=C3=A9ry?= long name\n'
2994+
' containing =?utf-8?q?a=2C?= comma\n'
2995+
' <to@example.com>\n'),
2996+
]
2997+
for (to, folded) in cases:
2998+
with self.subTest(to=to):
2999+
self._test(parser.get_address_list(to)[0], folded, policy=policy)
3000+
29763001
# XXX Need tests with comments on various sides of a unicode token,
29773002
# and with unicode tokens in the comments. Spaces inside the quotes
29783003
# currently don't do the right thing.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
In :mod:`ssl`, system call failures that OpenSSL reports using
2+
``ERR_LIB_SYS`` are now raised as :exc:`OSError`.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Fix bug in the folding of rfc2047 encoded-words when flattening an email message
2+
using a modern email policy. Previously when an encoded-word was too long
3+
for a line, it would be decoded, split across lines, and re-encoded. But commas
4+
and other special characters in the original text could be left unencoded and
5+
unquoted. This could theoretically be used to spoof header lines using
6+
a carefully constructed encoded-word if the resulting rendered email was
7+
transmitted or re-parsed.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Upgrade to libexpat 2.7.0

Modules/_ssl.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,11 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
656656
errstr = "Some I/O error occurred";
657657
}
658658
} else {
659+
if (ERR_GET_LIB(e) == ERR_LIB_SYS) {
660+
// A system error is being reported; reason is set to errno
661+
errno = ERR_GET_REASON(e);
662+
return PyErr_SetFromErrno(PyExc_OSError);
663+
}
659664
p = PY_SSL_ERROR_SYSCALL;
660665
}
661666
break;
@@ -681,6 +686,11 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
681686
errstr = "EOF occurred in violation of protocol";
682687
}
683688
#endif
689+
if (ERR_GET_LIB(e) == ERR_LIB_SYS) {
690+
// A system error is being reported; reason is set to errno
691+
errno = ERR_GET_REASON(e);
692+
return PyErr_SetFromErrno(PyExc_OSError);
693+
}
684694
break;
685695
}
686696
default:

Modules/expat/expat.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
1212
Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
1313
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
14-
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
14+
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
1515
Copyright (c) 2016 Cristian Rodríguez <crrodriguez@opensuse.org>
1616
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
1717
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
@@ -1067,8 +1067,8 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
10671067
See https://semver.org
10681068
*/
10691069
#define XML_MAJOR_VERSION 2
1070-
#define XML_MINOR_VERSION 6
1071-
#define XML_MICRO_VERSION 4
1070+
#define XML_MINOR_VERSION 7
1071+
#define XML_MICRO_VERSION 0
10721072

10731073
#ifdef __cplusplus
10741074
}

Modules/expat/refresh.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ fi
1212

1313
# Update this when updating to a new version after verifying that the changes
1414
# the update brings in are good. These values are used for verifying the SBOM, too.
15-
expected_libexpat_tag="R_2_6_4"
16-
expected_libexpat_version="2.6.4"
17-
expected_libexpat_sha256="fd03b7172b3bd7427a3e7a812063f74754f24542429b634e0db6511b53fb2278"
15+
expected_libexpat_tag="R_2_7_0"
16+
expected_libexpat_version="2.7.0"
17+
expected_libexpat_sha256="362e89ca6b8a0d46fc5740a917eb2a8b4d6356edbe016eee09f49c0781215844"
1818

1919
expat_dir="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")"
2020
cd ${expat_dir}

0 commit comments

Comments
 (0)