Skip to content

Commit f3a1afc

Browse files
authored
Fix url dispatcher index when variable is preceded by a fixed string after a slash (#8566)
1 parent e48acaf commit f3a1afc

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

CHANGES/8566.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed url dispatcher index not matching when a variable is preceded by a fixed string after a slash -- by :user:`bdraco`.

aiohttp/web_urldispatcher.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,8 +1108,14 @@ def register_resource(self, resource: AbstractResource) -> None:
11081108

11091109
def _get_resource_index_key(self, resource: AbstractResource) -> str:
11101110
"""Return a key to index the resource in the resource index."""
1111-
# strip at the first { to allow for variables
1112-
return resource.canonical.partition("{")[0].rstrip("/") or "/"
1111+
if "{" in (index_key := resource.canonical):
1112+
# strip at the first { to allow for variables, and than
1113+
# rpartition at / to allow for variable parts in the path
1114+
# For example if the canonical path is `/core/locations{tail:.*}`
1115+
# the index key will be `/core` since index is based on the
1116+
# url parts split by `/`
1117+
index_key = index_key.partition("{")[0].rpartition("/")[0]
1118+
return index_key.rstrip("/") or "/"
11131119

11141120
def index_resource(self, resource: AbstractResource) -> None:
11151121
"""Add a resource to the resource index."""

tests/test_web_urldispatcher.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,3 +916,27 @@ async def get(self) -> web.Response:
916916
r = await client.get("///a")
917917
assert r.status == 200
918918
await r.release()
919+
920+
921+
async def test_route_with_regex(aiohttp_client: AiohttpClient) -> None:
922+
"""Test a route with a regex preceded by a fixed string."""
923+
app = web.Application()
924+
925+
async def handler(request: web.Request) -> web.Response:
926+
assert isinstance(request.match_info._route.resource, Resource)
927+
return web.Response(text=request.match_info._route.resource.canonical)
928+
929+
app.router.add_get("/core/locations{tail:.*}", handler)
930+
client = await aiohttp_client(app)
931+
932+
r = await client.get("/core/locations/tail/here")
933+
assert r.status == 200
934+
assert await r.text() == "/core/locations{tail}"
935+
936+
r = await client.get("/core/locations_tail_here")
937+
assert r.status == 200
938+
assert await r.text() == "/core/locations{tail}"
939+
940+
r = await client.get("/core/locations_tail;id=abcdef")
941+
assert r.status == 200
942+
assert await r.text() == "/core/locations{tail}"

0 commit comments

Comments
 (0)