From 1131b3cbcd6f9e2aa3500fd4d7bf3cd200fa2532 Mon Sep 17 00:00:00 2001 From: Gabriel Figueiredo <53541827+gabriel-f-santos@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:12:43 -0300 Subject: [PATCH] Ensure accurate `root_path` removal in `get_route_path` function (#2600) * fix: regex inside function get_route_path to remove root_path * fix: apply format ruff * fix: mypy --------- Co-authored-by: Marcelo Trylesinski --- starlette/_utils.py | 2 +- tests/test__utils.py | 17 ++++++++++++++++- tests/test_routing.py | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/starlette/_utils.py b/starlette/_utils.py index 90bd346fd..f615eeea4 100644 --- a/starlette/_utils.py +++ b/starlette/_utils.py @@ -85,5 +85,5 @@ def collapse_excgroups() -> typing.Generator[None, None, None]: def get_route_path(scope: Scope) -> str: root_path = scope.get("root_path", "") - route_path = re.sub(r"^" + root_path, "", scope["path"]) + route_path = re.sub(r"^" + root_path + r"(?=/|$)", "", scope["path"]) return route_path diff --git a/tests/test__utils.py b/tests/test__utils.py index 2ecf47483..f46775b4b 100644 --- a/tests/test__utils.py +++ b/tests/test__utils.py @@ -1,7 +1,10 @@ import functools from typing import Any -from starlette._utils import is_async_callable +import pytest + +from starlette._utils import get_route_path, is_async_callable +from starlette.types import Scope def test_async_func() -> None: @@ -78,3 +81,15 @@ async def async_func( partial = functools.partial(async_func, b=2) nested_partial = functools.partial(partial, a=1) assert is_async_callable(nested_partial) + + +@pytest.mark.parametrize( + "scope, expected_result", + [ + ({"path": "/foo-123/bar", "root_path": "/foo"}, "/foo-123/bar"), + ({"path": "/foo/bar", "root_path": "/foo"}, "/bar"), + ({"path": "/foo", "root_path": "/foo"}, ""), + ], +) +def test_get_route_path(scope: Scope, expected_result: str) -> None: + assert get_route_path(scope) == expected_result diff --git a/tests/test_routing.py b/tests/test_routing.py index 9fa44def4..6bb398ba5 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -1221,6 +1221,12 @@ async def pure_asgi_echo_paths(scope: Scope, receive: Receive, send: Send, name: name="path", methods=["GET"], ), + Route( + "/root-queue/path", + functools.partial(echo_paths, name="queue_path"), + name="queue_path", + methods=["POST"], + ), Mount("/asgipath", app=functools.partial(pure_asgi_echo_paths, name="asgipath")), Mount( "/sub", @@ -1266,3 +1272,11 @@ def test_paths_with_root_path(test_client_factory: TestClientFactory) -> None: "path": "/root/sub/path", "root_path": "/root/sub", } + + response = client.post("/root/root-queue/path") + assert response.status_code == 200 + assert response.json() == { + "name": "queue_path", + "path": "/root/root-queue/path", + "root_path": "/root", + }