]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #9792: In case of connection failure, socket.create_connection()
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 7 Sep 2010 21:05:49 +0000 (21:05 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 7 Sep 2010 21:05:49 +0000 (21:05 +0000)
would swallow the exception and raise a new one, making it impossible
to fetch the original errno, or to filter timeout errors.  Now the
original error is re-raised.

Lib/socket.py
Lib/test/test_socket.py
Misc/NEWS

index 89fe36e7f9a2749cc124290730cc9b018263afa4..004d6a9445fe10765fe92813ab8ecfb6383007ec 100644 (file)
@@ -297,8 +297,8 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
     An host of '' or port 0 tells the OS to use the default.
     """
 
-    msg = "getaddrinfo returns an empty list"
     host, port = address
+    err = None
     for res in getaddrinfo(host, port, 0, SOCK_STREAM):
         af, socktype, proto, canonname, sa = res
         sock = None
@@ -311,9 +311,12 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
             sock.connect(sa)
             return sock
 
-        except error as err:
-            msg = err
+        except error as _:
+            err = _
             if sock is not None:
                 sock.close()
 
-    raise error(msg)
+    if err is not None:
+        raise err
+    else:
+        raise error("getaddrinfo returns an empty list")
index 2f6d00756e6a5a4ebd012b044e20a24dfad4254f..19c494b127b4325731eab71c657230c519d9b7d3 100644 (file)
@@ -13,6 +13,7 @@ import queue
 import sys
 import os
 import array
+import contextlib
 from weakref import proxy
 import signal
 
@@ -1203,12 +1204,42 @@ class BasicTCPTest2(NetworkConnectionTest, BasicTCPTest):
 
 class NetworkConnectionNoServer(unittest.TestCase):
 
-    def testWithoutServer(self):
+    class MockSocket(socket.socket):
+        def connect(self, *args):
+            raise socket.timeout('timed out')
+
+    @contextlib.contextmanager
+    def mocked_socket_module(self):
+        """Return a socket which times out on connect"""
+        old_socket = socket.socket
+        socket.socket = self.MockSocket
+        try:
+            yield
+        finally:
+            socket.socket = old_socket
+
+    def test_connect(self):
         port = support.find_unused_port()
-        self.assertRaises(
-            socket.error,
-            lambda: socket.create_connection((HOST, port))
-        )
+        cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        with self.assertRaises(socket.error) as cm:
+            cli.connect((HOST, port))
+        self.assertEqual(cm.exception.errno, errno.ECONNREFUSED)
+
+    def test_create_connection(self):
+        # Issue #9792: errors raised by create_connection() should have
+        # a proper errno attribute.
+        port = support.find_unused_port()
+        with self.assertRaises(socket.error) as cm:
+            socket.create_connection((HOST, port))
+        self.assertEqual(cm.exception.errno, errno.ECONNREFUSED)
+
+    def test_create_connection_timeout(self):
+        # Issue #9792: create_connection() should not recast timeout errors
+        # as generic socket errors.
+        with self.mocked_socket_module():
+            with self.assertRaises(socket.timeout):
+                socket.create_connection((HOST, 1234))
+
 
 @unittest.skipUnless(thread, 'Threading required for this test.')
 class NetworkConnectionAttributesTest(SocketTCPTest, ThreadableTest):
index 81df8036c5a02af73f5e3ed53776b8f2245917b0..c0f2d6edee9da7a1c9b13c09141f8c75311c57f3 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,11 @@ Core and Builtins
 Library
 -------
 
+- Issue #9792: In case of connection failure, socket.create_connection()
+  would swallow the exception and raise a new one, making it impossible
+  to fetch the original errno, or to filter timeout errors.  Now the
+  original error is re-raised.
+
 - Issue #9758: When fcntl.ioctl() was called with mutable_flag set to True,
   and the passed buffer was exactly 1024 bytes long, the buffer wouldn't
   be updated back after the system call.  Original patch by Brian Brazil.