Issue #14837: SSL errors now have library and reason attributes describing precisely what happened and in which OpenSSL submodule.

The str() of a SSLError is also enhanced accordingly.

NOTE: this commit creates a reference leak.  The leak seems tied to the
use of PyType_FromSpec() to create the SSLError type.  The leak is on the
type object when it is instantiated:

>>> e = ssl.SSLError()
>>> sys.getrefcount(ssl.SSLError)
35
>>> e = ssl.SSLError()
>>> sys.getrefcount(ssl.SSLError)
36
>>> e = ssl.SSLError()
>>> sys.getrefcount(ssl.SSLError)
37
This commit is contained in:
Antoine Pitrou 2012-06-22 21:11:52 +02:00
parent 31227ca514
commit 3b36fb1f53
4 changed files with 262 additions and 65 deletions

View file

@ -552,7 +552,7 @@ class ContextTests(unittest.TestCase):
with self.assertRaises(FileNotFoundError) as cm:
ctx.load_dh_params(WRONGCERT)
self.assertEqual(cm.exception.errno, errno.ENOENT)
with self.assertRaisesRegex(ssl.SSLError, "PEM routines"):
with self.assertRaises(ssl.SSLError) as cm:
ctx.load_dh_params(CERTFILE)
@skip_if_broken_ubuntu_ssl
@ -590,6 +590,47 @@ class ContextTests(unittest.TestCase):
self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
class SSLErrorTests(unittest.TestCase):
def test_str(self):
# The str() of a SSLError doesn't include the errno
e = ssl.SSLError(1, "foo")
self.assertEqual(str(e), "foo")
self.assertEqual(e.errno, 1)
# Same for a subclass
e = ssl.SSLZeroReturnError(1, "foo")
self.assertEqual(str(e), "foo")
self.assertEqual(e.errno, 1)
def test_lib_reason(self):
# Test the library and reason attributes
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
with self.assertRaises(ssl.SSLError) as cm:
ctx.load_dh_params(CERTFILE)
self.assertEqual(cm.exception.library, 'PEM')
self.assertEqual(cm.exception.reason, 'NO_START_LINE')
s = str(cm.exception)
self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
def test_subclass(self):
# Check that the appropriate SSLError subclass is raised
# (this only tests one of them)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
with socket.socket() as s:
s.bind(("127.0.0.1", 0))
s.listen(5)
with socket.socket() as c:
c.connect(s.getsockname())
c.setblocking(False)
c = ctx.wrap_socket(c, False, do_handshake_on_connect=False)
with self.assertRaises(ssl.SSLWantReadError) as cm:
c.do_handshake()
s = str(cm.exception)
self.assertTrue(s.startswith("The operation did not complete (read)"), s)
# For compatibility
self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
class NetworkedTests(unittest.TestCase):
def test_connect(self):
@ -1931,7 +1972,7 @@ def test_main(verbose=False):
if not os.path.exists(filename):
raise support.TestFailed("Can't read certificate file %r" % filename)
tests = [ContextTests, BasicSocketTests]
tests = [ContextTests, BasicSocketTests, SSLErrorTests]
if support.is_resource_enabled('network'):
tests.append(NetworkedTests)