Skip to content

Fix port issue on host-based routing #1322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 25, 2021
7 changes: 4 additions & 3 deletions docs/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion starlette/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions tests/test_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")]),
),
]
)

Expand All @@ -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 (
Expand All @@ -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):
Expand Down