Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ff9616b

Browse files
committed
Merge #19772: Do not mutate message when downcoding to 7bit.
2 parents 99b1f2b + 905c8c3 commit ff9616b

4 files changed

Lines changed: 29 additions & 2 deletions

File tree

Lib/email/generator.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import random
1313
import warnings
1414

15+
from copy import deepcopy
1516
from io import StringIO, BytesIO
1617
from email._policybase import compat32
1718
from email.header import Header
@@ -173,10 +174,18 @@ def _write(self, msg):
173174
# necessary.
174175
oldfp = self._fp
175176
try:
177+
self._munge_cte = None
176178
self._fp = sfp = self._new_buffer()
177179
self._dispatch(msg)
178180
finally:
179181
self._fp = oldfp
182+
munge_cte = self._munge_cte
183+
del self._munge_cte
184+
# If we munged the cte, copy the message again and re-fix the CTE.
185+
if munge_cte:
186+
msg = deepcopy(msg)
187+
msg.replace_header('content-transfer-encoding', munge_cte[0])
188+
msg.replace_header('content-type', munge_cte[1])
180189
# Write the headers. First we see if the message object wants to
181190
# handle that itself. If not, we'll do it generically.
182191
meth = getattr(msg, '_write_headers', None)
@@ -225,9 +234,14 @@ def _handle_text(self, msg):
225234
if _has_surrogates(msg._payload):
226235
charset = msg.get_param('charset')
227236
if charset is not None:
237+
# XXX: This copy stuff is an ugly hack to avoid modifying the
238+
# existing message.
239+
msg = deepcopy(msg)
228240
del msg['content-transfer-encoding']
229241
msg.set_payload(payload, charset)
230242
payload = msg.get_payload()
243+
self._munge_cte = (msg['content-transfer-encoding'],
244+
msg['content-type'])
231245
if self._mangle_from_:
232246
payload = fcre.sub('>From ', payload)
233247
self._write_lines(payload)

Lib/test/test_email/test_contentmanager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ def test_set_message_with_non_ascii_and_coercion_to_7bit(self):
536536
537537
Subject: Help
538538
Content-Type: text/plain; charset="utf-8"
539-
MIME-Version: 1.0
540539
Content-Transfer-Encoding: base64
540+
MIME-Version: 1.0
541541
542542
aidhaSB1biBwcm9ibMOobWUgZGUgcHl0aG9uLiBpbCBlc3Qgc29ydGkgZGUgc29uIHZpdmFyaXVt
543543
Lgo=

Lib/test/test_email/test_email.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3529,7 +3529,7 @@ def test_CRLFLF_at_end_of_part(self):
35293529
self.assertTrue(msg.get_payload(0).get_payload().endswith('\r\n'))
35303530

35313531

3532-
class Test8BitBytesHandling(unittest.TestCase):
3532+
class Test8BitBytesHandling(TestEmailBase):
35333533
# In Python3 all input is string, but that doesn't work if the actual input
35343534
# uses an 8bit transfer encoding. To hack around that, in email 5.1 we
35353535
# decode byte streams using the surrogateescape error handler, and
@@ -3782,6 +3782,16 @@ def test_generator_handles_8bit(self):
37823782
email.generator.Generator(out).flatten(msg)
37833783
self.assertEqual(out.getvalue(), self.non_latin_bin_msg_as7bit_wrapped)
37843784

3785+
def test_str_generator_should_not_mutate_msg_when_handling_8bit(self):
3786+
msg = email.message_from_bytes(self.non_latin_bin_msg)
3787+
out = BytesIO()
3788+
BytesGenerator(out).flatten(msg)
3789+
orig_value = out.getvalue()
3790+
Generator(StringIO()).flatten(msg) # Should not mutate msg!
3791+
out = BytesIO()
3792+
BytesGenerator(out).flatten(msg)
3793+
self.assertEqual(out.getvalue(), orig_value)
3794+
37853795
def test_bytes_generator_with_unix_from(self):
37863796
# The unixfrom contains a current date, so we can't check it
37873797
# literally. Just make sure the first word is 'From' and the

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ Core and Builtins
2727
Library
2828
-------
2929

30+
- Issue #19772: email.generator no longer mutates the message object when
31+
doing a down-transform from 8bit to 7bit CTEs.
32+
3033
- Issue #20536: the statistics module now correctly handle Decimal instances
3134
with positive exponents
3235

0 commit comments

Comments
 (0)