Skip to content

Commit f19d920

Browse files
[PR #8566/f3a1afc5 backport][3.10] Fix url dispatcher index when variable is preceded by a fixed string after a slash (#8578)
Co-authored-by: J. Nick Koston <[email protected]> fix for a regression in 3.10.x. Regressed in #7829 fixes #8567
1 parent 6dff116 commit f19d920

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
@@ -1131,8 +1131,14 @@ def register_resource(self, resource: AbstractResource) -> None:
11311131

11321132
def _get_resource_index_key(self, resource: AbstractResource) -> str:
11331133
"""Return a key to index the resource in the resource index."""
1134-
# strip at the first { to allow for variables
1135-
return resource.canonical.partition("{")[0].rstrip("/") or "/"
1134+
if "{" in (index_key := resource.canonical):
1135+
# strip at the first { to allow for variables, and than
1136+
# rpartition at / to allow for variable parts in the path
1137+
# For example if the canonical path is `/core/locations{tail:.*}`
1138+
# the index key will be `/core` since index is based on the
1139+
# url parts split by `/`
1140+
index_key = index_key.partition("{")[0].rpartition("/")[0]
1141+
return index_key.rstrip("/") or "/"
11361142

11371143
def index_resource(self, resource: AbstractResource) -> None:
11381144
"""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
@@ -937,3 +937,27 @@ async def get(self) -> web.Response:
937937
r = await client.get("///a")
938938
assert r.status == 200
939939
await r.release()
940+
941+
942+
async def test_route_with_regex(aiohttp_client: AiohttpClient) -> None:
943+
"""Test a route with a regex preceded by a fixed string."""
944+
app = web.Application()
945+
946+
async def handler(request: web.Request) -> web.Response:
947+
assert isinstance(request.match_info._route.resource, Resource)
948+
return web.Response(text=request.match_info._route.resource.canonical)
949+
950+
app.router.add_get("/core/locations{tail:.*}", handler)
951+
client = await aiohttp_client(app)
952+
953+
r = await client.get("/core/locations/tail/here")
954+
assert r.status == 200
955+
assert await r.text() == "/core/locations{tail}"
956+
957+
r = await client.get("/core/locations_tail_here")
958+
assert r.status == 200
959+
assert await r.text() == "/core/locations{tail}"
960+
961+
r = await client.get("/core/locations_tail;id=abcdef")
962+
assert r.status == 200
963+
assert await r.text() == "/core/locations{tail}"

0 commit comments

Comments
 (0)