Skip to content

Commit

Permalink
Raise warning if proxy key is eg. "all" instead of "all://". (#1127)
Browse files Browse the repository at this point in the history
* #1105 added deprecation warning, raised when we try to use proxies={"http": ...} instead of {"http://": ...}. Updated docs and added unit, which check the warning presence

* Update tests/client/test_proxies.py

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>

* Update tests/client/test_proxies.py

Co-authored-by: Tom Christie <tom@tomchristie.com>
Co-authored-by: Florimond Manca <florimond.manca@gmail.com>
  • Loading branch information
3 people authored Aug 5, 2020
1 parent 1da46f3 commit 7279ed4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 28 deletions.
20 changes: 10 additions & 10 deletions docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ For more advanced use cases, pass a proxies `dict`. For example, to route HTTP a

```python
proxies = {
"http": "http://localhost:8030",
"https": "http://localhost:8031",
"http://": "http://localhost:8030",
"https://": "http://localhost:8031",
}

with httpx.Client(proxies=proxies) as client:
Expand All @@ -295,7 +295,7 @@ with httpx.Client(proxies=proxies) as client:
For detailed information about proxy routing, see the [Routing](#routing) section.

!!! tip "Gotcha"
In most cases, the proxy URL for the `https` key _should_ use the `http://` scheme (that's not a typo!).
In most cases, the proxy URL for the `https://` key _should_ use the `http://` scheme (that's not a typo!).

This is because HTTP proxying requires initiating a connection with the proxy server. While it's possible that your proxy supports doing it via HTTPS, most proxies only support doing it via HTTP.

Expand All @@ -307,7 +307,7 @@ Proxy credentials can be passed as the `userinfo` section of the proxy URL. For

```python
proxies = {
"http": "http://username:password@localhost:8030",
"http://": "http://username:password@localhost:8030",
# ...
}
```
Expand All @@ -316,7 +316,7 @@ proxies = {

HTTPX provides fine-grained controls for deciding which requests should go through a proxy, and which shouldn't. This process is known as proxy routing.

The `proxies` dictionary maps URL patterns ("proxy keys") to proxy URLs. HTTPX matches requested URLs against proxy keys to decide which proxy should be used, if any. Matching is done from most specific proxy keys (e.g. `https://<domain>:<port>`) to least specific ones (e.g. `https`).
The `proxies` dictionary maps URL patterns ("proxy keys") to proxy URLs. HTTPX matches requested URLs against proxy keys to decide which proxy should be used, if any. Matching is done from most specific proxy keys (e.g. `https://<domain>:<port>`) to least specific ones (e.g. `https://`).

HTTPX supports routing proxies based on **scheme**, **domain**, **port**, or a combination of these.

Expand All @@ -326,7 +326,7 @@ Route everything through a proxy...

```python
proxies = {
"all": "http://localhost:8030",
"all://": "http://localhost:8030",
}
```

Expand All @@ -336,8 +336,8 @@ Route HTTP requests through one proxy, and HTTPS requests through another...

```python
proxies = {
"http": "http://localhost:8030",
"https": "http://localhost:8031",
"http://": "http://localhost:8030",
"https://": "http://localhost:8031",
}
```

Expand Down Expand Up @@ -402,7 +402,7 @@ To do so, pass `None` as the proxy URL. For example...
```python
proxies = {
# Route requests through a proxy by default...
"all": "http://localhost:8031",
"all://": "http://localhost:8031",
# Except those for "example.com".
"all://example.com": None,
}
Expand All @@ -415,7 +415,7 @@ You can combine the routing features outlined above to build complex proxy routi
```python
proxies = {
# Route all traffic through a proxy by default...
"all": "http://localhost:8030",
"all://": "http://localhost:8030",
# But don't use proxies for HTTPS requests to "domain.io"...
"https://domain.io": None,
# And use another proxy for requests to "example.com" and its subdomains...
Expand Down
5 changes: 5 additions & 0 deletions httpx/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ def __init__(self, pattern: str) -> None:
from ._models import URL

if pattern and ":" not in pattern:
warn_deprecated(
f"Proxy keys should use proper URL forms rather "
f"than plain scheme strings. "
f'Instead of "{pattern}", use "{pattern}://"'
)
pattern += "://"

url = URL(pattern)
Expand Down
56 changes: 38 additions & 18 deletions tests/client/test_proxies.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@ def url_to_origin(url: str):
@pytest.mark.parametrize(
["proxies", "expected_proxies"],
[
("http://127.0.0.1", [("all", "http://127.0.0.1")]),
({"all": "http://127.0.0.1"}, [("all", "http://127.0.0.1")]),
("http://127.0.0.1", [("all://", "http://127.0.0.1")]),
({"all://": "http://127.0.0.1"}, [("all://", "http://127.0.0.1")]),
(
{"http": "http://127.0.0.1", "https": "https://127.0.0.1"},
[("http", "http://127.0.0.1"), ("https", "https://127.0.0.1")],
{"http://": "http://127.0.0.1", "https://": "https://127.0.0.1"},
[("http://", "http://127.0.0.1"), ("https://", "https://127.0.0.1")],
),
(httpx.Proxy("http://127.0.0.1"), [("all", "http://127.0.0.1")]),
(httpx.Proxy("http://127.0.0.1"), [("all://", "http://127.0.0.1")]),
(
{"https": httpx.Proxy("https://127.0.0.1"), "all": "http://127.0.0.1"},
[("all", "http://127.0.0.1"), ("https", "https://127.0.0.1")],
{
"https://": httpx.Proxy("https://127.0.0.1"),
"all://": "http://127.0.0.1",
},
[("all://", "http://127.0.0.1"), ("https://", "https://127.0.0.1")],
),
],
)
Expand All @@ -54,7 +57,7 @@ def test_proxies_parameter(proxies, expected_proxies):
[
("http://example.com", None, None),
("http://example.com", {}, None),
("http://example.com", {"https": PROXY_URL}, None),
("http://example.com", {"https://": PROXY_URL}, None),
("http://example.com", {"http://example.net": PROXY_URL}, None),
# Using "*" should match any domain name.
("http://example.com", {"http://*": PROXY_URL}, PROXY_URL),
Expand All @@ -71,9 +74,9 @@ def test_proxies_parameter(proxies, expected_proxies):
("http://wwwexample.com", {"http://*example.com": PROXY_URL}, None),
# ...
("http://example.com:443", {"http://example.com": PROXY_URL}, PROXY_URL),
("http://example.com", {"all": PROXY_URL}, PROXY_URL),
("http://example.com", {"all": PROXY_URL, "http://example.com": None}, None),
("http://example.com", {"http": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://": PROXY_URL, "http://example.com": None}, None),
("http://example.com", {"http://": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://example.com": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://example.com:80": PROXY_URL}, None),
("http://example.com", {"http://example.com": PROXY_URL}, PROXY_URL),
Expand All @@ -83,8 +86,8 @@ def test_proxies_parameter(proxies, expected_proxies):
(
"http://example.com",
{
"all": PROXY_URL + ":1",
"http": PROXY_URL + ":2",
"all://": PROXY_URL + ":1",
"http://": PROXY_URL + ":2",
"all://example.com": PROXY_URL + ":3",
"http://example.com": PROXY_URL + ":4",
},
Expand All @@ -93,15 +96,15 @@ def test_proxies_parameter(proxies, expected_proxies):
(
"http://example.com",
{
"all": PROXY_URL + ":1",
"http": PROXY_URL + ":2",
"all://": PROXY_URL + ":1",
"http://": PROXY_URL + ":2",
"all://example.com": PROXY_URL + ":3",
},
PROXY_URL + ":3",
),
(
"http://example.com",
{"all": PROXY_URL + ":1", "http": PROXY_URL + ":2"},
{"all://": PROXY_URL + ":1", "http://": PROXY_URL + ":2"},
PROXY_URL + ":2",
),
],
Expand All @@ -120,12 +123,12 @@ def test_transport_for_request(url, proxies, expected):

@pytest.mark.asyncio
async def test_async_proxy_close():
client = httpx.AsyncClient(proxies={"all": PROXY_URL})
client = httpx.AsyncClient(proxies={"all://": PROXY_URL})
await client.aclose()


def test_sync_proxy_close():
client = httpx.Client(proxies={"all": PROXY_URL})
client = httpx.Client(proxies={"all://": PROXY_URL})
client.close()


Expand Down Expand Up @@ -244,3 +247,20 @@ def test_proxies_environ(monkeypatch, client_class, url, env, expected):
assert transport == client._transport
else:
assert transport.proxy_origin == url_to_origin(expected)


@pytest.mark.parametrize(
["proxies", "expected_scheme"],
[
({"http": "http://127.0.0.1"}, "http://"),
({"https": "http://127.0.0.1"}, "https://"),
({"all": "http://127.0.0.1"}, "all://"),
],
)
def test_for_deprecated_proxy_params(proxies, expected_scheme):
with pytest.deprecated_call() as block:
httpx.AsyncClient(proxies=proxies)

warning_message = str(block.pop(DeprecationWarning))

assert expected_scheme in warning_message

0 comments on commit 7279ed4

Please sign in to comment.