|
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 |
@@ -89,6 +90,18 @@ class Handler(SimpleIMAPHandler): |
89 | 90 | return Handler |
90 | 91 |
|
91 | 92 |
|
| 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 | + |
92 | 105 | class TestImaplib(unittest.TestCase): |
93 | 106 |
|
94 | 107 | def test_Internaldate2tuple(self): |
@@ -474,10 +487,8 @@ def cmd_AUTHENTICATE(self, tag, args): |
474 | 487 | self.server.response = yield |
475 | 488 | self._send_tagged(tag, 'OK', 'FAKEAUTH successful') |
476 | 489 | def cmd_APPEND(self, tag, args): |
477 | | - self._send_textline('+') |
478 | 490 | self.server.response = args |
479 | | - literal = yield |
480 | | - self.server.response.append(literal) |
| 491 | + self.server.response.append(_read_literal(self, args[-1])) |
481 | 492 | literal = yield |
482 | 493 | self.server.response.append(literal) |
483 | 494 | self._send_tagged(tag, 'OK', 'okay') |
@@ -737,6 +748,19 @@ def test_login(self): |
737 | 748 | self.assertEqual(data[0], b'LOGIN completed') |
738 | 749 | self.assertEqual(client.state, 'AUTH') |
739 | 750 |
|
| 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 | + |
740 | 764 | def test_login_capabilities(self): |
741 | 765 | # A server may advertise new capabilities after login (as an |
742 | 766 | # untagged CAPABILITY response); imaplib must refresh its cached |
@@ -1673,10 +1697,8 @@ def test_enable_UTF8_True_append(self): |
1673 | 1697 |
|
1674 | 1698 | class UTF8AppendServer(self.UTF8Server): |
1675 | 1699 | def cmd_APPEND(self, tag, args): |
1676 | | - self._send_textline('+') |
1677 | 1700 | self.server.response = args |
1678 | | - literal = yield |
1679 | | - self.server.response.append(literal) |
| 1701 | + self.server.response.append(_read_literal(self, args[-1])) |
1680 | 1702 | literal = yield |
1681 | 1703 | self.server.response.append(literal) |
1682 | 1704 | self._send_tagged(tag, 'OK', 'okay') |
|
0 commit comments