Skip to content
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

Subrouters match the wrong method when more than one matches #300

Closed
silverweed opened this issue Oct 2, 2017 · 13 comments
Closed

Subrouters match the wrong method when more than one matches #300

silverweed opened this issue Oct 2, 2017 · 13 comments

Comments

@silverweed
Copy link

Introduced by #288.
Given the following code:

package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

func main() {
	router := mux.NewRouter()
	get := router.Methods("GET", "HEAD").Subrouter()
	post := router.Methods("POST").Subrouter()

	post.HandleFunc("/some/{thing}", func(rw http.ResponseWriter, req *http.Request) {
		fmt.Fprintln(rw, "post")
	})
	get.HandleFunc("/some/{thing}", func(rw http.ResponseWriter, req *http.Request) {
		fmt.Fprintln(rw, "get")
	})

	http.Handle("/", router)
	http.ListenAndServe(":8888", nil)
}

a POST request to /some/thing will always match the get subrouter:

curl localhost:8888/some/thing -X POST # -> get

The same happens when there is a subrouter with a "catch-all" route, like

get.HandleFunc("/{anything}", getAnything)

This route will match any valid POST route without parameters.

These behaviours happen no matter the calling order of the HandleFuncs.

Commenting these lines seems to solve the issue, but of course breaks #288

@leofachini
Copy link

leofachini commented Oct 8, 2017

I'm facing the same problem as you @silverweed, but with another route setup. (Would you think these might be related? If not, I will open a new issue.)

With the following code:

`
func main() {
r := mux.NewRouter()
sub := r.PathPrefix("/").Subrouter()

sub.StrictSlash(true).Path("/test").Methods("GET").HandlerFunc(getFunc)
sub.StrictSlash(true).Path("/test").Methods("POST").HandlerFunc(postFunc)

log.Fatal(http.ListenAndServe(":3000", r))

}

func getFunc(w http.ResponseWriter, r *http.Request) {

fmt.Printf("%+v\n", r.Method)

json.NewEncoder(w).Encode(r.Method)

}

func postFunc(w http.ResponseWriter, r *http.Request) {

fmt.Printf("%+v\n", r.Method)

json.NewEncoder(w).Encode(r.Method)

}
`

A GET to localhost:3000/test will result in:
GET ✔️

A GET to localhost:3000/test/ will result in:
GET ✔️

A POST to localhost:3000/test will result in:
POST ✔️

A POST to localhost:3000/test/ will result in:
GET ❌ (unexpected behavior)

@stevenh
Copy link

stevenh commented Oct 19, 2017

This has hit us too, the current 1.5.0 release is totally broken for any users that have Method based routing.

This means anyone updating using ^1.x... semantic versioning will end up with broken apps.

Given this there really needs to be 1.5.1 release urgently to address this.

@elithrar
Copy link
Contributor

elithrar commented Oct 19, 2017 via email

@stevenh
Copy link

stevenh commented Oct 19, 2017

Yes thats exactly what we’ve done but not before it caused an outage for our customers.
So just trying to help protect others from such an outage.

@roobre
Copy link
Contributor

roobre commented Nov 3, 2017

Maybe I can look into this if any of the affected users add some test cases. I just tweaked this code in #311, so it shouldn't be difficult for me to fix this.

@elithrar
Copy link
Contributor

elithrar commented Nov 4, 2017 via email

@roobre
Copy link
Contributor

roobre commented Nov 5, 2017

Maybe I can take a look at the user examples to see if they can be ported to tests. I'll give it a try tomorrow.

@mtso
Copy link
Contributor

mtso commented Nov 26, 2017

Hi @roobre, are you still working on this? If not, I'd like to take a stab at it.

I found something odd here: https://github.com/gorilla/mux/blob/master/route.go#L84
Using OP's example, it's assigning a handler only if match.Handler is nil, but it’s already assigned to GET when executing the POST match. The fix may lie before that, though, because match.Handler should be nil for an invalid method match.

@roobre
Copy link
Contributor

roobre commented Nov 26, 2017

I'm quite on hold since reviewers are on vacation :(

I planned to get on this when my PR (#294) gets resolved, but if you want to look at it, be my guest :3

kisielk pushed a commit that referenced this issue Nov 28, 2017
* Test method-based subrouters for multiple matching paths

* Pass TestMethodsSubrouter

* Change http.Method* constants to string literals
- Make compatible with Go v1.5

* Make TestMethodsSubrouter stateless and concurrent

* Remove t.Run and break up tests for concurrency

* Use backticks to remove quote escaping

* Remove global method handlers and HTTP method constants
@kisielk
Copy link
Contributor

kisielk commented Nov 28, 2017

@silverweed @leofachini @stevenh @roobre can you check if the PR today fixed this for you?

@silverweed
Copy link
Author

@kisielk Looks like it's working well :)
Thank you!

@elithrar
Copy link
Contributor

Closing this out.

@etrapani
Copy link

I remove the strictSlash and everything work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants