X Tutup
Skip to content

Commit 94a7927

Browse files
committed
python#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.
1 parent de02b08 commit 94a7927

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

Lib/email/contentmanager.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,13 @@ def _finalize_set(msg, disposition, filename, cid, params):
126126
msg.set_param(key, value)
127127

128128

129-
# XXX: This is a cleaned-up version of base64mime.body_encode. It would
130-
# be nice to drop both this and quoprimime.body_encode in favor of
131-
# enhanced binascii routines that accepted a max_line_length parameter.
129+
# XXX: This is a cleaned-up version of base64mime.body_encode (including a bug
130+
# fix in the calculation of unencoded_bytes_per_line). It would be nice to
131+
# drop both this and quoprimime.body_encode in favor of enhanced binascii
132+
# routines that accepted a max_line_length parameter.
132133
def _encode_base64(data, max_line_length):
133134
encoded_lines = []
134-
unencoded_bytes_per_line = max_line_length * 3 // 4
135+
unencoded_bytes_per_line = max_line_length // 4 * 3
135136
for i in range(0, len(data), unencoded_bytes_per_line):
136137
thisline = data[i:i+unencoded_bytes_per_line]
137138
encoded_lines.append(binascii.b2a_base64(thisline).decode('ascii'))

Lib/test/test_email/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ def example_as_myfunc_input(self, name, count):
121121
Note: if and only if the generated test name is a valid identifier can it
122122
be used to select the test individually from the unittest command line.
123123
124+
The values in the params dict can be a single value, a tuple, or a
125+
dict. If a single value of a tuple, it is passed to the test function
126+
as positional arguments. If a dict, it is a passed via **kw.
127+
124128
"""
125129
paramdicts = {}
126130
testers = collections.defaultdict(list)
@@ -149,8 +153,12 @@ def example_as_myfunc_input(self, name, count):
149153
if name.startswith(paramsname):
150154
testnameroot = 'test_' + name[len(paramsname):]
151155
for paramname, params in paramsdict.items():
152-
test = (lambda self, name=name, params=params:
153-
getattr(self, name)(*params))
156+
if hasattr(params, 'keys'):
157+
test = (lambda self, name=name, params=params:
158+
getattr(self, name)(**params))
159+
else:
160+
test = (lambda self, name=name, params=params:
161+
getattr(self, name)(*params))
154162
testname = testnameroot + '_' + paramname
155163
test.__name__ = testname
156164
testfuncs[testname] = test

Lib/test/test_email/test_inversion.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io
88
import unittest
99
from email import policy, message_from_bytes
10+
from email.message import EmailMessage
1011
from email.generator import BytesGenerator
1112
from test.test_email import TestEmailBase, parameterize
1213

@@ -23,7 +24,10 @@ def dedent(bstr):
2324

2425

2526
@parameterize
26-
class TestInversion(TestEmailBase, unittest.TestCase):
27+
class TestInversion(TestEmailBase):
28+
29+
policy = policy.default
30+
message = EmailMessage
2731

2832
def msg_as_input(self, msg):
2933
m = message_from_bytes(msg, policy=policy.SMTP)
@@ -44,6 +48,23 @@ def msg_as_input(self, msg):
4448

4549
}
4650

51+
payload_params = {
52+
'plain_text': dict(payload='This is a test\n'*20),
53+
'base64_text': dict(payload=(('xy a'*40+'\n')*5), cte='base64'),
54+
'qp_text': dict(payload=(('xy a'*40+'\n')*5), cte='quoted-printable'),
55+
}
56+
57+
def payload_as_body(self, payload, **kw):
58+
msg = self._make_message()
59+
msg['From'] = 'foo'
60+
msg['To'] = 'bar'
61+
msg['Subject'] = 'payload round trip test'
62+
msg.set_content(payload, **kw)
63+
b = bytes(msg)
64+
msg2 = message_from_bytes(b, policy=self.policy)
65+
self.assertEqual(bytes(msg2), b)
66+
self.assertEqual(msg2.get_content(), payload)
67+
4768

4869
if __name__ == '__main__':
4970
unittest.main()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ Core and Builtins
6262
Library
6363
-------
6464

65+
- Issue #28047: Fixed calculation of line length used for the base64 CTE
66+
in the new email policies.
67+
6568
- Issue #27445: Don't pass str(_charset) to MIMEText.set_payload().
6669
Patch by Claude Paroz.
6770

0 commit comments

Comments
 (0)
X Tutup