Repository navigation
feat: restrict routes to hosts with hosts= - #12
Merged
Merged
Conversation
Add a hosts= option to routes, mirroring methods=, and an optional host parameter when matching. A route without hosts matches every host, so existing code is unaffected. A route with hosts only matches the hosts it lists, and is skipped as if its path hadn't matched otherwise, so a route that doesn't exist on the given host raises NotFoundError. hosts is normalized to a set, so a bare string is never matched as a substring, and hosts are compared verbatim: callers strip the port and lowercase the host before passing it. Mounted routers accept hosts= too, and receive the host to match their own routes. hosts becomes a reserved option in route()/bind(), so it's no longer forwarded to the target like other extra keyword arguments. Closes klen#11
klen
approved these changes
Oct 19, 2026
Owner
There was a problem hiding this comment.
Approved. Checked it locally: builds clean (the str host=* in the pxd lines up with host: str | None), 78 tests pass compiled and pure, mypy/ruff clean.
Covers everything from #11: narrow hosts= form (no when=), reuses NotFoundError, hosts normalized to a set in bind()/__route__(), verbatim comparison documented, reserved hosts documented. Folding host into path (host mismatch → path=False) is fine, and skipping a separate host flag on RouteMatch was the right call.
DRY the methods/hosts normalization shared by bind() and __route__().
Owner
|
Merged — thanks again for the PR, the benchmarks and the care with the review follow-ups! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #11.
Adds a
hosts=option to routes, mirroringmethods=, and an optionalhostparameter when matching:Details
hostis an optional third parameter of__call__andmatch, so it's part ofmatch()'slru_cachekey. A route withhostsdoesn't match when nohostis passed, and routes withouthostsmatch any host, so existing code is unaffected.hosts=too, checked before delegating, like the mount'smethods, andMount.matchpasses the host down so routes inside a mounted router can be restricted by host as well. Without this,__route__'s**__would silently swallowhosts=on a mount.hosts, so positional calls likeRoute(path, methods, target)keep working. The.pxddeclares the new attribute andcpdef RouteMatch match(self, str path, str method, str host=*).tests/test_hosts.pycovers matching and skipping, several hosts, verbatim comparison, falling through to later routes,NotFoundErrorvs.InvalidMethodError, positionalhost, caching per host, the reserved option,bind(), method shortcuts and mounts.test_parity.pygained host cases, which pass against the compiled build.Benchmark
test_benchmark(which registers no host-restricted routes), alternatingdevelopand this branch 5× each, Apple M3, Python 3.13.16, Cython 3.3.0:developmedian (range)That's about +1.5% in both builds, with overlapping ranges. The remaining cost is the extra
hostargument on each route match.Possible follow-up
A host mismatch is reported like a path mismatch (
path=False). An additionalhostflag onRouteMatch, next topathandmethod, would let callers ofmatch()tell "this path exists on another host" apart from "no such path", e.g. to log it or answer differently. It doesn't change any matching outcome and would make code more complex, so I left it out to keep this PR small. I'm happy to add it if you think it's useful.