-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Add mechanism to route based on the escaped path #184
Conversation
ab963db
to
f527679
Compare
The new test case fails on < go1.5. Please advise on how to skip this case for those versions. |
I think you need to have a separate getPath for versions < go1.5 |
Correct. You need to put it in its own file with a build tag so that it sometimes it can make sense to copy std lib code in to backport the
|
f527679
to
8f41eac
Compare
I actually found the way recommended to do it in < 1.5 as mentioned here: https://golang.org/pkg/net/url/#URL I'm essentially doing what the new Going to now see if I can replace the regex matching with simple string slicing. |
LGTM. @elithrar ? |
// as detailed here as detailed in https://golang.org/pkg/net/url/#URL | ||
// for < 1.5 server side workaround | ||
// http://localhost/path/here?v=1 -> /path/here | ||
re := regexp.MustCompile(req.URL.Scheme `://` req.URL.Host) |
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.
Could a panic be triggered here? punycode and RFC compliant hosts should not (I have not tested exhaustively...), but worried about adding MustCompile to the request critical path.
One reasonably key comment, and the follow-up question: could this be done in middleware prior to mux handling the request? |
I realized the regex was unnecessary and would probably have large performance impacts, the parsing is cleaner and tighter now with just some simple indexing. As for the middleware, are you suggesting we forcibly assign req.URL.Path the escaped path we extracted? I think that would be unwise as it would break what is expected in req.URL.Path as specified by the stdlib. |
b76b288
to
5f70225
Compare
Running some benchmarks on this (just for documentation) and running some further testing. I was checked out into this branch and it broke an API proxy I had running for a project, so want to replicate and ensure we are testing more thoroughly. ("blocked") |
// http://localhost/path/here?v=1 -> /path/here | ||
iStart := len(req.URL.Scheme `://` req.URL.Host) | ||
path := req.RequestURI[iStart:] | ||
if i := strings.LastIndex(path, "?"); i > -1 { |
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.
This handles URLs in the form scheme://host/path?query
and scheme://host/path?query#fragment
, but not scheme://host/path#fragment
.
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.
Since we have the raw query string and fragment can we just get the length of those and strip that off via a slice as well?
5f70225
to
cef43a6
Compare
@elithrar Can you provide a test case/situation that's causing the breakage? |
@kushmansingh Will try to get something to you tonight - it's easy to replicate but want to dig into why first. |
OK - with the tip of this branch installed: run https://gist.github.com/elithrar/51399e558e517bade6c29fed7ee72dbd (a minimal version of my API proxy with all of the CORS/RW wrapper pulled out for simplicity). mux is panicking when parsing the URL. The
Stack trace:
|
@kushmansingh see above (just in case GitHub chooses not to send you the notification). |
@elithrar Added a test case to replicate the condition, everything should be good now hopefully 😄 |
Thanks. LGTM to me and the updated branch no longer panics.
|
I'm in Africa for the next 3 weeks so won't be reviewing code. If it looks
|
Some of my code stopped working after this change. I came to this PR to understand the change better and to figure out if the problem was in my code, or in this change. In general, I don't mind breaking changes in APIs, as long as they are done intentionally and lead to an improvement, so it's not a problem. But I wish this PR was documented better - it was hard to figure out why it was done and what it attempted to accomplish. After looking around, I think I've figured out what happened, so I'll offer some suggestions for improvement (for next time) and explain for posterity in case others run into the same issue as I did:
The reason my code stopped working (all routes stopped matching) is because I was modifying the I'll note that I'm thankful to the developers/maintainers of this library for doing a great job overall, and to the PR creator for working on resolving an issue. This comment is simply to provide what I hope is helpful additional information and suggestions for improvement for next time. I'm not trying to be negative. Thanks! |
This is needed after change in gorilla/mux#184 started using req.RequestURI rather than req.URL.Path to determine path for route matching. Clearing req.RequestURI is a simple fix that works, but maybe I'll want a more sophisticated fix later that modifies req.RequestURI to match req.URI.Path modification. Or look into doing routing at URL path-level rather than HTTP request-level.
I appreciate the feedback @shurcooL - this definitely was not intended as a breaking change, but (as you detailed) ended up being one due to oversight. As an aside: mux has a lot of users, and an API that we are trying to keep useful-yet-flexible. The Issues and PR tabs are littered with rejections of features, but perhaps not as many rejections as I'd like (given 20/20 hindsight!). That's not unique for an OSS project though! |
As @shurcooL already correctly described, this change assumes that This change probably breaks a lot of exiting uses of gorilla/mux and imho reverting this change should be considered until there is a better solution. |
@neelance Would you be able to submit a PR that reverts this? (it's not a one-click revert). I won't have time until tonight or tomorrow (at the earliest). (or, at the least, open an issue with your comment above) |
Reversion is probably the fastest solution if this is breaking for a lot of users. Here are some options for how to get this behavior functioning:
I'm open to any other solutions and comments and I apologize for the inconvenience caused by this breakage. |
It appears the URL.Path is broken for any use as a routing path. Even in newer version of Go it contains an 'unescaped' path, but they don't take any precautions to only unescape valid characters in a segment. The result is a path that can contain '/' where it should NOT exist. https://play.golang.org/p/j41wEQeMM-
Result:
The documentation examples for ServeMux imply that request.URL.Path is a public interface suitable for overriding (e.g. StripPrefix ). It probably shouldn't since this won't result in proper behavior. Gorilla Mux should be clear in the docs about what value is used to route on so users can use that as part of the public API. The tricky bit here is that Path and RawPath must both be in sync or EscapedPath() will not work as expected (see above example). It should also be made clear if the paths given to routers need to be URL encoded themselves. |
@calebcase The documentation of URL.Path recognizes this fact (https://golang.org/pkg/net/url/#URL):
So I wouldn't say that "URL.Path is broken for any use as a routing path". They chose to ignore this edge case for simplicity. If your application depends on this edge case, then unfortunately you have to roll your own implementation based on URL.RawPath or Request.RequestURI instead of relying on the standard library's tools. I think the same applies to gorilla/mux. |
Possible, but not now. gorilla/mux has been around for a long while and Ubuntu/Debian, et. al, still package < Go 1.5 (horrible, but reality).
This would likely live outside of mux, since mux doesn't have an API for middleware. Alternatively, it would work like
As above (so yes, I agree). |
Here's an idea, but I'm unsure if it's viable or not. If you look at how https://godoc.org/net/url#URL.EscapedPath works:
Can we do something similar and detect if req.URL.Path is a valid/possible encoding of req.RequestURI, and only use req.RequestURI in that case? Otherwise defer to req.URL.Path? |
My preference is to be explicit rather than implicit ('clever'). @kushmansingh Are you able to submit a PR that (my preference) adds a |
@elithrar I'll be working on it and should have one up in the next day or two. I'll post updates if anything changes. |
See #190 - feedback welcome. |
- Resolves a breaking change in #184
No description provided.