Repository: urllib3/urllib3

Issue:
Ensure HTTP/2 isn't offered for tunnel CONNECT requests
We don't intend to support HTTP/2 for establishing a proxy tunnel, HTTP/1.1 works just fine for this purpose.


Discussion:
Hey have raise a pr. Do we need any other flags also? 
https://github.com/urllib3/urllib3/pull/3321



Patch:
diff --git a/src/urllib3/http2/connection.py b/src/urllib3/http2/connection.py
index 358c9fc4b0..f486145280 100644
--- a/src/urllib3/http2/connection.py
+++ b/src/urllib3/http2/connection.py
@@ -95,6 +95,9 @@ def __init__(
 
         super().__init__(host, port, **kwargs)
 
+        if self._tunnel_host is not None:
+            raise NotImplementedError("Tunneling isn't supported with HTTP/2")
+
     def _new_h2_conn(self) -> _LockedObject[h2.connection.H2Connection]:
         config = h2.config.H2Configuration(client_side=True)
         return _LockedObject(h2.connection.H2Connection(config=config))
@@ -209,6 +212,17 @@ def send(self, data: typing.Any) -> None:
                     % type(data)
                 )
 
+    def set_tunnel(
+        self,
+        host: str,
+        port: int | None = None,
+        headers: typing.Mapping[str, str] | None = None,
+        scheme: str = "http",
+    ) -> None:
+        raise NotImplementedError(
+            "HTTP/2 does not support setting up a tunnel through a proxy"
+        )
+
     def getresponse(  # type: ignore[override]
         self,
     ) -> HTTP2Response:


Test patch:
diff --git a/test/with_dummyserver/test_connectionpool.py b/test/with_dummyserver/test_connectionpool.py
index 7c9bb9beab..9f915462c2 100644
--- a/test/with_dummyserver/test_connectionpool.py
+++ b/test/with_dummyserver/test_connectionpool.py
@@ -452,7 +452,6 @@ def test_socket_timeout_updated_on_reuse_parameter(
             )
 
     def test_tunnel(self, http_version: str) -> None:
-        # note the actual httplib.py has no tests for this functionality
         timeout = Timeout(total=None)
         with HTTPConnectionPool(self.host, self.port, timeout=timeout) as pool:
             conn = pool._get_conn()
diff --git a/test/with_dummyserver/test_https.py b/test/with_dummyserver/test_https.py
index 1c6f7a8948..fe6a037be5 100644
--- a/test/with_dummyserver/test_https.py
+++ b/test/with_dummyserver/test_https.py
@@ -616,7 +616,7 @@ def test_https_timeout(self) -> None:
             with pytest.warns(InsecureRequestWarning):
                 https_pool.request("GET", "/")
 
-    def test_tunnel(self) -> None:
+    def test_tunnel(self, http_version: str) -> None:
         """test the _tunnel behavior"""
         timeout = Timeout(total=None)
         with HTTPSConnectionPool(
@@ -627,13 +627,21 @@ def test_tunnel(self) -> None:
             ssl_minimum_version=self.tls_version(),
         ) as https_pool:
             with contextlib.closing(https_pool._new_conn()) as conn:
-                conn.set_tunnel(self.host, self.port)
-                with mock.patch.object(
-                    conn, "_tunnel", create=True, return_value=None
-                ) as conn_tunnel:
-                    with pytest.warns(InsecureRequestWarning):
-                        https_pool._make_request(conn, "GET", "/")
-                conn_tunnel.assert_called_once_with()
+                if http_version == "h2":
+                    with pytest.raises(NotImplementedError) as e:
+                        conn.set_tunnel(self.host, self.port)
+                    assert (
+                        str(e.value)
+                        == "HTTP/2 does not support setting up a tunnel through a proxy"
+                    )
+                else:
+                    conn.set_tunnel(self.host, self.port)
+                    with mock.patch.object(
+                        conn, "_tunnel", create=True, return_value=None
+                    ) as conn_tunnel:
+                        with pytest.warns(InsecureRequestWarning):
+                            https_pool._make_request(conn, "GET", "/")
+                    conn_tunnel.assert_called_once_with()
 
     @requires_network()
     def test_enhanced_timeout(self) -> None:
diff --git a/test/with_dummyserver/test_socketlevel.py b/test/with_dummyserver/test_socketlevel.py
index 87dafd4223..c17732eca6 100644
--- a/test/with_dummyserver/test_socketlevel.py
+++ b/test/with_dummyserver/test_socketlevel.py
@@ -1138,6 +1138,27 @@ def echo_socket_handler(listener: socket.socket) -> None:
                     retries=False,
                 )
 
+    def test_tunnel_sets_http_11_alpn(self) -> None:
+        done_receiving = Event()
+        self.buf = b""
+
+        def socket_handler(listener: socket.socket) -> None:
+            sock = listener.accept()[0]
+
+            self.buf = sock.recv(65536)  # We only accept one packet
+            done_receiving.set()  # let the test know it can proceed
+            sock.close()
+
+        self._start_server(socket_handler)
+        base_url = f"https://{self.host}:{self.port}"
+        with proxy_from_url(base_url) as proxy:
+            with pytest.raises(MaxRetryError):
+                proxy.request("GET", "https://localhost/")
+
+        done_receiving.wait()
+        assert b"http/1.1" in self.buf
+        assert b"h2" not in self.buf
+
     def test_connect_reconn(self) -> None:
         def proxy_ssl_one(listener: socket.socket) -> None:
             sock = listener.accept()[0]