-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Fix non-exact match of pattern with trailing slash. #3923
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
Fix non-exact match of pattern with trailing slash. #3923
Conversation
For better or worse, some communities (notably Django) have chosen to include trailing slashes in URLs. |
I didn't include any documentation changes because the v4 branch doesn't appear to contain a changelog yet (until it's deemed stable, I guess). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
in a browser foo and foo/ are different, I want to be like the browser, not django, I need to look deeper at this commit, on a phone right now. |
With this code will a location of "foo" match pattern of "foo/"? |
Just ran into this yesterday. More specifically, in any RFC 3986 compliant URL parser will distinguish with the trailing slash. But in terms of what this API is attempting to do, which is match a URL pattern, I can confirm if you go into something like the Basic example and change the <Match pattern="/about/" component={About} />
// These match
<Link to="/about">About</Link> // Wrong!
<Link to="/about/">About</Link>
// These don't match :(
<Link to="/about/foo">About</Link>
<Link to="/about/foo/">About</Link> This looks to be fixing a specific pattern condition. The spec violation is another issue entirely, but should be fixed. Could that be coming from |
<Match pattern="/foo/bar/"/>
// SHOULD match
"/foo/bar/"
// SHOULD NOT match
"/foo/bar"
<Match pattern="/foo/bar"/>
// SHOULD match
"/foo/bar/"
"/foo/bar" |
@timdorr I fixed my message and deleted our other ones to keep this thread less crazy than it was heading :) |
No worries. Again, that's sort of a separate issue from this PR. This is fixing matching for any non-exact pattern that has a trailing slash (E.g., I say we merge this in as a start and then look at the issue of exact-ish non-trailing URLs matching a trailing slash pattern. (E.g., |
Indeed browsers don' t give slashes any special treatment. Web servers serving static files off a filesystem might have filesystem-like semantics (e.g. collapse duplicate slashes, handle ../ for navigating to a parent directory, etc.) but that's unrelated to HTTP.
I'm not sure if or how it comes into play here, but it's something to keep in mind. I agree with the behavior @ryanflorence specified two comments above. Basically react-router should do a prefix match when I'm happy to investigate further and add more tests, either in this PR or in a follow-up PR. Whatever works best for you :-) |
@timdorr There's a good chance that setting the |
@aaugustin Yep, that's definitely what we need. Good find! |
Should I add this fix to this PR or start a new PR? |
If it's that simple, I say add it here. Might as well tackle all the trailing slash stuff in one go. |
@@ -1,21 +1,30 @@ | |||
import pathToRegexp from 'path-to-regexp' | |||
|
|||
const cache = {} | |||
const pathToRegexpOptions = {strict: true} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just inline this. No need to extract it out. We're not using it anywhere else and there are only a few potential options anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, a small nitpick: Can you put spaces inside of the brackets for an object? It's not officially enforced, but it's kind of the standard around the code and looks good inline with everything else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do. Pulling the constant out was a nano-optimization. Sorry about not checking the coding style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes noted
I just added another commit to prevent URL FYI while we're looking at path-to-regex options:
|
Let's keep this PR on hold for today, I'll try |
I just added a commit that removes the As far as I can tell, I have addressed all comments in the thread. This should be ready to merge. Thanks! |
While this PR still carries @timdorr's "Changes requested" mark, I made the requested changes, and then some. It's ready for a new round of review and hopefully a merge. Please let me know if there's any way I can help. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It reads a little oddly, but I'm fine with it as-is.
@@ -1,22 +1,20 @@ | |||
import pathToRegexp from 'path-to-regexp' | |||
|
|||
const cache = {} | |||
// cache[exactly][pattern] contains getMatcher(pattern, exactly) | |||
const cache = {true: {}, false: {}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is the only weird part that bothers me. But implicit type conversion always does that for me...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! As a Pythonista, I failed to notice that these keys are strings / symbols, not booleans. I agree that it feels sloppy...
That said, adding explicit type conversions doesn't make the code more readable. Perhaps it's best to live with the implicit conversion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add a small ternary to use proper string keys. To help with that, you can store that as a separate variable, cache_type
for instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I added a commit with that change.
Currently the test for a non-exact, partial match fails.
Currently, in the v4 branch,
<Match pattern="/foo/" component={Foo} />
fails to match at/foo/bar/
, because the URL is truncated to/foo/bar
instead of/foo/
prior to being matched.