mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
0810fa7988
commit
74125a60b7
|
@ -327,6 +327,9 @@ An :class:`IMAP4` instance has the following methods:
|
||||||
|
|
||||||
Shutdown connection to server. Returns server ``BYE`` response.
|
Shutdown connection to server. Returns server ``BYE`` response.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
The method no longer ignores silently arbitrary exceptions.
|
||||||
|
|
||||||
|
|
||||||
.. method:: IMAP4.lsub(directory='""', pattern='*')
|
.. method:: IMAP4.lsub(directory='""', pattern='*')
|
||||||
|
|
||||||
|
|
|
@ -709,6 +709,9 @@ Changes in Python behavior
|
||||||
Changes in the Python API
|
Changes in the Python API
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
* The :meth:`imap.IMAP4.logout` method no longer ignores silently arbitrary
|
||||||
|
exceptions.
|
||||||
|
|
||||||
* The function :func:`platform.popen` has been removed, it was deprecated since
|
* The function :func:`platform.popen` has been removed, it was deprecated since
|
||||||
Python 3.3: use :func:`os.popen` instead.
|
Python 3.3: use :func:`os.popen` instead.
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,9 @@ class IMAP4:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
if self.state == "LOGOUT":
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.logout()
|
self.logout()
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -625,11 +628,8 @@ class IMAP4:
|
||||||
Returns server 'BYE' response.
|
Returns server 'BYE' response.
|
||||||
"""
|
"""
|
||||||
self.state = 'LOGOUT'
|
self.state = 'LOGOUT'
|
||||||
try: typ, dat = self._simple_command('LOGOUT')
|
typ, dat = self._simple_command('LOGOUT')
|
||||||
except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]]
|
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
if 'BYE' in self.untagged_responses:
|
|
||||||
return 'BYE', self.untagged_responses['BYE']
|
|
||||||
return typ, dat
|
return typ, dat
|
||||||
|
|
||||||
|
|
||||||
|
@ -1012,16 +1012,17 @@ class IMAP4:
|
||||||
|
|
||||||
|
|
||||||
def _command_complete(self, name, tag):
|
def _command_complete(self, name, tag):
|
||||||
|
logout = (name == 'LOGOUT')
|
||||||
# BYE is expected after LOGOUT
|
# BYE is expected after LOGOUT
|
||||||
if name != 'LOGOUT':
|
if not logout:
|
||||||
self._check_bye()
|
self._check_bye()
|
||||||
try:
|
try:
|
||||||
typ, data = self._get_tagged_response(tag)
|
typ, data = self._get_tagged_response(tag, expect_bye=logout)
|
||||||
except self.abort as val:
|
except self.abort as val:
|
||||||
raise self.abort('command: %s => %s' % (name, val))
|
raise self.abort('command: %s => %s' % (name, val))
|
||||||
except self.error as val:
|
except self.error as val:
|
||||||
raise self.error('command: %s => %s' % (name, val))
|
raise self.error('command: %s => %s' % (name, val))
|
||||||
if name != 'LOGOUT':
|
if not logout:
|
||||||
self._check_bye()
|
self._check_bye()
|
||||||
if typ == 'BAD':
|
if typ == 'BAD':
|
||||||
raise self.error('%s command error: %s %s' % (name, typ, data))
|
raise self.error('%s command error: %s %s' % (name, typ, data))
|
||||||
|
@ -1117,7 +1118,7 @@ class IMAP4:
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def _get_tagged_response(self, tag):
|
def _get_tagged_response(self, tag, expect_bye=False):
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
result = self.tagged_commands[tag]
|
result = self.tagged_commands[tag]
|
||||||
|
@ -1125,9 +1126,15 @@ class IMAP4:
|
||||||
del self.tagged_commands[tag]
|
del self.tagged_commands[tag]
|
||||||
return result
|
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
|
# If we've seen a BYE at this point, the socket will be
|
||||||
# closed, so report the BYE now.
|
# closed, so report the BYE now.
|
||||||
|
|
||||||
self._check_bye()
|
self._check_bye()
|
||||||
|
|
||||||
# Some have reported "unexpected response" exceptions.
|
# Some have reported "unexpected response" exceptions.
|
||||||
|
|
|
@ -470,8 +470,8 @@ class NewIMAPTestsMixin():
|
||||||
self.assertEqual(typ, 'OK')
|
self.assertEqual(typ, 'OK')
|
||||||
self.assertEqual(data[0], b'LOGIN completed')
|
self.assertEqual(data[0], b'LOGIN completed')
|
||||||
typ, data = client.logout()
|
typ, data = client.logout()
|
||||||
self.assertEqual(typ, 'BYE')
|
self.assertEqual(typ, 'BYE', (typ, data))
|
||||||
self.assertEqual(data[0], b'IMAP4ref1 Server logging out')
|
self.assertEqual(data[0], b'IMAP4ref1 Server logging out', (typ, data))
|
||||||
self.assertEqual(client.state, 'LOGOUT')
|
self.assertEqual(client.state, 'LOGOUT')
|
||||||
|
|
||||||
def test_lsub(self):
|
def test_lsub(self):
|
||||||
|
@ -937,7 +937,7 @@ class RemoteIMAPTest(unittest.TestCase):
|
||||||
with transient_internet(self.host):
|
with transient_internet(self.host):
|
||||||
rs = self.server.logout()
|
rs = self.server.logout()
|
||||||
self.server = None
|
self.server = None
|
||||||
self.assertEqual(rs[0], 'BYE')
|
self.assertEqual(rs[0], 'BYE', rs)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(ssl, "SSL not available")
|
@unittest.skipUnless(ssl, "SSL not available")
|
||||||
|
@ -995,7 +995,7 @@ class RemoteIMAP_SSLTest(RemoteIMAPTest):
|
||||||
with transient_internet(self.host):
|
with transient_internet(self.host):
|
||||||
_server = self.imap_class(self.host, self.port)
|
_server = self.imap_class(self.host, self.port)
|
||||||
rs = _server.logout()
|
rs = _server.logout()
|
||||||
self.assertEqual(rs[0], 'BYE')
|
self.assertEqual(rs[0], 'BYE', rs)
|
||||||
|
|
||||||
def test_ssl_context_certfile_exclusive(self):
|
def test_ssl_context_certfile_exclusive(self):
|
||||||
with transient_internet(self.host):
|
with transient_internet(self.host):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
The :meth:`imap.IMAP4.logout` method no longer ignores silently arbitrary
|
||||||
|
exceptions.
|
Loading…
Reference in New Issue