mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									a88c83cbab
								
							
						
					
					
						commit
						4b92b5fad3
					
				
					 3 changed files with 48 additions and 9 deletions
				
			
		|  | @ -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. |     An host of '' or port 0 tells the OS to use the default. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     msg = "getaddrinfo returns an empty list" |  | ||||||
|     host, port = address |     host, port = address | ||||||
|  |     err = None | ||||||
|     for res in getaddrinfo(host, port, 0, SOCK_STREAM): |     for res in getaddrinfo(host, port, 0, SOCK_STREAM): | ||||||
|         af, socktype, proto, canonname, sa = res |         af, socktype, proto, canonname, sa = res | ||||||
|         sock = None |         sock = None | ||||||
|  | @ -311,9 +311,12 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, | ||||||
|             sock.connect(sa) |             sock.connect(sa) | ||||||
|             return sock |             return sock | ||||||
| 
 | 
 | ||||||
|         except error as err: |         except error as _: | ||||||
|             msg = err |             err = _ | ||||||
|             if sock is not None: |             if sock is not None: | ||||||
|                 sock.close() |                 sock.close() | ||||||
| 
 | 
 | ||||||
|     raise error(msg) |     if err is not None: | ||||||
|  |         raise err | ||||||
|  |     else: | ||||||
|  |         raise error("getaddrinfo returns an empty list") | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| import sys | import sys | ||||||
| import os | import os | ||||||
| import array | import array | ||||||
|  | import contextlib | ||||||
| from weakref import proxy | from weakref import proxy | ||||||
| import signal | import signal | ||||||
| 
 | 
 | ||||||
|  | @ -1203,12 +1204,42 @@ class BasicTCPTest2(NetworkConnectionTest, BasicTCPTest): | ||||||
| 
 | 
 | ||||||
| class NetworkConnectionNoServer(unittest.TestCase): | 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() |         port = support.find_unused_port() | ||||||
|         self.assertRaises( |         cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||||||
|             socket.error, |         with self.assertRaises(socket.error) as cm: | ||||||
|             lambda: socket.create_connection((HOST, port)) |             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.') | @unittest.skipUnless(thread, 'Threading required for this test.') | ||||||
| class NetworkConnectionAttributesTest(SocketTCPTest, ThreadableTest): | class NetworkConnectionAttributesTest(SocketTCPTest, ThreadableTest): | ||||||
|  |  | ||||||
|  | @ -13,6 +13,11 @@ Core and Builtins | ||||||
| Library | 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, | - 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 |   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. |   be updated back after the system call.  Original patch by Brian Brazil. | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Antoine Pitrou
						Antoine Pitrou