https://github.com/python/cpython/commit/6759fd82117a50c40a0911189eda1c8dfa93ad03
commit: 6759fd82117a50c40a0911189eda1c8dfa93ad03
branch: 3.15
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-02T11:57:58Z
summary:

[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 ddb6539c4976b18895bb5c5cd37d197c60fb459d)

Co-authored-by: harjoth <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>

files:
M Lib/test/test_imaplib.py

diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
index e797a625014603..cb62aef1ff52d4 100644
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -9,6 +9,7 @@
 import calendar
 import threading
 import re
+import select
 import socket
 
 from test.support import verbose, run_with_tz, run_with_locale, cpython_only
@@ -89,6 +90,18 @@ class Handler(SimpleIMAPHandler):
     return Handler
 
 
+def _read_literal(handler, marker):
+    # Read one literal, a raw octet sequence, by its count from the marker
+    # ('{N}', or '(~{N}' in UTF8 mode).
+    size = int(re.search(r'\{(\d+)\}', marker).group(1))
+    # The client must wait for the continuation, so nothing should be readable.
+    if select.select([handler.connection], [], [], 0)[0]:
+        raise AssertionError('client sent the literal before the '
+                             'continuation request')
+    handler._send_textline('+')
+    return handler.rfile.read(size)
+
+
 class TestImaplib(unittest.TestCase):
 
     def test_Internaldate2tuple(self):
@@ -474,10 +487,8 @@ def cmd_AUTHENTICATE(self, tag, args):
                 self.server.response = yield
                 self._send_tagged(tag, 'OK', 'FAKEAUTH successful')
             def cmd_APPEND(self, tag, args):
-                self._send_textline('+')
                 self.server.response = args
-                literal = yield
-                self.server.response.append(literal)
+                self.server.response.append(_read_literal(self, args[-1]))
                 literal = yield
                 self.server.response.append(literal)
                 self._send_tagged(tag, 'OK', 'okay')
@@ -737,6 +748,19 @@ def test_login(self):
         self.assertEqual(data[0], b'LOGIN completed')
         self.assertEqual(client.state, 'AUTH')
 
+    def test_append_line_endings(self):
+        # append() normalizes bare CR and LF in the message to CRLF.
+        class AppendHandler(SimpleIMAPHandler):
+            def cmd_APPEND(self, tag, args):
+                self.server.response = _read_literal(self, args[-1])
+                yield  # read the trailer line
+                self._send_tagged(tag, 'OK', 'APPEND completed')
+        client, server = self._setup(AppendHandler)
+        client.login('user', 'pass')
+        message = b'a\rb\nc\r\nd'
+        client.append('INBOX', None, None, message)
+        self.assertEqual(server.response, b'a\r\nb\r\nc\r\nd')
+
     def test_login_capabilities(self):
         # A server may advertise new capabilities after login (as an
         # untagged CAPABILITY response); imaplib must refresh its cached
@@ -1673,10 +1697,8 @@ def test_enable_UTF8_True_append(self):
 
         class UTF8AppendServer(self.UTF8Server):
             def cmd_APPEND(self, tag, args):
-                self._send_textline('+')
                 self.server.response = args
-                literal = yield
-                self.server.response.append(literal)
+                self.server.response.append(_read_literal(self, args[-1]))
                 literal = yield
                 self.server.response.append(literal)
                 self._send_tagged(tag, 'OK', 'okay')

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to