|
9 | 9 | import calendar |
10 | 10 | import threading |
11 | 11 | import re |
| 12 | +import select |
12 | 13 | import socket |
13 | 14 |
|
14 | 15 | from test.support import verbose, run_with_tz, run_with_locale, cpython_only |
@@ -90,6 +91,18 @@ class Handler(SimpleIMAPHandler): |
90 | 91 | return Handler |
91 | 92 |
|
92 | 93 |
|
| 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 | + |
93 | 106 | class TestImaplib(unittest.TestCase): |
94 | 107 |
|
95 | 108 | def test_Internaldate2tuple(self): |
@@ -475,10 +488,8 @@ def cmd_AUTHENTICATE(self, tag, args): |
475 | 488 | self.server.response = yield |
476 | 489 | self._send_tagged(tag, 'OK', 'FAKEAUTH successful') |
477 | 490 | def cmd_APPEND(self, tag, args): |
478 | | - self._send_textline('+') |
479 | 491 | self.server.response = args |
480 | | - literal = yield |
481 | | - self.server.response.append(literal) |
| 492 | + self.server.response.append(_read_literal(self, args[-1])) |
482 | 493 | literal = yield |
483 | 494 | self.server.response.append(literal) |
484 | 495 | self._send_tagged(tag, 'OK', 'okay') |
@@ -743,6 +754,19 @@ def test_login(self): |
743 | 754 | self.assertEqual(data[0], b'LOGIN completed') |
744 | 755 | self.assertEqual(client.state, 'AUTH') |
745 | 756 |
|
| 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 | + |
746 | 770 | def test_login_capabilities(self): |
747 | 771 | # A server may advertise new capabilities after login (as an |
748 | 772 | # untagged CAPABILITY response); imaplib must refresh its cached |
@@ -1651,10 +1675,8 @@ def test_enable_UTF8_True_append(self): |
1651 | 1675 |
|
1652 | 1676 | class UTF8AppendServer(self.UTF8Server): |
1653 | 1677 | def cmd_APPEND(self, tag, args): |
1654 | | - self._send_textline('+') |
1655 | 1678 | self.server.response = args |
1656 | | - literal = yield |
1657 | | - self.server.response.append(literal) |
| 1679 | + self.server.response.append(_read_literal(self, args[-1])) |
1658 | 1680 | literal = yield |
1659 | 1681 | self.server.response.append(literal) |
1660 | 1682 | self._send_tagged(tag, 'OK', 'okay') |
|
0 commit comments