|
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, requires_resource |
@@ -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): |
@@ -425,10 +438,8 @@ def cmd_AUTHENTICATE(self, tag, args): |
425 | 438 | self.server.response = yield |
426 | 439 | self._send_tagged(tag, 'OK', 'FAKEAUTH successful') |
427 | 440 | def cmd_APPEND(self, tag, args): |
428 | | - self._send_textline('+') |
429 | 441 | self.server.response = args |
430 | | - literal = yield |
431 | | - self.server.response.append(literal) |
| 442 | + self.server.response.append(_read_literal(self, args[-1])) |
432 | 443 | literal = yield |
433 | 444 | self.server.response.append(literal) |
434 | 445 | self._send_tagged(tag, 'OK', 'okay') |
@@ -626,6 +637,19 @@ def test_login(self): |
626 | 637 | self.assertEqual(data[0], b'LOGIN completed') |
627 | 638 | self.assertEqual(client.state, 'AUTH') |
628 | 639 |
|
| 640 | + def test_append_line_endings(self): |
| 641 | + # append() normalizes bare CR and LF in the message to CRLF. |
| 642 | + class AppendHandler(SimpleIMAPHandler): |
| 643 | + def cmd_APPEND(self, tag, args): |
| 644 | + self.server.response = _read_literal(self, args[-1]) |
| 645 | + yield # read the trailer line |
| 646 | + self._send_tagged(tag, 'OK', 'APPEND completed') |
| 647 | + client, server = self._setup(AppendHandler) |
| 648 | + client.login('user', 'pass') |
| 649 | + message = b'a\rb\nc\r\nd' |
| 650 | + client.append('INBOX', None, None, message) |
| 651 | + self.assertEqual(server.response, b'a\r\nb\r\nc\r\nd') |
| 652 | + |
629 | 653 | def test_logout(self): |
630 | 654 | client, _ = self._setup(SimpleIMAPHandler) |
631 | 655 | typ, data = client.login('user', 'pass') |
@@ -1461,10 +1485,8 @@ def test_enable_UTF8_True_append(self): |
1461 | 1485 |
|
1462 | 1486 | class UTF8AppendServer(self.UTF8Server): |
1463 | 1487 | def cmd_APPEND(self, tag, args): |
1464 | | - self._send_textline('+') |
1465 | 1488 | self.server.response = args |
1466 | | - literal = yield |
1467 | | - self.server.response.append(literal) |
| 1489 | + self.server.response.append(_read_literal(self, args[-1])) |
1468 | 1490 | literal = yield |
1469 | 1491 | self.server.response.append(literal) |
1470 | 1492 | self._send_tagged(tag, 'OK', 'okay') |
|
0 commit comments