Skip to content

Commit 82c26f2

Browse files
authored
Fixed URLRouter root_path handling. (#1954)
* Add tests for handling root_path in URLRouting * Handle root_path in URLRouter If we have a scope["root_path"], raise if it does not prefix scope["path"], and strip it from scope["path"] if it does. Do this only if we're in an outermost URLRouter. Signed-off-by: Alejandro R. Sedeño <[email protected]> Signed-off-by: Alejandro R Sedeño <[email protected]>
1 parent ecbf353 commit 82c26f2

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

channels/routing.py

+9
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ async def __call__(self, scope, receive, send):
107107
path = scope.get("path_remaining", scope.get("path", None))
108108
if path is None:
109109
raise ValueError("No 'path' key in connection scope, cannot route URLs")
110+
111+
if "path_remaining" not in scope:
112+
# We are the outermost URLRouter, so handle root_path if present.
113+
root_path = scope.get("root_path", "")
114+
if root_path and not path.startswith(root_path):
115+
# If root_path is present, path must start with it.
116+
raise ValueError("No route found for path %r." % path)
117+
path = path[len(root_path) :]
118+
110119
# Remove leading / to match Django's handling
111120
path = path.lstrip("/")
112121
# Run through the routes we have until one matches

tests/test_routing.py

+40
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ async def test_url_router():
107107
"args": tuple(),
108108
"kwargs": {"default": 42},
109109
}
110+
# Valid root_path in scope
111+
assert (
112+
await router(
113+
{"type": "http", "path": "/root/", "root_path": "/root"}, None, None
114+
)
115+
== 1
116+
)
117+
assert (
118+
await router(
119+
{"type": "http", "path": "/root/foo/", "root_path": "/root"}, None, None
120+
)
121+
== 2
122+
)
123+
124+
# Unmatched root_path in scope
125+
with pytest.raises(ValueError):
126+
await router({"type": "http", "path": "/", "root_path": "/root"}, None, None)
110127

111128
# Invalid matches
112129
with pytest.raises(ValueError):
@@ -261,6 +278,29 @@ async def test_path_remaining():
261278
== 2
262279
)
263280

281+
assert (
282+
await outermost_router(
283+
{"type": "http", "path": "/root/prefix/stuff/", "root_path": "/root"},
284+
None,
285+
None,
286+
)
287+
== 2
288+
)
289+
290+
with pytest.raises(ValueError):
291+
await outermost_router(
292+
{"type": "http", "path": "/root/root/prefix/stuff/", "root_path": "/root"},
293+
None,
294+
None,
295+
)
296+
297+
with pytest.raises(ValueError):
298+
await outermost_router(
299+
{"type": "http", "path": "/root/prefix/root/stuff/", "root_path": "/root"},
300+
None,
301+
None,
302+
)
303+
264304

265305
def test_invalid_routes():
266306
"""

0 commit comments

Comments
 (0)