Repository: urllib3/urllib3

Issue:
socket leaked when ssl_wrap_socket fails 
### Subject

socket leaked when ssl_wrap_socket fails 

### Environment

```
>>> import platform
>>> import urllib3
>>> 
>>> print("OS", platform.platform())
OS Linux-5.4.0-100-generic-x86_64-with-glibc2.31
>>> print("Python", platform.python_version())
Python 3.9.10
>>> print("urllib3", urllib3.__version__)
urllib3 1.26.8
```

### Steps to Reproduce

```python
import pytest
import urllib3


def test_requests_leak():
    with pytest.raises(Exception):
        with urllib3.PoolManager(ca_certs=__file__) as http:
            http.request("GET", "https://google.com")
```

### Expected Behavior

no ResourceWarning

### Actual Behavior
```
:

    def unraisable_exception_runtest_hook() -> Generator[None, None, None]:
        with catch_unraisable_exception() as cm:
            yield
            if cm.unraisable:
                if cm.unraisable.err_msg is not None:
                    err_msg = cm.unraisable.err_msg
                else:
                    err_msg = "Exception ignored in"
                msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
                msg += "".join(
                    traceback.format_exception(
                        cm.unraisable.exc_type,
                        cm.unraisable.exc_value,
                        cm.unraisable.exc_traceback,
                    )
                )
>               warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E               pytest.PytestUnraisableExceptionWarning: Exception ignored in: <socket.socket fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6>
E               
E               Traceback (most recent call last):
E                 File "/home/graingert/projects/requests-leak/test_requests_leak.py", line 8, in test_requests_leak
E                   http.request("GET", "https://google.com")
E               ResourceWarning: unclosed <socket.socket fd=14, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.99.58', 43618), raddr=('172.217.16.238', 443)>
```


Discussion:
pquentin: Nice, the tests passed. Do we need a changelog entry, or are we going to pick it up from 1.26.x?
sethmlarson: @pquentin Yeah, we're backporting this one, no changelog needed.

Patch:
diff --git a/src/urllib3/connection.py b/src/urllib3/connection.py
index c53d3ca9..4cc72bab 100644
--- a/src/urllib3/connection.py
+++ b/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.


Test patch:
diff --git a/test/with_dummyserver/test_https.py b/test/with_dummyserver/test_https.py
index 7d498fa6..1a6d6c40 100644
--- a/test/with_dummyserver/test_https.py
+++ b/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(