Skip to content

Commit 2dfdcb6

Browse files
Fix Generator._make_boundary behavior with CRLF line endings.
The Generator._make_boundary regex does not match on boundary phrases correctly when using CRLF line endings due to re.MULTILINE not considering \r\n as a line ending.
1 parent 8a73478 commit 2dfdcb6

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

Lib/email/generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ def _make_boundary(cls, text=None):
392392
b = boundary
393393
counter = 0
394394
while True:
395-
cre = cls._compile_re('^--' + re.escape(b) + '(--)?$', re.MULTILINE)
395+
cre = cls._compile_re('^--' + re.escape(b) + '(--)?\r?$', re.MULTILINE)
396396
if not cre.search(text):
397397
break
398398
b = boundary + '.' + str(counter)

Lib/test/test_email/test_generator.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import io
22
import textwrap
33
import unittest
4+
import random
5+
import sys
46
from email import message_from_string, message_from_bytes
57
from email.message import EmailMessage
8+
from email.mime.multipart import MIMEMultipart
9+
from email.mime.text import MIMEText
610
from email.generator import Generator, BytesGenerator
11+
import email.generator
712
from email.headerregistry import Address
813
from email import policy
914
import email.errors
1015
from test.test_email import TestEmailBase, parameterize
16+
import test.support
17+
1118

1219

1320
@parameterize
@@ -288,6 +295,34 @@ def test_keep_long_encoded_newlines(self):
288295
g.flatten(msg)
289296
self.assertEqual(s.getvalue(), self.typ(expected))
290297

298+
def _test_boundary_detection(self, linesep):
299+
# Generate a boundary token in the same way as _make_boundary
300+
token = random.randrange(sys.maxsize)
301+
302+
def _patch_random_randrange(*args, **kwargs):
303+
return token
304+
305+
with test.support.swap_attr(
306+
random, "randrange", _patch_random_randrange
307+
):
308+
boundary = self.genclass._make_boundary(text=None)
309+
boundary_in_part = (
310+
"this goes before the boundary\n--"
311+
+ boundary
312+
+ "\nthis goes after\n"
313+
)
314+
msg = MIMEMultipart()
315+
msg.attach(MIMEText(boundary_in_part))
316+
self.genclass(self.ioclass()).flatten(msg, linesep=linesep)
317+
# .0 is appended if the boundary was found.
318+
self.assertEqual(msg.get_boundary(), boundary + ".0")
319+
320+
def test_lf_boundary_detection(self):
321+
self._test_boundary_detection("\n")
322+
323+
def test_crlf_boundary_detection(self):
324+
self._test_boundary_detection("\r\n")
325+
291326

292327
class TestGenerator(TestGeneratorBase, TestEmailBase):
293328

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`email.generator.Generator._make_boundary` now correctly finds the
2+
boundary when using CRLF linesep.

0 commit comments

Comments
 (0)