mirror of
https://github.com/python/cpython.git
synced 2025-11-27 13:45:25 +00:00
#28047: Fix calculation of base64 line length.
This is buggy in the old email code as well, but it doesn't affect anything there because only the default line length is ever used there.
This commit is contained in:
parent
de02b084e6
commit
94a7927cc6
4 changed files with 40 additions and 7 deletions
|
|
@ -126,12 +126,13 @@ def _finalize_set(msg, disposition, filename, cid, params):
|
||||||
msg.set_param(key, value)
|
msg.set_param(key, value)
|
||||||
|
|
||||||
|
|
||||||
# XXX: This is a cleaned-up version of base64mime.body_encode. It would
|
# XXX: This is a cleaned-up version of base64mime.body_encode (including a bug
|
||||||
# be nice to drop both this and quoprimime.body_encode in favor of
|
# fix in the calculation of unencoded_bytes_per_line). It would be nice to
|
||||||
# enhanced binascii routines that accepted a max_line_length parameter.
|
# drop both this and quoprimime.body_encode in favor of enhanced binascii
|
||||||
|
# routines that accepted a max_line_length parameter.
|
||||||
def _encode_base64(data, max_line_length):
|
def _encode_base64(data, max_line_length):
|
||||||
encoded_lines = []
|
encoded_lines = []
|
||||||
unencoded_bytes_per_line = max_line_length * 3 // 4
|
unencoded_bytes_per_line = max_line_length // 4 * 3
|
||||||
for i in range(0, len(data), unencoded_bytes_per_line):
|
for i in range(0, len(data), unencoded_bytes_per_line):
|
||||||
thisline = data[i:i+unencoded_bytes_per_line]
|
thisline = data[i:i+unencoded_bytes_per_line]
|
||||||
encoded_lines.append(binascii.b2a_base64(thisline).decode('ascii'))
|
encoded_lines.append(binascii.b2a_base64(thisline).decode('ascii'))
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,10 @@ def parameterize(cls):
|
||||||
Note: if and only if the generated test name is a valid identifier can it
|
Note: if and only if the generated test name is a valid identifier can it
|
||||||
be used to select the test individually from the unittest command line.
|
be used to select the test individually from the unittest command line.
|
||||||
|
|
||||||
|
The values in the params dict can be a single value, a tuple, or a
|
||||||
|
dict. If a single value of a tuple, it is passed to the test function
|
||||||
|
as positional arguments. If a dict, it is a passed via **kw.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
paramdicts = {}
|
paramdicts = {}
|
||||||
testers = collections.defaultdict(list)
|
testers = collections.defaultdict(list)
|
||||||
|
|
@ -149,6 +153,10 @@ def parameterize(cls):
|
||||||
if name.startswith(paramsname):
|
if name.startswith(paramsname):
|
||||||
testnameroot = 'test_' + name[len(paramsname):]
|
testnameroot = 'test_' + name[len(paramsname):]
|
||||||
for paramname, params in paramsdict.items():
|
for paramname, params in paramsdict.items():
|
||||||
|
if hasattr(params, 'keys'):
|
||||||
|
test = (lambda self, name=name, params=params:
|
||||||
|
getattr(self, name)(**params))
|
||||||
|
else:
|
||||||
test = (lambda self, name=name, params=params:
|
test = (lambda self, name=name, params=params:
|
||||||
getattr(self, name)(*params))
|
getattr(self, name)(*params))
|
||||||
testname = testnameroot + '_' + paramname
|
testname = testnameroot + '_' + paramname
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ producing RFC valid messages.
|
||||||
import io
|
import io
|
||||||
import unittest
|
import unittest
|
||||||
from email import policy, message_from_bytes
|
from email import policy, message_from_bytes
|
||||||
|
from email.message import EmailMessage
|
||||||
from email.generator import BytesGenerator
|
from email.generator import BytesGenerator
|
||||||
from test.test_email import TestEmailBase, parameterize
|
from test.test_email import TestEmailBase, parameterize
|
||||||
|
|
||||||
|
|
@ -23,7 +24,10 @@ def dedent(bstr):
|
||||||
|
|
||||||
|
|
||||||
@parameterize
|
@parameterize
|
||||||
class TestInversion(TestEmailBase, unittest.TestCase):
|
class TestInversion(TestEmailBase):
|
||||||
|
|
||||||
|
policy = policy.default
|
||||||
|
message = EmailMessage
|
||||||
|
|
||||||
def msg_as_input(self, msg):
|
def msg_as_input(self, msg):
|
||||||
m = message_from_bytes(msg, policy=policy.SMTP)
|
m = message_from_bytes(msg, policy=policy.SMTP)
|
||||||
|
|
@ -44,6 +48,23 @@ class TestInversion(TestEmailBase, unittest.TestCase):
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
payload_params = {
|
||||||
|
'plain_text': dict(payload='This is a test\n'*20),
|
||||||
|
'base64_text': dict(payload=(('xy a'*40+'\n')*5), cte='base64'),
|
||||||
|
'qp_text': dict(payload=(('xy a'*40+'\n')*5), cte='quoted-printable'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def payload_as_body(self, payload, **kw):
|
||||||
|
msg = self._make_message()
|
||||||
|
msg['From'] = 'foo'
|
||||||
|
msg['To'] = 'bar'
|
||||||
|
msg['Subject'] = 'payload round trip test'
|
||||||
|
msg.set_content(payload, **kw)
|
||||||
|
b = bytes(msg)
|
||||||
|
msg2 = message_from_bytes(b, policy=self.policy)
|
||||||
|
self.assertEqual(bytes(msg2), b)
|
||||||
|
self.assertEqual(msg2.get_content(), payload)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #28047: Fixed calculation of line length used for the base64 CTE
|
||||||
|
in the new email policies.
|
||||||
|
|
||||||
- Issue #27445: Don't pass str(_charset) to MIMEText.set_payload().
|
- Issue #27445: Don't pass str(_charset) to MIMEText.set_payload().
|
||||||
Patch by Claude Paroz.
|
Patch by Claude Paroz.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue