Skip to content

Commit f8981f3

Browse files
karpetrosyantomchristieT-256
authored
Add the 'proxy' parameter and deprecate 'proxies'. (#2879)
* Add the proxy parameter and deprecate proxies * Make the Client.proxy and HTTPTransport.proxy types the same * Update httpx/_transports/default.py Co-authored-by: T-256 <[email protected]> * Update httpx/_transports/default.py Co-authored-by: T-256 <[email protected]> * Drop unneeded noqa * Changelog * update documentation * Allow None in mounts * typos * Update httpx/_types.py * Changes proxies to proxy in CLI app * Add proxy to request function * Update CHANGELOG.md Co-authored-by: Tom Christie <[email protected]> * Update docs/troubleshooting.md Co-authored-by: Tom Christie <[email protected]> * Update docs/troubleshooting.md Co-authored-by: Tom Christie <[email protected]> * Lint --------- Co-authored-by: Tom Christie <[email protected]> Co-authored-by: T-256 <[email protected]>
1 parent b471f01 commit f8981f3

File tree

11 files changed

+281
-170
lines changed

11 files changed

+281
-170
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased
88

9+
### Changed
10+
11+
* The `proxies` argument is now deprecated. You should use the `proxy` argument instead, or use `mounts=` for more complex configurations. (#2879)
12+
913
### Fixed
1014

1115
* Allow URLs where username or password contains unescaped '@'. (#2986)

docs/advanced.md

Lines changed: 132 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ The `NetRCAuth()` class uses [the `netrc.netrc()` function from the Python stand
504504

505505
## HTTP Proxying
506506

507-
HTTPX supports setting up [HTTP proxies](https://en.wikipedia.org/wiki/Proxy_server#Web_proxy_servers) via the `proxies` parameter to be passed on client initialization or top-level API functions like `httpx.get(..., proxies=...)`.
507+
HTTPX supports setting up [HTTP proxies](https://en.wikipedia.org/wiki/Proxy_server#Web_proxy_servers) via the `proxy` parameter to be passed on client initialization or top-level API functions like `httpx.get(..., proxy=...)`.
508508

509509
<div align="center">
510510
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/Open_proxy_h2g2bob.svg/480px-Open_proxy_h2g2bob.svg.png"/>
@@ -516,19 +516,19 @@ HTTPX supports setting up [HTTP proxies](https://en.wikipedia.org/wiki/Proxy_ser
516516
To route all traffic (HTTP and HTTPS) to a proxy located at `http://localhost:8030`, pass the proxy URL to the client...
517517

518518
```python
519-
with httpx.Client(proxies="http://localhost:8030") as client:
519+
with httpx.Client(proxy="http://localhost:8030") as client:
520520
...
521521
```
522522

523-
For more advanced use cases, pass a proxies `dict`. For example, to route HTTP and HTTPS requests to 2 different proxies, respectively located at `http://localhost:8030`, and `http://localhost:8031`, pass a `dict` of proxy URLs:
523+
For more advanced use cases, pass a mounts `dict`. For example, to route HTTP and HTTPS requests to 2 different proxies, respectively located at `http://localhost:8030`, and `http://localhost:8031`, pass a `dict` of proxy URLs:
524524

525525
```python
526-
proxies = {
527-
"http://": "http://localhost:8030",
528-
"https://": "http://localhost:8031",
526+
proxy_mounts = {
527+
"http://": httpx.HTTPTransport(proxy="http://localhost:8030"),
528+
"https://": httpx.HTTPTransport(proxy="http://localhost:8031"),
529529
}
530530

531-
with httpx.Client(proxies=proxies) as client:
531+
with httpx.Client(mounts=proxy_mounts) as client:
532532
...
533533
```
534534

@@ -546,132 +546,10 @@ For detailed information about proxy routing, see the [Routing](#routing) sectio
546546
Proxy credentials can be passed as the `userinfo` section of the proxy URL. For example:
547547

548548
```python
549-
proxies = {
550-
"http://": "http://username:password@localhost:8030",
551-
# ...
552-
}
553-
```
554-
555-
### Routing
556-
557-
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.
558-
559-
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://`).
560-
561-
HTTPX supports routing proxies based on **scheme**, **domain**, **port**, or a combination of these.
562-
563-
#### Wildcard routing
564-
565-
Route everything through a proxy...
566-
567-
```python
568-
proxies = {
569-
"all://": "http://localhost:8030",
570-
}
571-
```
572-
573-
#### Scheme routing
574-
575-
Route HTTP requests through one proxy, and HTTPS requests through another...
576-
577-
```python
578-
proxies = {
579-
"http://": "http://localhost:8030",
580-
"https://": "http://localhost:8031",
581-
}
582-
```
583-
584-
#### Domain routing
585-
586-
Proxy all requests on domain "example.com", let other requests pass through...
587-
588-
```python
589-
proxies = {
590-
"all://example.com": "http://localhost:8030",
591-
}
592-
```
593-
594-
Proxy HTTP requests on domain "example.com", let HTTPS and other requests pass through...
595-
596-
```python
597-
proxies = {
598-
"http://example.com": "http://localhost:8030",
599-
}
600-
```
601-
602-
Proxy all requests to "example.com" and its subdomains, let other requests pass through...
603-
604-
```python
605-
proxies = {
606-
"all://*example.com": "http://localhost:8030",
607-
}
608-
```
609-
610-
Proxy all requests to strict subdomains of "example.com", let "example.com" and other requests pass through...
611-
612-
```python
613-
proxies = {
614-
"all://*.example.com": "http://localhost:8030",
615-
}
616-
```
617-
618-
#### Port routing
619-
620-
Proxy HTTPS requests on port 1234 to "example.com"...
621-
622-
```python
623-
proxies = {
624-
"https://example.com:1234": "http://localhost:8030",
625-
}
626-
```
627-
628-
Proxy all requests on port 1234...
629-
630-
```python
631-
proxies = {
632-
"all://*:1234": "http://localhost:8030",
633-
}
634-
```
635-
636-
#### No-proxy support
637-
638-
It is also possible to define requests that _shouldn't_ be routed through proxies.
639-
640-
To do so, pass `None` as the proxy URL. For example...
641-
642-
```python
643-
proxies = {
644-
# Route requests through a proxy by default...
645-
"all://": "http://localhost:8031",
646-
# Except those for "example.com".
647-
"all://example.com": None,
648-
}
649-
```
650-
651-
#### Complex configuration example
652-
653-
You can combine the routing features outlined above to build complex proxy routing configurations. For example...
654-
655-
```python
656-
proxies = {
657-
# Route all traffic through a proxy by default...
658-
"all://": "http://localhost:8030",
659-
# But don't use proxies for HTTPS requests to "domain.io"...
660-
"https://domain.io": None,
661-
# And use another proxy for requests to "example.com" and its subdomains...
662-
"all://*example.com": "http://localhost:8031",
663-
# And yet another proxy if HTTP is used,
664-
# and the "internal" subdomain on port 5550 is requested...
665-
"http://internal.example.com:5550": "http://localhost:8032",
666-
}
549+
with httpx.Client(proxy="http://username:password@localhost:8030") as client:
550+
...
667551
```
668552

669-
#### Environment variables
670-
671-
HTTP proxying can also be configured through environment variables, although with less fine-grained control.
672-
673-
See documentation on [`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`](environment_variables.md#http_proxy-https_proxy-all_proxy) for more information.
674-
675553
### Proxy mechanisms
676554

677555
!!! note
@@ -707,7 +585,7 @@ $ pip install httpx[socks]
707585
You can now configure a client to make requests via a proxy using the SOCKS protocol:
708586

709587
```python
710-
httpx.Client(proxies='socks5://user:pass@host:port')
588+
httpx.Client(proxy='socks5://user:pass@host:port')
711589
```
712590

713591
## Timeout Configuration
@@ -1294,3 +1172,125 @@ Adding support for custom schemes:
12941172
mounts = {"file://": FileSystemTransport()}
12951173
client = httpx.Client(mounts=mounts)
12961174
```
1175+
1176+
### Routing
1177+
1178+
HTTPX provides a powerful mechanism for routing requests, allowing you to write complex rules that specify which transport should be used for each request.
1179+
1180+
The `mounts` dictionary maps URL patterns to HTTP transports. HTTPX matches requested URLs against URL patterns to decide which transport should be used, if any. Matching is done from most specific URL patterns (e.g. `https://<domain>:<port>`) to least specific ones (e.g. `https://`).
1181+
1182+
HTTPX supports routing requests based on **scheme**, **domain**, **port**, or a combination of these.
1183+
1184+
#### Wildcard routing
1185+
1186+
Route everything through a transport...
1187+
1188+
```python
1189+
mounts = {
1190+
"all://": httpx.HTTPTransport(proxy="http://localhost:8030"),
1191+
}
1192+
```
1193+
1194+
#### Scheme routing
1195+
1196+
Route HTTP requests through one transport, and HTTPS requests through another...
1197+
1198+
```python
1199+
mounts = {
1200+
"http://": httpx.HTTPTransport(proxy="http://localhost:8030"),
1201+
"https://": httpx.HTTPTransport(proxy="http://localhost:8031"),
1202+
}
1203+
```
1204+
1205+
#### Domain routing
1206+
1207+
Proxy all requests on domain "example.com", let other requests pass through...
1208+
1209+
```python
1210+
mounts = {
1211+
"all://example.com": httpx.HTTPTransport(proxy="http://localhost:8030"),
1212+
}
1213+
```
1214+
1215+
Proxy HTTP requests on domain "example.com", let HTTPS and other requests pass through...
1216+
1217+
```python
1218+
mounts = {
1219+
"http://example.com": httpx.HTTPTransport(proxy="http://localhost:8030"),
1220+
}
1221+
```
1222+
1223+
Proxy all requests to "example.com" and its subdomains, let other requests pass through...
1224+
1225+
```python
1226+
mounts = {
1227+
"all://*example.com": httpx.HTTPTransport(proxy="http://localhost:8030"),
1228+
}
1229+
```
1230+
1231+
Proxy all requests to strict subdomains of "example.com", let "example.com" and other requests pass through...
1232+
1233+
```python
1234+
mounts = {
1235+
"all://*.example.com": httpx.HTTPTransport(proxy="http://localhost:8030"),
1236+
}
1237+
```
1238+
1239+
#### Port routing
1240+
1241+
Proxy HTTPS requests on port 1234 to "example.com"...
1242+
1243+
```python
1244+
mounts = {
1245+
"https://example.com:1234": httpx.HTTPTransport(proxy="http://localhost:8030"),
1246+
}
1247+
```
1248+
1249+
Proxy all requests on port 1234...
1250+
1251+
```python
1252+
mounts = {
1253+
"all://*:1234": httpx.HTTPTransport(proxy="http://localhost:8030"),
1254+
}
1255+
```
1256+
1257+
#### No-proxy support
1258+
1259+
It is also possible to define requests that _shouldn't_ be routed through the transport.
1260+
1261+
To do so, pass `None` as the proxy URL. For example...
1262+
1263+
```python
1264+
mounts = {
1265+
# Route requests through a proxy by default...
1266+
"all://": httpx.HTTPTransport(proxy="http://localhost:8031"),
1267+
# Except those for "example.com".
1268+
"all://example.com": None,
1269+
}
1270+
```
1271+
1272+
#### Complex configuration example
1273+
1274+
You can combine the routing features outlined above to build complex proxy routing configurations. For example...
1275+
1276+
```python
1277+
mounts = {
1278+
# Route all traffic through a proxy by default...
1279+
"all://": httpx.HTTPTransport(proxy="http://localhost:8030"),
1280+
# But don't use proxies for HTTPS requests to "domain.io"...
1281+
"https://domain.io": None,
1282+
# And use another proxy for requests to "example.com" and its subdomains...
1283+
"all://*example.com": httpx.HTTPTransport(proxy="http://localhost:8031"),
1284+
# And yet another proxy if HTTP is used,
1285+
# and the "internal" subdomain on port 5550 is requested...
1286+
"http://internal.example.com:5550": httpx.HTTPTransport(proxy="http://localhost:8032"),
1287+
}
1288+
```
1289+
1290+
#### Environment variables
1291+
1292+
There are also environment variables that can be used to control the dictionary of the client mounts.
1293+
They can be used to configure HTTP proxying for clients.
1294+
1295+
See documentation on [`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`](environment_variables.md#http_proxy-https_proxy-all_proxy) for more information.
1296+

docs/compatibility.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,17 @@ httpx.get('https://www.example.com', timeout=None)
157157

158158
## Proxy keys
159159

160-
When using `httpx.Client(proxies={...})` to map to a selection of different proxies, we use full URL schemes, such as `proxies={"http://": ..., "https://": ...}`.
160+
HTTPX uses the mounts argument for HTTP proxying and transport routing.
161+
It can do much more than proxies and allows you to configure more than just the proxy route.
162+
For more detailed documentation, see [Mounting Transports](advanced.md#mounting-transports).
163+
164+
When using `httpx.Client(mounts={...})` to map to a selection of different transports, we use full URL schemes, such as `mounts={"http://": ..., "https://": ...}`.
161165

162166
This is different to the `requests` usage of `proxies={"http": ..., "https": ...}`.
163167

164-
This change is for better consistency with more complex mappings, that might also include domain names, such as `proxies={"all://": ..., "all://www.example.com": None}` which maps all requests onto a proxy, except for requests to "www.example.com" which have an explicit exclusion.
168+
This change is for better consistency with more complex mappings, that might also include domain names, such as `mounts={"all://": ..., httpx.HTTPTransport(proxy="all://www.example.com": None})` which maps all requests onto a proxy, except for requests to "www.example.com" which have an explicit exclusion.
165169

166-
Also note that `requests.Session.request(...)` allows a `proxies=...` parameter, whereas `httpx.Client.request(...)` does not.
170+
Also note that `requests.Session.request(...)` allows a `proxies=...` parameter, whereas `httpx.Client.request(...)` does not allow `mounts=...`.
167171

168172
## SSL configuration
169173

@@ -195,7 +199,7 @@ We don't support `response.is_ok` since the naming is ambiguous there, and might
195199

196200
There is no notion of [prepared requests](https://requests.readthedocs.io/en/stable/user/advanced/#prepared-requests) in HTTPX. If you need to customize request instantiation, see [Request instances](advanced.md#request-instances).
197201

198-
Besides, `httpx.Request()` does not support the `auth`, `timeout`, `follow_redirects`, `proxies`, `verify` and `cert` parameters. However these are available in `httpx.request`, `httpx.get`, `httpx.post` etc., as well as on [`Client` instances](advanced.md#client-instances).
202+
Besides, `httpx.Request()` does not support the `auth`, `timeout`, `follow_redirects`, `mounts`, `verify` and `cert` parameters. However these are available in `httpx.request`, `httpx.get`, `httpx.post` etc., as well as on [`Client` instances](advanced.md#client-instances).
199203

200204
## Mocking
201205

docs/contributing.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,7 @@ this is where our previously generated `client.pem` comes in:
213213
```
214214
import httpx
215215
216-
proxies = {"all://": "http://127.0.0.1:8080/"}
217-
218-
with httpx.Client(proxies=proxies, verify="/path/to/client.pem") as client:
216+
with httpx.Client(proxy="http://127.0.0.1:8080/", verify="/path/to/client.pem") as client:
219217
response = client.get("https://example.org")
220218
print(response.status_code) # should print 200
221219
```

docs/troubleshooting.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ httpx.ProxyError: _ssl.c:1091: The handshake operation timed out
1919
**Resolution**: it is likely that you've set up your proxies like this...
2020

2121
```python
22-
proxies = {
23-
"http://": "http://myproxy.org",
24-
"https://": "https://myproxy.org",
22+
mounts = {
23+
"http://": httpx.HTTPTransport(proxy="http://myproxy.org"),
24+
"https://": httpx.HTTPTransport(proxy="https://myproxy.org"),
2525
}
2626
```
2727

@@ -32,16 +32,18 @@ But if you get the error above, it is likely that your proxy doesn't support con
3232
Change the scheme of your HTTPS proxy to `http://...` instead of `https://...`:
3333

3434
```python
35-
proxies = {
36-
"http://": "http://myproxy.org",
37-
"https://": "http://myproxy.org",
35+
mounts = {
36+
"http://": httpx.HTTPTransport(proxy="http://myproxy.org"),
37+
"https://": httpx.HTTPTransport(proxy="http://myproxy.org"),
3838
}
3939
```
4040

4141
This can be simplified to:
4242

4343
```python
44-
proxies = "http://myproxy.org"
44+
proxy = "http://myproxy.org"
45+
with httpx.Client(proxy=proxy) as client:
46+
...
4547
```
4648

4749
For more information, see [Proxies: FORWARD vs TUNNEL](advanced.md#forward-vs-tunnel).

0 commit comments

Comments
 (0)