From 7c7ec5a7f72de360bafa938d14e2e1d6f4b6cb69 Mon Sep 17 00:00:00 2001 From: Eugene Mayer Date: Thu, 25 Nov 2021 17:11:25 +0300 Subject: [PATCH] Remove port from Host routing regex (#1322) Co-authored-by: Amin Alaee Co-authored-by: Marcelo Trylesinski --- docs/routing.md | 7 ++++--- starlette/routing.py | 2 +- tests/test_routing.py | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/docs/routing.md b/docs/routing.md index a0606ef4c..f19c57b70 100644 --- a/docs/routing.md +++ b/docs/routing.md @@ -183,9 +183,10 @@ url = app.url_path_for("user_detail", username=...) If you want to use different routes for the same path based on the `Host` header. Note that port is removed from the `Host` header when matching. -For example, `Host (host='example.org:3600', ...)` will not be processed -even if the `Host` header is `example.org:3600`. -Therefore, specify only the domain or IP address +For example, `Host (host='example.org:3600', ...)` will be processed +even if the `Host` header contains or does not contain a port other than `3600` +(`example.org:5600`, `example.org`). +Therefore, you can specify the port if you need it for use in `url_for`. There are several ways to connect host-based routes to your application diff --git a/starlette/routing.py b/starlette/routing.py index 9a1a5e12d..f9474b4a1 100644 --- a/starlette/routing.py +++ b/starlette/routing.py @@ -146,7 +146,7 @@ def compile_path( ending = "s" if len(duplicated_params) > 1 else "" raise ValueError(f"Duplicated param name{ending} {names} at path {path}") - path_regex += re.escape(path[idx:]) + "$" + path_regex += re.escape(path[idx:].split(":")[0]) + "$" path_format += path[idx:] return re.compile(path_regex), path_format, param_convertors diff --git a/tests/test_routing.py b/tests/test_routing.py index 9e734b9cc..e1374cc5d 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -352,6 +352,11 @@ def users_api(request): name="api", app=Router([Route("/users", users_api, name="users")]), ), + Host( + "port.example.org:3600", + name="port", + app=Router([Route("/", homepage, name="homepage")]), + ), ] ) @@ -375,6 +380,21 @@ def test_host_routing(test_client_factory): response = client.get("/") assert response.status_code == 200 + client = test_client_factory(mixed_hosts_app, base_url="https://port.example.org/") + + response = client.get("/users") + assert response.status_code == 404 + + response = client.get("/") + assert response.status_code == 200 + + client = test_client_factory( + mixed_hosts_app, base_url="https://port.example.org:5600/" + ) + + response = client.get("/") + assert response.status_code == 200 + def test_host_reverse_urls(): assert ( @@ -389,6 +409,12 @@ def test_host_reverse_urls(): mixed_hosts_app.url_path_for("api:users").make_absolute_url("https://whatever") == "https://api.example.org/users" ) + assert ( + mixed_hosts_app.url_path_for("port:homepage").make_absolute_url( + "https://whatever" + ) + == "https://port.example.org:3600/" + ) async def subdomain_app(scope, receive, send):