Skip to content

Commit 6759fd8

Browse files
serhiy-storchakaharjothkharaclaude
authored
[3.15] gh-49680: Test imaplib.IMAP4.append line-ending normalization (GH-152877)
gh-49680: Test imaplib.IMAP4.append line-ending normalization (cherry picked from commit ddb6539) Co-authored-by: harjoth <harjoth.khara@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ad6b359 commit 6759fd8

1 file changed

Lines changed: 28 additions & 6 deletions

File tree

Lib/test/test_imaplib.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import calendar
1010
import threading
1111
import re
12+
import select
1213
import socket
1314

1415
from test.support import verbose, run_with_tz, run_with_locale, cpython_only
@@ -89,6 +90,18 @@ class Handler(SimpleIMAPHandler):
8990
return Handler
9091

9192

93+
def _read_literal(handler, marker):
94+
# Read one literal, a raw octet sequence, by its count from the marker
95+
# ('{N}', or '(~{N}' in UTF8 mode).
96+
size = int(re.search(r'\{(\d+)\}', marker).group(1))
97+
# The client must wait for the continuation, so nothing should be readable.
98+
if select.select([handler.connection], [], [], 0)[0]:
99+
raise AssertionError('client sent the literal before the '
100+
'continuation request')
101+
handler._send_textline('+')
102+
return handler.rfile.read(size)
103+
104+
92105
class TestImaplib(unittest.TestCase):
93106

94107
def test_Internaldate2tuple(self):
@@ -474,10 +487,8 @@ def cmd_AUTHENTICATE(self, tag, args):
474487
self.server.response = yield
475488
self._send_tagged(tag, 'OK', 'FAKEAUTH successful')
476489
def cmd_APPEND(self, tag, args):
477-
self._send_textline('+')
478490
self.server.response = args
479-
literal = yield
480-
self.server.response.append(literal)
491+
self.server.response.append(_read_literal(self, args[-1]))
481492
literal = yield
482493
self.server.response.append(literal)
483494
self._send_tagged(tag, 'OK', 'okay')
@@ -737,6 +748,19 @@ def test_login(self):
737748
self.assertEqual(data[0], b'LOGIN completed')
738749
self.assertEqual(client.state, 'AUTH')
739750

751+
def test_append_line_endings(self):
752+
# append() normalizes bare CR and LF in the message to CRLF.
753+
class AppendHandler(SimpleIMAPHandler):
754+
def cmd_APPEND(self, tag, args):
755+
self.server.response = _read_literal(self, args[-1])
756+
yield # read the trailer line
757+
self._send_tagged(tag, 'OK', 'APPEND completed')
758+
client, server = self._setup(AppendHandler)
759+
client.login('user', 'pass')
760+
message = b'a\rb\nc\r\nd'
761+
client.append('INBOX', None, None, message)
762+
self.assertEqual(server.response, b'a\r\nb\r\nc\r\nd')
763+
740764
def test_login_capabilities(self):
741765
# A server may advertise new capabilities after login (as an
742766
# untagged CAPABILITY response); imaplib must refresh its cached
@@ -1673,10 +1697,8 @@ def test_enable_UTF8_True_append(self):
16731697

16741698
class UTF8AppendServer(self.UTF8Server):
16751699
def cmd_APPEND(self, tag, args):
1676-
self._send_textline('+')
16771700
self.server.response = args
1678-
literal = yield
1679-
self.server.response.append(literal)
1701+
self.server.response.append(_read_literal(self, args[-1]))
16801702
literal = yield
16811703
self.server.response.append(literal)
16821704
self._send_tagged(tag, 'OK', 'okay')

0 commit comments

Comments
 (0)