diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-04-15 16:23:20 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-15 16:23:20 (GMT) |
commit | 74125a60b7a477451ff2b8385bfbce3fdaee8dbc (patch) | |
tree | 2a6670b9046ee35a4dc19d907b862c158c33dbfe /Lib | |
parent | 0810fa79885276114d1a94e2ce61da367ebb1ffc (diff) | |
download | cpython-74125a60b7a477451ff2b8385bfbce3fdaee8dbc.zip cpython-74125a60b7a477451ff2b8385bfbce3fdaee8dbc.tar.gz cpython-74125a60b7a477451ff2b8385bfbce3fdaee8dbc.tar.bz2 |
bpo-36348: IMAP4.logout() doesn't ignore exc (GH-12411)
The imap.IMAP4.logout() method no longer ignores silently arbitrary
exceptions.
Changes:
* The IMAP4.logout() method now expects a "BYE" untagged response,
rather than relying on _check_bye() which raises a self.abort()
exception.
* IMAP4.__exit__() now does nothing if the client already logged out.
* Add more debug info if test_logout() tests fail.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/imaplib.py | 25 | ||||
-rw-r--r-- | Lib/test/test_imaplib.py | 8 |
2 files changed, 20 insertions, 13 deletions
diff --git a/Lib/imaplib.py b/Lib/imaplib.py index dd237f7..341ee25 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -272,6 +272,9 @@ class IMAP4: return self def __exit__(self, *args): + if self.state == "LOGOUT": + return + try: self.logout() except OSError: @@ -625,11 +628,8 @@ class IMAP4: Returns server 'BYE' response. """ self.state = 'LOGOUT' - try: typ, dat = self._simple_command('LOGOUT') - except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]] + typ, dat = self._simple_command('LOGOUT') self.shutdown() - if 'BYE' in self.untagged_responses: - return 'BYE', self.untagged_responses['BYE'] return typ, dat @@ -1012,16 +1012,17 @@ class IMAP4: def _command_complete(self, name, tag): + logout = (name == 'LOGOUT') # BYE is expected after LOGOUT - if name != 'LOGOUT': + if not logout: self._check_bye() try: - typ, data = self._get_tagged_response(tag) + typ, data = self._get_tagged_response(tag, expect_bye=logout) except self.abort as val: raise self.abort('command: %s => %s' % (name, val)) except self.error as val: raise self.error('command: %s => %s' % (name, val)) - if name != 'LOGOUT': + if not logout: self._check_bye() if typ == 'BAD': raise self.error('%s command error: %s %s' % (name, typ, data)) @@ -1117,7 +1118,7 @@ class IMAP4: return resp - def _get_tagged_response(self, tag): + def _get_tagged_response(self, tag, expect_bye=False): while 1: result = self.tagged_commands[tag] @@ -1125,9 +1126,15 @@ class IMAP4: del self.tagged_commands[tag] return result + if expect_bye: + typ = 'BYE' + bye = self.untagged_responses.pop(typ, None) + if bye is not None: + # Server replies to the "LOGOUT" command with "BYE" + return (typ, bye) + # If we've seen a BYE at this point, the socket will be # closed, so report the BYE now. - self._check_bye() # Some have reported "unexpected response" exceptions. diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index aec36af..9305e47 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -470,8 +470,8 @@ class NewIMAPTestsMixin(): self.assertEqual(typ, 'OK') self.assertEqual(data[0], b'LOGIN completed') typ, data = client.logout() - self.assertEqual(typ, 'BYE') - self.assertEqual(data[0], b'IMAP4ref1 Server logging out') + self.assertEqual(typ, 'BYE', (typ, data)) + self.assertEqual(data[0], b'IMAP4ref1 Server logging out', (typ, data)) self.assertEqual(client.state, 'LOGOUT') def test_lsub(self): @@ -937,7 +937,7 @@ class RemoteIMAPTest(unittest.TestCase): with transient_internet(self.host): rs = self.server.logout() self.server = None - self.assertEqual(rs[0], 'BYE') + self.assertEqual(rs[0], 'BYE', rs) @unittest.skipUnless(ssl, "SSL not available") @@ -995,7 +995,7 @@ class RemoteIMAP_SSLTest(RemoteIMAPTest): with transient_internet(self.host): _server = self.imap_class(self.host, self.port) rs = _server.logout() - self.assertEqual(rs[0], 'BYE') + self.assertEqual(rs[0], 'BYE', rs) def test_ssl_context_certfile_exclusive(self): with transient_internet(self.host): |