Skip to content

Commit e8c5252

Browse files
Fix domain matching being lower priority than path matching (#11673)
1 parent 1590c86 commit e8c5252

File tree

4 files changed

+26
-16
lines changed

4 files changed

+26
-16
lines changed

CHANGES/11673.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed routing to a sub-application added via ``.add_domain()`` not working
2+
if the same path exists on the parent app. -- by :user:`Dreamsorcerer`.

aiohttp/web_urldispatcher.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,21 @@ async def resolve(self, request: Request) -> UrlMappingMatchInfo:
977977
resource_index = self._resource_index
978978
allowed_methods: set[str] = set()
979979

980+
# MatchedSubAppResource is primarily used to match on domain names
981+
# (though custom rules could match on other things). This means that
982+
# the traversal algorithm below can't be applied, and that we likely
983+
# need to check these first so a sub app that defines the same path
984+
# as a parent app will get priority if there's a domain match.
985+
#
986+
# For most cases we do not expect there to be many of these since
987+
# currently they are only added by `.add_domain()`.
988+
for resource in self._matched_sub_app_resources:
989+
match_dict, allowed = await resource.resolve(request)
990+
if match_dict is not None:
991+
return match_dict
992+
else:
993+
allowed_methods |= allowed
994+
980995
# Walk the url parts looking for candidates. We walk the url backwards
981996
# to ensure the most explicit match is found first. If there are multiple
982997
# candidates for a given url part because there are multiple resources
@@ -994,21 +1009,6 @@ async def resolve(self, request: Request) -> UrlMappingMatchInfo:
9941009
break
9951010
url_part = url_part.rpartition("/")[0] or "/"
9961011

997-
#
998-
# We didn't find any candidates, so we'll try the matched sub-app
999-
# resources which we have to walk in a linear fashion because they
1000-
# have regex/wildcard match rules and we cannot index them.
1001-
#
1002-
# For most cases we do not expect there to be many of these since
1003-
# currently they are only added by `add_domain`
1004-
#
1005-
for resource in self._matched_sub_app_resources:
1006-
match_dict, allowed = await resource.resolve(request)
1007-
if match_dict is not None:
1008-
return match_dict
1009-
else:
1010-
allowed_methods |= allowed
1011-
10121012
if allowed_methods:
10131013
return MatchInfoError(HTTPMethodNotAllowed(request.method, allowed_methods))
10141014

docs/web_reference.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,14 @@ Application and Router
15391539
matches the pattern *domain* then
15401540
further resolving is passed to *subapp*.
15411541

1542+
.. warning::
1543+
1544+
Registering many domains using this method may cause performance
1545+
issues with handler routing. If you have a substantial number of
1546+
applications for different domains, you may want to consider
1547+
using a reverse proxy (such as Nginx) to handle routing to
1548+
different apps, rather that registering them as sub-applications.
1549+
15421550
:param str domain: domain or mask of domain for the resource.
15431551

15441552
:param Application subapp: nested application.

tests/test_web_urldispatcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,8 +951,8 @@ async def get(self) -> web.Response:
951951
assert r.status == 200
952952

953953

954-
@pytest.mark.xfail(reason="https://github.com/aio-libs/aiohttp/issues/11665")
955954
async def test_subapp_domain_routing_same_path(aiohttp_client: AiohttpClient) -> None:
955+
"""Regression test for #11665."""
956956
app = web.Application()
957957
sub_app = web.Application()
958958

0 commit comments

Comments
 (0)