Skip to content

Commit c98e263

Browse files
miss-islingtonserhiy-storchakaharjothkharaclaude
authored
[3.14] gh-49680: Test imaplib.IMAP4.append line-ending normalization (GH-152877) (GH-152878)
(cherry picked from commit ddb6539) (cherry picked from commit 6759fd8) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: harjoth <harjoth.khara@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e112e47 commit c98e263

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
@@ -90,6 +91,18 @@ class Handler(SimpleIMAPHandler):
9091
return Handler
9192

9293

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

95108
def test_Internaldate2tuple(self):
@@ -475,10 +488,8 @@ def cmd_AUTHENTICATE(self, tag, args):
475488
self.server.response = yield
476489
self._send_tagged(tag, 'OK', 'FAKEAUTH successful')
477490
def cmd_APPEND(self, tag, args):
478-
self._send_textline('+')
479491
self.server.response = args
480-
literal = yield
481-
self.server.response.append(literal)
492+
self.server.response.append(_read_literal(self, args[-1]))
482493
literal = yield
483494
self.server.response.append(literal)
484495
self._send_tagged(tag, 'OK', 'okay')
@@ -743,6 +754,19 @@ def test_login(self):
743754
self.assertEqual(data[0], b'LOGIN completed')
744755
self.assertEqual(client.state, 'AUTH')
745756

757+
def test_append_line_endings(self):
758+
# append() normalizes bare CR and LF in the message to CRLF.
759+
class AppendHandler(SimpleIMAPHandler):
760+
def cmd_APPEND(self, tag, args):
761+
self.server.response = _read_literal(self, args[-1])
762+
yield # read the trailer line
763+
self._send_tagged(tag, 'OK', 'APPEND completed')
764+
client, server = self._setup(AppendHandler)
765+
client.login('user', 'pass')
766+
message = b'a\rb\nc\r\nd'
767+
client.append('INBOX', None, None, message)
768+
self.assertEqual(server.response, b'a\r\nb\r\nc\r\nd')
769+
746770
def test_login_capabilities(self):
747771
# A server may advertise new capabilities after login (as an
748772
# untagged CAPABILITY response); imaplib must refresh its cached
@@ -1651,10 +1675,8 @@ def test_enable_UTF8_True_append(self):
16511675

16521676
class UTF8AppendServer(self.UTF8Server):
16531677
def cmd_APPEND(self, tag, args):
1654-
self._send_textline('+')
16551678
self.server.response = args
1656-
literal = yield
1657-
self.server.response.append(literal)
1679+
self.server.response.append(_read_literal(self, args[-1]))
16581680
literal = yield
16591681
self.server.response.append(literal)
16601682
self._send_tagged(tag, 'OK', 'okay')

0 commit comments

Comments
 (0)