Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable tunnel for http2 requests #3321

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/urllib3/http2.py
Expand Up @@ -61,6 +61,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))
Expand Down Expand Up @@ -118,6 +121,17 @@ def send(self, data: bytes) -> None: # type: ignore[override] # Defensive:
return
raise NotImplementedError("Sending data isn't supported yet")

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:
Expand Down
47 changes: 29 additions & 18 deletions test/with_dummyserver/test_connectionpool.py
Expand Up @@ -437,33 +437,44 @@ def test_socket_timeout_updated_on_reuse_parameter(
[mock.call(x) for x in expect_settimeout_calls]
)

def test_tunnel(self) -> None:
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()
try:
conn.set_tunnel(self.host, self.port)
with mock.patch.object(
conn, "_tunnel", create=True, return_value=None
) as conn_tunnel:
pool._make_request(conn, "GET", "/")
conn_tunnel.assert_called_once_with()
finally:
conn.close()
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:
try:
conn.set_tunnel(self.host, self.port)
with mock.patch.object(
conn, "_tunnel", create=True, return_value=None
) as conn_tunnel:
pool._make_request(conn, "GET", "/")
conn_tunnel.assert_called_once_with()
finally:
conn.close()

# test that it's not called when tunnel is not set
timeout = Timeout(total=None)
with HTTPConnectionPool(self.host, self.port, timeout=timeout) as pool:
conn = pool._get_conn()
try:
with mock.patch.object(
conn, "_tunnel", create=True, return_value=None
) as conn_tunnel:
pool._make_request(conn, "GET", "/")
assert not conn_tunnel.called
finally:
conn.close()
if http_version == "h2":
pass
else:
try:
with mock.patch.object(
conn, "_tunnel", create=True, return_value=None
) as conn_tunnel:
pool._make_request(conn, "GET", "/")
assert not conn_tunnel.called
finally:
conn.close()

def test_redirect_relative_url_no_deprecation(self) -> None:
with HTTPConnectionPool(self.host, self.port) as pool:
Expand Down
24 changes: 16 additions & 8 deletions test/with_dummyserver/test_https.py
Expand Up @@ -603,7 +603,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(
Expand All @@ -614,13 +614,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:
Expand Down