-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
url matching order changed versus 2.2 #2924
Comments
@pgjones can you check this when you get a chance? |
99% This is a bug in the new matcher. werkzeug/src/werkzeug/routing/matcher.py Line 128 in 7868bef
Making the change fixes a similar issue on my end and all tests pass, which indicates that there is a missing test. edit: this is not the issue, false positive related to the structure of the routes I was testing |
Having dug deeper into the issue, I think it comes from a conflict in how RulePart weights are calculated. Currently However, The simplest fix is to switch to use Here is an example of the missing test. def test_static_priority():
map = r.Map(
[
r.Rule("/<path:dyn2>/<dyn1>", endpoint="file"),
r.Rule("/<dyn1>/statn", endpoint="stat"),
],
adapter = map.bind("example.org", "/")
assert adapter.match("/d2/d1", method="GET") == ('file', {'dyn2': 'd2', 'dyn1': 'd1'})
assert adapter.match("/d1/statn", method="GET") == ('stat', {'dyn1': 'd1'}) |
Fix issue pallets#2924 where Rules with dynamic elements would take priority over rules with static elements of the same length. The underlying issue was that the ordering for rules was backwards with regard to number of argument weights. In order to ensure that static elements match first the shortest rule must be tested first. To ensure that a RulePart that contains a path converter does not incorrectly take priority over other RuleParts that are part of other Rules that should have priority, RuleParts containing a path converter are assigned an infinite number of argument weights because they can consume an arbitrary number of url path elements when matching. With this change, two consecutive path converters give priority to the first converter. In general two consecutive path converters with different names cannot have consistent or predicatable behavior (where would you cut?). Tests are updated accordingly. Might consider making back to back path converters an error. closes pallets#2924
Fix issue pallets#2924 where Rules with dynamic elements would take priority over rules with static elements of the same length. The underlying issue was that the ordering for rules was backwards with regard to number of argument weights. In order to ensure that static elements match first the shortest rule must be tested first. To ensure that a RulePart that contains a path converter does not incorrectly take priority over other RuleParts that are part of other Rules that should have priority, RuleParts containing a path converter are assigned an infinite number of argument weights because they can consume an arbitrary number of url path elements when matching. With this change, two consecutive path converters give priority to the first converter. In general two consecutive path converters with different names cannot have consistent or predicatable behavior (where would you cut?). Tests are updated accordingly. Might consider making back to back path converters an error.
(Sorry for the convoluted title: I don't know the right vocabulary for this.)
I noticed when upgrading to Werkzeug 2.2+, two of my routing rules have swapped priority.
Sample application
Here's a simple werkzeug application. The important part is the 2 rules:
cat server.py
Before (on werkzeug <2.2)
Run the server:
Note how /healthcheck behaves the same on both the "static" subdomain, and a different subdomain "foo":
"static" subdomain:
"foo" subdomain:
After (werkzeug 2.2+)
Note how /healthcheck now behaves differently on the two subdomains. On "static", we now get back the
on_static
endpoint, and on "foo" we still get back theon_healthcheck
endpoint."static" subdomain:
"foo" subdomain:
I see the same behavior with the latest version of werkzeug (3.0.3 at time of writing).
Summary
Is this change in behavior intentional? The PR #2433 just describes this as a faster matcher, it doesn't say anything about a change in behavior.
Is there some way of configuring a route across all subdomains that takes precedence over the subdomain specific
/<path:filename>
rule in my example?Workaround
I don't have a great workaround for this. I can get close to the pre-werkzeug 2.2 behavior by adding a 3rd rule specifically for the "static" subdomain:
Rule('/<path:filename>', endpoint=self.on_static, subdomain="static"), Rule('/healthcheck', endpoint=self.on_healthcheck, subdomain="<subdomain>"), +Rule('/healthcheck', endpoint=self.on_healthcheck, subdomain="static"),
But this behaves a bit differently: there's no
subdomain
argument passed to my endpoint handler.Environment:
@pgjones, since you wrote the new matcher
The text was updated successfully, but these errors were encountered: