diff --git a/httpx/_client.py b/httpx/_client.py index 13cd933673..476a8bbcc4 100644 --- a/httpx/_client.py +++ b/httpx/_client.py @@ -394,6 +394,8 @@ def _merge_url(self, url: URL | str) -> URL: to create the URL used for the outgoing request. """ merge_url = URL(url) + if merge_url.scheme and not merge_url.host: + raise InvalidURL(f"Invalid URL '{url}': has scheme but missing host") if merge_url.is_relative_url: # To merge URLs we always append to the base URL. To get this # behaviour correct we always ensure the base URL ends in a '/' diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py index 8d7eaa3c58..96e1bd5b19 100644 --- a/tests/client/test_async_client.py +++ b/tests/client/test_async_client.py @@ -32,7 +32,9 @@ async def test_get(server): @pytest.mark.anyio async def test_get_invalid_url(server, url): async with httpx.AsyncClient() as client: - with pytest.raises((httpx.UnsupportedProtocol, httpx.LocalProtocolError)): + with pytest.raises( + (httpx.UnsupportedProtocol, httpx.LocalProtocolError, httpx.InvalidURL) + ): await client.get(url) diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 657839018a..90ee189527 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -40,10 +40,27 @@ def test_get(server): ) def test_get_invalid_url(server, url): with httpx.Client() as client: - with pytest.raises((httpx.UnsupportedProtocol, httpx.LocalProtocolError)): + with pytest.raises( + (httpx.UnsupportedProtocol, httpx.LocalProtocolError, httpx.InvalidURL) + ): client.get(url) +def test_get_invalid_url_with_scheme_no_host(): + """ + Regression test for: https://github.com/encode/httpx/issues/1832 + URLs with scheme but no host should raise InvalidURL. + """ + with httpx.Client() as client: + with pytest.raises(httpx.InvalidURL) as exc: + client.get("https:/google.com") + assert "has scheme but missing host" in str(exc.value) + + with pytest.raises(httpx.InvalidURL) as exc: + client.get("https:///google.com") + assert "has scheme but missing host" in str(exc.value) + + def test_build_request(server): url = server.url.copy_with(path="/echo_headers") headers = {"Custom-header": "value"}