Skip to content

Commit 7b314cf

Browse files
committed
Remove "better UDS handling"
1 parent 8d25920 commit 7b314cf

File tree

7 files changed

+7
-125
lines changed

7 files changed

+7
-125
lines changed

docs/deployment.md

-4
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,6 @@ Options:
9999
to the $FORWARDED_ALLOW_IPS environment
100100
variable if available, or '127.0.0.1'. The
101101
literal '*' means trust everything.
102-
--forwarded-trust-literals Trust all literals in proxy headers.
103-
Defaults to False. Useful when using
104-
multiple proxies with UNIX Domain Sockets
105-
for transport.
106102
--root-path TEXT Set the ASGI 'root_path' for applications
107103
submounted below a given URL path.
108104
--limit-concurrency INTEGER Maximum number of concurrent connections or

docs/index.md

-4
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,6 @@ Options:
169169
to the $FORWARDED_ALLOW_IPS environment
170170
variable if available, or '127.0.0.1'. The
171171
literal '*' means trust everything.
172-
--forwarded-trust-literals Trust all literals in proxy headers.
173-
Defaults to False. Useful when using
174-
multiple proxies with UNIX Domain Sockets
175-
for transport.
176172
--root-path TEXT Set the ASGI 'root_path' for applications
177173
submounted below a given URL path.
178174
--limit-concurrency INTEGER Maximum number of concurrent connections or

docs/settings.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,9 @@ Note that WSGI mode always disables WebSocket support, as it is not supported by
8888
## HTTP
8989

9090
* `--root-path <str>` - Set the ASGI `root_path` for applications submounted below a given URL path.
91-
* `--proxy-headers` / `--no-proxy-headers` - Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info. Defaults to enabled, but is restricted to only trusting
91+
* `--proxy-headers` / `--no-proxy-headers` - Enable/Disable X-Forwarded-Proto, X-Forwarded-For to populate remote address info. Defaults to enabled, but is restricted to only trusting
9292
connecting IPs in the `forwarded-allow-ips` configuration.
9393
* `--forwarded-allow-ips` <comma-separated-list> Comma separated list of IP Addresses, IP Networks, or literals (e.g. UNIX Socket path) to trust with proxy headers. Defaults to the `$FORWARDED_ALLOW_IPS` environment variable if available, or '127.0.0.1'. The literal `'*'` means trust everything.
94-
* `--forwarded-trust-literals` - Trust all literals in proxy headers. Defaults to False. Useful when using multiple proxies with UNIX Domain Sockets for transport.
9594
* `--server-header` / `--no-server-header` - Enable/Disable default `Server` header.
9695
* `--date-header` / `--no-date-header` - Enable/Disable default `Date` header.
9796

tests/middleware/test_proxy_headers.py

+1-64
Original file line numberDiff line numberDiff line change
@@ -36,50 +36,20 @@ async def default_app(
3636
await response(scope, receive, send)
3737

3838

39-
class UdsMiddleware:
40-
"""Middleware that mimics ProxyHeadersMiddleware but first sets client to `None`
41-
42-
Manually acts as if Uvicorn is running behind a UNIX Domain Socket
43-
"""
44-
45-
def __init__(self, *args, **kwargs) -> None:
46-
self.app = ProxyHeadersMiddleware(*args, **kwargs)
47-
return
48-
49-
async def __call__(
50-
self,
51-
scope: Scope,
52-
receive: ASGIReceiveCallable,
53-
send: ASGISendCallable,
54-
) -> None:
55-
if scope["type"] in ("http", "websocket"):
56-
scope["client"] = None # type: ignore
57-
return await self.app(scope, receive, send)
58-
59-
6039
def make_httpx_client(
6140
trusted_hosts: str | list[str],
6241
client: tuple[str, int] = ("127.0.0.1", 123),
63-
trust_none_client: bool = False,
64-
trust_all_literal_clients: bool = False,
65-
app_class: type = ProxyHeadersMiddleware,
6642
) -> httpx.AsyncClient:
6743
"""Create async client for use in test cases
6844
6945
Args:
7046
trusted_hosts: trusted_hosts for proxy middleware
7147
client: transport client to use
72-
trust_none_client: trust_none_client for proxy middleware
73-
trust_all_literal_clients: trust_all_literal_clients for proxy middleware
74-
app_class: ASGI app to use with transport.
75-
This is so that can use `UdsMiddleware`.
7648
"""
7749

7850
app = cast(
7951
httpx._transports.asgi._ASGIApp,
80-
app_class(
81-
default_app, trusted_hosts, trust_none_client, trust_all_literal_clients
82-
),
52+
ProxyHeadersMiddleware(default_app, trusted_hosts),
8353
)
8454
transport = httpx.ASGITransport(app=app, client=client)
8555
return httpx.AsyncClient(transport=transport, base_url="http://testserver")
@@ -391,25 +361,6 @@ def test_forwarded_hosts(
391361
assert (test_host in trusted_hosts) is expected
392362

393363

394-
@pytest.mark.parametrize(
395-
("test_host", "expected"),
396-
[
397-
("127.0.0.1", True),
398-
("192.168.0.1", False),
399-
("::1", True),
400-
("ff::1", False),
401-
("some-literal", True),
402-
("1.2.34.5.6.7", True), # invalid ipv4
403-
(":::1", True), # invalip ipv6
404-
("unix:", True),
405-
("", False), # empty string is not literal
406-
],
407-
)
408-
def test_forwarded_hosts_trust_literals(test_host: str, expected: bool) -> None:
409-
trusted_hosts = _TrustedHosts("127.0.0.1, ::1, some-literal", True)
410-
assert (test_host in trusted_hosts) is expected
411-
412-
413364
@pytest.mark.anyio
414365
@pytest.mark.parametrize(
415366
("trusted_hosts", "expected"),
@@ -517,20 +468,6 @@ async def websocket_app(scope, receive, send):
517468
assert data == "wss://1.2.3.4:0"
518469

519470

520-
@pytest.mark.anyio
521-
@pytest.mark.parametrize(
522-
("trust_none_client", "expected"),
523-
[(False, "http://NONE"), (True, "https://1.2.3.4:0")],
524-
)
525-
async def test_proxy_headers_uds(trust_none_client: bool, expected: str) -> None:
526-
async with make_httpx_client(
527-
"10.0.0.0/8", trust_none_client=trust_none_client, app_class=UdsMiddleware
528-
) as client:
529-
response = await client.get("/", headers=make_x_headers("1.2.3.4, 10.1.1.1"))
530-
assert response.status_code == 200
531-
assert response.text == expected
532-
533-
534471
@pytest.mark.anyio
535472
async def test_proxy_headers_empty_x_forwarded_for() -> None:
536473
# fallback to the default behavior if x-forwarded-for is an empty list

uvicorn/config.py

-5
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,6 @@ def __init__(
208208
server_header: bool = True,
209209
date_header: bool = True,
210210
forwarded_allow_ips: list[str] | str | None = None,
211-
forwarded_trust_literals: bool = False,
212211
root_path: str = "",
213212
limit_concurrency: int | None = None,
214213
limit_max_requests: int | None = None,
@@ -350,8 +349,6 @@ def __init__(
350349
else:
351350
self.forwarded_allow_ips = forwarded_allow_ips
352351

353-
self.forwarded_trust_literals = forwarded_trust_literals
354-
355352
if self.reload and self.workers > 1:
356353
logger.warning('"workers" flag is ignored when reloading is enabled.')
357354

@@ -498,8 +495,6 @@ def load(self) -> None:
498495
self.loaded_app = ProxyHeadersMiddleware(
499496
self.loaded_app,
500497
trusted_hosts=self.forwarded_allow_ips,
501-
trust_none_client=bool(self.uds),
502-
trust_all_literal_clients=self.forwarded_trust_literals,
503498
)
504499

505500
self.loaded = True

uvicorn/main.py

-11
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,6 @@ def print_version(ctx: click.Context, param: click.Parameter, value: bool) -> No
250250
"$FORWARDED_ALLOW_IPS environment variable if available, or '127.0.0.1'. "
251251
"The literal '*' means trust everything.",
252252
)
253-
@click.option(
254-
"--forwarded-trust-literals",
255-
is_flag=True,
256-
default=False,
257-
help="Trust all literals in proxy headers. Defaults to False. Useful when using "
258-
"multiple proxies with UNIX Domain Sockets for transport.",
259-
)
260253
@click.option(
261254
"--root-path",
262255
type=str,
@@ -405,7 +398,6 @@ def main(
405398
server_header: bool,
406399
date_header: bool,
407400
forwarded_allow_ips: str,
408-
forwarded_trust_literals: bool,
409401
root_path: str,
410402
limit_concurrency: int,
411403
backlog: int,
@@ -455,7 +447,6 @@ def main(
455447
server_header=server_header,
456448
date_header=date_header,
457449
forwarded_allow_ips=forwarded_allow_ips,
458-
forwarded_trust_literals=forwarded_trust_literals,
459450
root_path=root_path,
460451
limit_concurrency=limit_concurrency,
461452
backlog=backlog,
@@ -508,7 +499,6 @@ def run(
508499
server_header: bool = True,
509500
date_header: bool = True,
510501
forwarded_allow_ips: list[str] | str | None = None,
511-
forwarded_trust_literals: bool = False,
512502
root_path: str = "",
513503
limit_concurrency: int | None = None,
514504
backlog: int = 2048,
@@ -561,7 +551,6 @@ def run(
561551
server_header=server_header,
562552
date_header=date_header,
563553
forwarded_allow_ips=forwarded_allow_ips,
564-
forwarded_trust_literals=forwarded_trust_literals,
565554
root_path=root_path,
566555
limit_concurrency=limit_concurrency,
567556
backlog=backlog,

uvicorn/middleware/proxy_headers.py

+5-35
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ class _TrustedHosts:
2121
def __init__(
2222
self,
2323
trusted_hosts: Union[List[str], str],
24-
trust_all_literal_clients: bool = False,
2524
) -> None:
2625
self.always_trust: bool = trusted_hosts == "*"
27-
self.trust_all_literal_clients = trust_all_literal_clients
2826

2927
self.trusted_literals: Set[str] = set()
3028
self.trusted_hosts: Set[ipaddress._BaseAddress] = set()
@@ -77,8 +75,6 @@ def __contains__(self, item: Optional[str]) -> bool:
7775
return any(ip in net for net in self.trusted_networks)
7876

7977
except ValueError:
80-
if self.trust_all_literal_clients:
81-
return True
8278
return item in self.trusted_literals
8379

8480
def get_trusted_client_host(self, x_forwarded_for: str) -> Optional[str]:
@@ -109,8 +105,8 @@ def __str__(self) -> str:
109105

110106
return (
111107
f"{self.__class__.__name__}({self.trusted_hosts=}, "
112-
f"{self.trusted_networks=}, {self.trusted_literals=}, "
113-
f"{self.trust_all_literal_clients=}"
108+
f"{self.trusted_networks=}, {self.trusted_literals=}"
109+
")"
114110
)
115111

116112

@@ -124,16 +120,6 @@ class ProxyHeadersMiddleware:
124120
Modifies the `client` and `scheme` information so that they reference
125121
the connecting client, rather that the connecting proxy.
126122
127-
Use `trust_none_client = True` to continue with proxy header handling when
128-
the initial client is `None`. This does not affect the handling of client
129-
adddresses in the proxy headers. If you are listening on a UNIX Domain Sockets
130-
you will need to set this to `True` to enable proxy handling.
131-
132-
Use `trust_all_literal_clients = True` to trust all non-IP clients in the header.
133-
This is useful if you are using UNIX Domain Sockets to communicate between your
134-
proxies and do not wish to list each literal or if you do not know the value of
135-
each literal and startup.
136-
137123
References:
138124
139125
- <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#Proxies>
@@ -144,13 +130,9 @@ def __init__(
144130
self,
145131
app: "ASGI3Application",
146132
trusted_hosts: Union[List[str], str] = "127.0.0.1",
147-
trust_none_client: bool = False,
148-
trust_all_literal_clients: bool = False,
149133
) -> None:
150134
self.app = app
151-
self.trusted_hosts = _TrustedHosts(trusted_hosts, trust_all_literal_clients)
152-
self.trust_none_client = trust_none_client
153-
print(self.trusted_hosts)
135+
self.trusted_hosts = _TrustedHosts(trusted_hosts)
154136
return
155137

156138
async def __call__(
@@ -159,20 +141,11 @@ async def __call__(
159141
if scope["type"] in ("http", "websocket"):
160142
scope = cast(Union[HTTPScope, WebSocketScope], scope)
161143
client_addr: Optional[Tuple[str, int]] = scope.get("client")
144+
client_host = client_addr[0] if client_addr else None
162145

163-
if (client_addr is None and self.trust_none_client) or (
164-
client_addr is not None and client_addr[0] in self.trusted_hosts
165-
):
146+
if client_host in self.trusted_hosts:
166147
headers = dict(scope["headers"])
167148

168-
# if b"forwarded" in headers:
169-
# ...
170-
# https://github.com/encode/uvicorn/discussions/2236
171-
# TODO: We should probably also support the Forwarded header:
172-
# https://datatracker.ietf.org/doc/html/rfc7239
173-
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded
174-
# If we do it should take precedence over the x-forwarded-* headers.
175-
176149
if b"x-forwarded-proto" in headers:
177150
# Determine if the incoming request was http or https based on
178151
# the X-Forwarded-Proto header.
@@ -204,8 +177,5 @@ async def __call__(
204177
# if b"x-forwarded-port" in headers:
205178
# ...
206179
# https://github.com/encode/uvicorn/issues/1974
207-
# TODO: Are we able to reliabily extract x-forwarded-port?
208-
# https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html#x-forwarded-port
209-
# If yes we should update the NGINX in docs/deployment.md
210180

211181
return await self.app(scope, receive, send)

0 commit comments

Comments
 (0)