Skip to content

Commit a54317c

Browse files
authored
fix(asgi.Request): handle scope['client'] being None (#2584)
1 parent bc01a2b commit a54317c

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Due to the differences in interpretation of the ASGI specification, Uvicorn
2+
could set `client` in the HTTP connection scope in a way that broke
3+
:meth:`req.access_route <falcon.asgi.Request.access_route>` and
4+
:meth:`req.remote_addr <falcon.asgi.Request.remote_addr>` when the app server
5+
was bound to a Unix domain socket.
6+
7+
This discrepancy was addressed, and Falcon should now fall back to the same
8+
default value (``'127.0.0.1'``) in this case as if `client` was missing
9+
altogether.

falcon/asgi/request.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,12 @@ def access_route(self) -> list[str]:
489489
# effectively what we are doing since we only ever
490490
# access this field when setting self._cached_access_route
491491
client, __ = self.scope['client']
492-
except KeyError:
492+
# NOTE(vytas): Uvicorn may explicitly set scope['client'] to None.
493+
# According to the spec, it does default to None when missing,
494+
# but it is unclear whether it can be explicitly set to None, or
495+
# it must be a valid iterable when present. In any case, we
496+
# simply catch TypeError here too to account for this scenario.
497+
except (KeyError, TypeError):
493498
# NOTE(kgriffs): Default to localhost so that app logic does
494499
# note have to special-case the handling of a missing
495500
# client field in the connection scope. This should be

tests/asgi/test_request_asgi.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22

33
from falcon import testing
4+
from falcon.asgi import Request
45

56

67
def test_missing_server_in_scope():
@@ -9,6 +10,18 @@ def test_missing_server_in_scope():
910
assert req.port == 80
1011

1112

13+
def test_client_none_in_scope():
14+
# Regression test for #2583
15+
16+
async def recv():
17+
pass
18+
19+
scope = testing.create_scope()
20+
scope['client'] = None
21+
req = Request(scope, recv)
22+
assert req.remote_addr == '127.0.0.1'
23+
24+
1225
def test_log_error_not_supported():
1326
req = testing.create_asgi_req()
1427
with pytest.raises(NotImplementedError):

0 commit comments

Comments
 (0)