Repository: urllib3/urllib3

Issue:
Incorrect behaviour of `proxy_is_verified`
### Subject

`proxy_is_verified` is never set for HTTPs to HTTP proxies. `proxy_is_verified` is set only at https://github.com/urllib3/urllib3/blob/main/src/urllib3/connection.py#L694 and the function `_connect_tls_proxy` containing this line is called only when we are creating a HTTP tunnel https://github.com/urllib3/urllib3/blob/main/src/urllib3/connection.py#L672. We would have to set the value for `proxy_is_verified` for scenarios when we are not using a TLS-in-TLS tunnel and instead setting up a TLS connection for HTTPs to HTTP case.

More context - https://github.com/urllib3/urllib3/pull/3070#pullrequestreview-1607114075

### Environment

Describe your environment.
At least, paste here the output of:

```python
import platform
import ssl
import urllib3

print("OS", platform.platform()) # OS macOS-13.4.1-arm64-arm-64bit
print("Python", platform.python_version()) # Python 3.10.12
print(ssl.OPENSSL_VERSION) # OpenSSL 3.1.1 30 May 2023
print("urllib3", urllib3.__version__) # urllib3 1.26.14
```

### Steps to Reproduce

You can add a `print` statement to print `proxy_is_verified` for `HTTPS` to `HTTP` connection. The value of `proxy_is_verified` is set to `None` and never updated to `False` for the following example. 

```python
proxy = urllib3.ProxyManager('https://127.0.0.1:8443', cert_reqs='NONE')
res = proxy.request('GET', 'https://bff.familyid.samagra.io')
```

### Expected Behavior
`proxy_is_verified` set to `False` or `True` appropriately. 

### Actual Behavior

According to this comment in code if we are connected to proxy, it should not be `Nonfe` https://github.com/urllib3/urllib3/blob/d9f85a749488188c286cd50606d159874db94d5f/src/urllib3/connection.py#L120

But `proxy_is_verified` is set to `None` instead of `False`

What happens instead.

For `HTTPS` proxy connection to `HTTP` host, `proxy_is_verified` is never set properly. `proxy_is_verified` is set appropriately for `HTTPS` to `HTTPS` connections. 




Discussion:
Hey folks, I would like to solve this. lt will help unblock #3070 



Patch:
diff --git a/changelog/3130.bugfix.rst b/changelog/3130.bugfix.rst
new file mode 100644
index 0000000000..cf301fb406
--- /dev/null
+++ b/changelog/3130.bugfix.rst
@@ -0,0 +1,3 @@
+Fixed ``HTTPConnection.proxy_is_verified`` and ``HTTPSConnection.proxy_is_verified``
+to be always set to a boolean after connecting to a proxy. It could be
+``None`` in some cases previously.
\ No newline at end of file
diff --git a/src/urllib3/connection.py b/src/urllib3/connection.py
index 42b1bbc5e5..a438713a97 100644
--- a/src/urllib3/connection.py
+++ b/src/urllib3/connection.py
@@ -248,6 +248,9 @@ def connect(self) -> None:
         # not using tunnelling.
         self._has_connected_to_proxy = bool(self.proxy)
 
+        if self._has_connected_to_proxy:
+            self.proxy_is_verified = False
+
     @property
     def is_closed(self) -> bool:
         return self.sock is None
@@ -611,8 +614,11 @@ def connect(self) -> None:
         if self._tunnel_host is not None:
             # We're tunneling to an HTTPS origin so need to do TLS-in-TLS.
             if self._tunnel_scheme == "https":
+                # _connect_tls_proxy will verify and assign proxy_is_verified
                 self.sock = sock = self._connect_tls_proxy(self.host, sock)
                 tls_in_tls = True
+            elif self._tunnel_scheme == "http":
+                self.proxy_is_verified = False
 
             # If we're tunneling it means we're connected to our proxy.
             self._has_connected_to_proxy = True
@@ -656,6 +662,11 @@ def connect(self) -> None:
             assert_fingerprint=self.assert_fingerprint,
         )
         self.sock = sock_and_verified.socket
+
+        # TODO: Set correct `self.is_verified` in case of HTTPS proxy +
+        #       HTTP destination, see
+        #       `test_is_verified_https_proxy_to_http_target` and
+        #       https://github.com/urllib3/urllib3/issues/3267.
         self.is_verified = sock_and_verified.is_verified
 
         # If there's a proxy to be connected to we are fully connected.
@@ -663,6 +674,11 @@ def connect(self) -> None:
         # not using tunnelling.
         self._has_connected_to_proxy = bool(self.proxy)
 
+        # Set `self.proxy_is_verified` unless it's already set while
+        # establishing a tunnel.
+        if self._has_connected_to_proxy and self.proxy_is_verified is None:
+            self.proxy_is_verified = sock_and_verified.is_verified
+
     def _connect_tls_proxy(self, hostname: str, sock: socket.socket) -> ssl.SSLSocket:
         """
         Establish a TLS connection to the proxy using the provided SSL context.


Test patch:
diff --git a/test/with_dummyserver/test_proxy_poolmanager.py b/test/with_dummyserver/test_proxy_poolmanager.py
index db9229895c..e520f30063 100644
--- a/test/with_dummyserver/test_proxy_poolmanager.py
+++ b/test/with_dummyserver/test_proxy_poolmanager.py
@@ -43,6 +43,16 @@
 from .. import TARPIT_HOST, requires_network
 
 
+def assert_is_verified(pm: ProxyManager, *, proxy: bool, target: bool) -> None:
+    pool = list(pm.pools._container.values())[-1]  # retrieve last pool entry
+    connection = (
+        pool.pool.queue[-1] if pool.pool is not None else None
+    )  # retrieve last connection entry
+
+    assert connection.proxy_is_verified is proxy
+    assert connection.is_verified is target
+
+
 class TestHTTPProxyManager(HypercornDummyProxyTestCase):
     @classmethod
     def setup_class(cls) -> None:
@@ -83,6 +93,31 @@ def test_https_proxy(self) -> None:
             r = https.request("GET", f"{self.http_url}/")
             assert r.status == 200
 
+    def test_is_verified_http_proxy_to_http_target(self) -> None:
+        with proxy_from_url(self.proxy_url, ca_certs=DEFAULT_CA) as http:
+            r = http.request("GET", f"{self.http_url}/")
+            assert r.status == 200
+            assert_is_verified(http, proxy=False, target=False)
+
+    def test_is_verified_http_proxy_to_https_target(self) -> None:
+        with proxy_from_url(self.proxy_url, ca_certs=DEFAULT_CA) as http:
+            r = http.request("GET", f"{self.https_url}/")
+            assert r.status == 200
+            assert_is_verified(http, proxy=False, target=True)
+
+    @pytest.mark.xfail(reason="see https://github.com/urllib3/urllib3/issues/3267")
+    def test_is_verified_https_proxy_to_http_target(self) -> None:
+        with proxy_from_url(self.https_proxy_url, ca_certs=DEFAULT_CA) as https:
+            r = https.request("GET", f"{self.http_url}/")
+            assert r.status == 200
+            assert_is_verified(https, proxy=True, target=False)
+
+    def test_is_verified_https_proxy_to_https_target(self) -> None:
+        with proxy_from_url(self.https_proxy_url, ca_certs=DEFAULT_CA) as https:
+            r = https.request("GET", f"{self.https_url}/")
+            assert r.status == 200
+            assert_is_verified(https, proxy=True, target=True)
+
     def test_http_and_https_kwarg_ca_cert_data_proxy(self) -> None:
         with open(DEFAULT_CA) as pem_file:
             pem_file_data = pem_file.read()