Avoid socket leak if HTTPSConnection.connect() fails
MODIFY
src/urllib3/connection.py
src/urllib3/connection.py
@@ -447,17 +447,16 @@ class HTTPSConnection(HTTPConnection):
self._connecting_to_proxy = bool(self.proxy)
sock: Union[socket.socket, "ssl.SSLSocket"]
- sock = self._new_conn()
+ self.sock = sock = self._new_conn()
hostname: str = self.host
tls_in_tls = False
if self._is_using_tunnel():
if self.tls_in_tls_required:
- sock = self._connect_tls_proxy(hostname, sock)
+ self.sock = sock = self._connect_tls_proxy(hostname, sock)
tls_in_tls = True
self._connecting_to_proxy = False
- self.sock = sock
# Calls self._set_hostport(), so self.host is
# self._tunnel_host below.

MODIFY
test/with_dummyserver/test_https.py
test/with_dummyserver/test_https.py
@@ -329,6 +329,23 @@ class TestHTTPS(HTTPSDummyServerTestCase):
or "self signed certificate in certificate chain" in str(e.value.reason)
), f"Expected 'certificate verify failed', instead got: {e.value.reason!r}"
+ def test_wrap_socket_failure_resource_leak(self) -> None:
+ with HTTPSConnectionPool(
+ self.host,
+ self.port,
+ cert_reqs="CERT_REQUIRED",
+ ca_certs=self.bad_ca_path,
+ ssl_minimum_version=self.tls_version(),
+ ) as https_pool:
+ conn = https_pool._get_conn()
+ try:
+ with pytest.raises(ssl.SSLError):
+ conn.connect()
+
+ assert conn.sock
+ finally:
+ conn.close()
+
def test_verified_without_ca_certs(self) -> None:
# default is cert_reqs=None which is ssl.CERT_NONE
with HTTPSConnectionPool(

Avoid socket leak if HTTPSConnection.connect() fails