julienschmidt / httprouter

A high performance HTTP request router that scales well
https://pkg.go.dev/github.com/julienschmidt/httprouter
BSD 3-Clause "New" or "Revised" License
16.63k stars 1.47k forks source link

url encoded within restapi url component #226

Open uriklagnes opened 6 years ago

uriklagnes commented 6 years ago

Hi,

I'm trying to create an API with scheme POST /some/base/url/{{ some other url encoded here }}

Where the last part of the url is extracted by router, but it is itself an url that has been encoded by front end code.

So {{ some other url encoded here }} will be something like http://www.google.ca

(But the front end will encode this as http%3A%2F%2Fwww.google.ca first)

The problem is, when front end does the POST call, it gets a 404. My hunch is that the router must be "seeing" the URL as the real URL and is trying to match on: /some/base/url/http://www.google.ca <-- it is seeing the two // within url.

Is there a way for me to actually confirm this? Because the 404 is coming from the router not my app. Is there a workaround?

Thanks

tmthrgd commented 6 years ago

https://github.com/julienschmidt/httprouter/blob/e1b9828bc9e5904baec057a154c09ca40fe7fae0/router.go#L340 uses req.URL.Path as the path to match against where req.URL is a url.URL. According to the documentation of url.URL:

Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/. A consequence is that it is impossible to tell which slashes in the Path were slashes in the raw URL and which were %2f. This distinction is rarely important, but when it is, code must not use Path directly. The Parse function sets both Path and RawPath in the URL it returns, and URL's String method uses RawPath if it is a valid encoding of Path, by calling the EscapedPath method.

If you need this behaviour, try replacing that line with the following and seeing if that works:

    path := req.URL.EscapedPath() 
Mousaka commented 6 years ago

@uriklagnes You might find this interesting if you are using or can use a gorilla/mux Router. There is this setting available for it: UseEncodedPath

UseEncodedPath tells the router to match the encoded original
path to the routes.
For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".

If not called, the router will match the unencoded path to the
routes. For eg. "/path/foo%2Fbar/to" will match the path 
"/path/foo/bar/to"

Judging from the description it seems to solve your problem. I'm soon gonna try it out.

pietervogelaar commented 5 years ago

@uriklagnes You might find this interesting if you are using or can use a gorilla/mux Router. There is this setting available for it: UseEncodedPath

UseEncodedPath tells the router to match the encoded original
path to the routes.
For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".

If not called, the router will match the unencoded path to the
routes. For eg. "/path/foo%2Fbar/to" will match the path 
"/path/foo/bar/to"

Judging from the description it seems to solve your problem. I'm soon gonna try it out.

I can confirm that the gorilla/mux router solves this problem. It would be nice if httprouter supports this too.

firelizzard18 commented 1 year ago

I opened a PR to implement an option to enable this behavior