mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
Merge #19772: Do not mutate message when downcoding to 7bit.
This commit is contained in:
commit
ff9616bbf7
4 changed files with 29 additions and 2 deletions
|
@ -12,6 +12,7 @@ import time
|
||||||
import random
|
import random
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO, BytesIO
|
||||||
from email._policybase import compat32
|
from email._policybase import compat32
|
||||||
from email.header import Header
|
from email.header import Header
|
||||||
|
@ -173,10 +174,18 @@ class Generator:
|
||||||
# necessary.
|
# necessary.
|
||||||
oldfp = self._fp
|
oldfp = self._fp
|
||||||
try:
|
try:
|
||||||
|
self._munge_cte = None
|
||||||
self._fp = sfp = self._new_buffer()
|
self._fp = sfp = self._new_buffer()
|
||||||
self._dispatch(msg)
|
self._dispatch(msg)
|
||||||
finally:
|
finally:
|
||||||
self._fp = oldfp
|
self._fp = oldfp
|
||||||
|
munge_cte = self._munge_cte
|
||||||
|
del self._munge_cte
|
||||||
|
# If we munged the cte, copy the message again and re-fix the CTE.
|
||||||
|
if munge_cte:
|
||||||
|
msg = deepcopy(msg)
|
||||||
|
msg.replace_header('content-transfer-encoding', munge_cte[0])
|
||||||
|
msg.replace_header('content-type', munge_cte[1])
|
||||||
# Write the headers. First we see if the message object wants to
|
# Write the headers. First we see if the message object wants to
|
||||||
# handle that itself. If not, we'll do it generically.
|
# handle that itself. If not, we'll do it generically.
|
||||||
meth = getattr(msg, '_write_headers', None)
|
meth = getattr(msg, '_write_headers', None)
|
||||||
|
@ -225,9 +234,14 @@ class Generator:
|
||||||
if _has_surrogates(msg._payload):
|
if _has_surrogates(msg._payload):
|
||||||
charset = msg.get_param('charset')
|
charset = msg.get_param('charset')
|
||||||
if charset is not None:
|
if charset is not None:
|
||||||
|
# XXX: This copy stuff is an ugly hack to avoid modifying the
|
||||||
|
# existing message.
|
||||||
|
msg = deepcopy(msg)
|
||||||
del msg['content-transfer-encoding']
|
del msg['content-transfer-encoding']
|
||||||
msg.set_payload(payload, charset)
|
msg.set_payload(payload, charset)
|
||||||
payload = msg.get_payload()
|
payload = msg.get_payload()
|
||||||
|
self._munge_cte = (msg['content-transfer-encoding'],
|
||||||
|
msg['content-type'])
|
||||||
if self._mangle_from_:
|
if self._mangle_from_:
|
||||||
payload = fcre.sub('>From ', payload)
|
payload = fcre.sub('>From ', payload)
|
||||||
self._write_lines(payload)
|
self._write_lines(payload)
|
||||||
|
|
|
@ -536,8 +536,8 @@ class TestRawDataManager(TestEmailBase):
|
||||||
From: victim@monty.org
|
From: victim@monty.org
|
||||||
Subject: Help
|
Subject: Help
|
||||||
Content-Type: text/plain; charset="utf-8"
|
Content-Type: text/plain; charset="utf-8"
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Transfer-Encoding: base64
|
Content-Transfer-Encoding: base64
|
||||||
|
MIME-Version: 1.0
|
||||||
|
|
||||||
aidhaSB1biBwcm9ibMOobWUgZGUgcHl0aG9uLiBpbCBlc3Qgc29ydGkgZGUgc29uIHZpdmFyaXVt
|
aidhaSB1biBwcm9ibMOobWUgZGUgcHl0aG9uLiBpbCBlc3Qgc29ydGkgZGUgc29uIHZpdmFyaXVt
|
||||||
Lgo=
|
Lgo=
|
||||||
|
|
|
@ -3529,7 +3529,7 @@ Here's the message body
|
||||||
self.assertTrue(msg.get_payload(0).get_payload().endswith('\r\n'))
|
self.assertTrue(msg.get_payload(0).get_payload().endswith('\r\n'))
|
||||||
|
|
||||||
|
|
||||||
class Test8BitBytesHandling(unittest.TestCase):
|
class Test8BitBytesHandling(TestEmailBase):
|
||||||
# In Python3 all input is string, but that doesn't work if the actual input
|
# In Python3 all input is string, but that doesn't work if the actual input
|
||||||
# uses an 8bit transfer encoding. To hack around that, in email 5.1 we
|
# uses an 8bit transfer encoding. To hack around that, in email 5.1 we
|
||||||
# decode byte streams using the surrogateescape error handler, and
|
# decode byte streams using the surrogateescape error handler, and
|
||||||
|
@ -3782,6 +3782,16 @@ class Test8BitBytesHandling(unittest.TestCase):
|
||||||
email.generator.Generator(out).flatten(msg)
|
email.generator.Generator(out).flatten(msg)
|
||||||
self.assertEqual(out.getvalue(), self.non_latin_bin_msg_as7bit_wrapped)
|
self.assertEqual(out.getvalue(), self.non_latin_bin_msg_as7bit_wrapped)
|
||||||
|
|
||||||
|
def test_str_generator_should_not_mutate_msg_when_handling_8bit(self):
|
||||||
|
msg = email.message_from_bytes(self.non_latin_bin_msg)
|
||||||
|
out = BytesIO()
|
||||||
|
BytesGenerator(out).flatten(msg)
|
||||||
|
orig_value = out.getvalue()
|
||||||
|
Generator(StringIO()).flatten(msg) # Should not mutate msg!
|
||||||
|
out = BytesIO()
|
||||||
|
BytesGenerator(out).flatten(msg)
|
||||||
|
self.assertEqual(out.getvalue(), orig_value)
|
||||||
|
|
||||||
def test_bytes_generator_with_unix_from(self):
|
def test_bytes_generator_with_unix_from(self):
|
||||||
# The unixfrom contains a current date, so we can't check it
|
# The unixfrom contains a current date, so we can't check it
|
||||||
# literally. Just make sure the first word is 'From' and the
|
# literally. Just make sure the first word is 'From' and the
|
||||||
|
|
|
@ -27,6 +27,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #19772: email.generator no longer mutates the message object when
|
||||||
|
doing a down-transform from 8bit to 7bit CTEs.
|
||||||
|
|
||||||
- Issue #20536: the statistics module now correctly handle Decimal instances
|
- Issue #20536: the statistics module now correctly handle Decimal instances
|
||||||
with positive exponents
|
with positive exponents
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue