Repository: gorilla/mux (go)

Issue:
[bug] Documentation for func (*Route) HeadersRegexp is incorrect
**Describe the bug**

The documentation example for [`func (*Route) HeadersRegexp`](https://pkg.go.dev/github.com/gorilla/mux?utm_source=godoc#Route.HeadersRegexp) is incorrect:

```go
r := mux.NewRouter()
r.HeadersRegexp("Content-Type", "application/(text|json)",
          "X-Requested-With", "XMLHttpRequest")
```

`mux.NewRouter()` returns `*mux.Router` but `HeadersRegexp` is defined on `*Route`. This is a small mistake and is not a major issue because the next (more verbose) example clarifies the mistake.

However, it's a mistake.

Should be something like:

```go
r := mux.NewRouter().NewRoute()
r.HeadersRegexp("Content-Type", "application/(text|json)",
          "X-Requested-With", "XMLHttpRequest")
```

**Versions**
> Go version: `go version`
go version go1.16.4 darwin/amd64


> package version: run `git rev-parse HEAD` inside the repo
91708ff8e35bafc8612f690a25f5dd0be6f16864


**Steps to Reproduce**
> How can the bug be triggered?

"Bug" is in documentation; triggered by looking at it.


**Expected behavior**
> What output or behaviour were you expecting instead?

As mentioned above, the example should look like:

```go
r := mux.NewRouter().NewRoute()
r.HeadersRegexp("Content-Type", "application/(text|json)",
          "X-Requested-With", "XMLHttpRequest")
```



Pull request description:
Clarify documentation examples of Route methods
Fixes #666 

**Summary of Changes**

1. Update `Route` method documentation comments where the example in the comments showed a `Router` before. Updated method names include:
    * `Headers`
    * `HeadersRegexp`
    * `Host`
    * `Path`
    * `Queries`
    * `Subrouter`
    * `URL`

Notes:
* This includes what PR #667 did plus some changes requested by a maintainer in the comments
* I was a little torn about changing the example in `Subrouter` since `(*Router).Host()` (like several `(*Router)` methods) just calls `(*Router).NewRoute().Host()` so I understand if maintainers are ambivalent about that example or want it to remain the same.


Patch:
diff --git a/route.go b/route.go
index ce1c9bf..cd85f4b 100644
--- a/route.go
+++ b/route.go
@@ -66,6 +66,16 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
 
 			matchErr = nil // nolint:ineffassign
 			return false
+		} else {
+			// Multiple routes may share the same path but use different HTTP methods. For instance:
+			// Route 1: POST "/users/{id}".
+			// Route 2: GET "/users/{id}", parameters: "id": "[0-9]+".
+			//
+			// The router must handle these cases correctly. For a GET request to "/users/abc" with "id" as "-2",
+			// The router should return a "Not Found" error as no route fully matches this request.
+			if match.MatchErr == ErrMethodMismatch {
+				match.MatchErr = nil
+			}
 		}
 	}
 
@@ -230,7 +240,7 @@ func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
 // Headers adds a matcher for request header values.
 // It accepts a sequence of key/value pairs to be matched. For example:
 //
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	r.Headers("Content-Type", "application/json",
 //	          "X-Requested-With", "XMLHttpRequest")
 //
@@ -255,7 +265,7 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
 // HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
 // support. For example:
 //
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	r.HeadersRegexp("Content-Type", "application/(text|json)",
 //	          "X-Requested-With", "XMLHttpRequest")
 //
@@ -283,7 +293,7 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route {
 //
 // For example:
 //
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	r.Host("www.example.com")
 //	r.Host("{subdomain}.domain.com")
 //	r.Host("{subdomain:[a-z]+}.domain.com")
@@ -342,7 +352,7 @@ func (r *Route) Methods(methods ...string) *Route {
 //
 // For example:
 //
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	r.Path("/products/").Handler(ProductsHandler)
 //	r.Path("/products/{key}").Handler(ProductsHandler)
 //	r.Path("/articles/{category}/{id:[0-9]+}").
@@ -377,7 +387,7 @@ func (r *Route) PathPrefix(tpl string) *Route {
 // It accepts a sequence of key/value pairs. Values may define variables.
 // For example:
 //
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	r.Queries("foo", "bar", "id", "{id:[0-9]+}")
 //
 // The above route will only match if the URL contains the defined queries
@@ -473,7 +483,7 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
 //
 // It will test the inner routes only if the parent route matched. For example:
 //
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	s := r.Host("www.example.com").Subrouter()
 //	s.HandleFunc("/products/", ProductsHandler)
 //	s.HandleFunc("/products/{key}", ProductHandler)
@@ -524,7 +534,7 @@ func (r *Route) Subrouter() *Router {
 // The scheme of the resulting url will be the first argument that was passed to Schemes:
 //
 //	// url.String() will be "https://example.com"
-//	r := mux.NewRouter()
+//	r := mux.NewRouter().NewRoute()
 //	url, err := r.Host("example.com")
 //	             .Schemes("https", "http").URL()
 //


Test patch:
diff --git a/mux_test.go b/mux_test.go
index 4345254..bd97d33 100644
--- a/mux_test.go
+++ b/mux_test.go
@@ -2069,6 +2069,53 @@ func TestNoMatchMethodErrorHandler(t *testing.T) {
 	}
 }
 
+func TestMultipleDefinitionOfSamePathWithDifferentMethods(t *testing.T) {
+	emptyHandler := func(w http.ResponseWriter, r *http.Request) {}
+
+	r := NewRouter()
+	r.HandleFunc("/api", emptyHandler).Methods("POST")
+	r.HandleFunc("/api", emptyHandler).Queries("time", "{time:[0-9]+}").Methods("GET")
+
+	t.Run("Post Method should be matched properly", func(t *testing.T) {
+		req, _ := http.NewRequest("POST", "http://localhost/api", nil)
+		match := new(RouteMatch)
+		matched := r.Match(req, match)
+		if !matched {
+			t.Error("Should have matched route for methods")
+		}
+		if match.MatchErr != nil {
+			t.Error("Should not have any matching error. Found:", match.MatchErr)
+		}
+	})
+
+	t.Run("Get Method with invalid query value should not match", func(t *testing.T) {
+		req, _ := http.NewRequest("GET", "http://localhost/api?time=-4", nil)
+		match := new(RouteMatch)
+		matched := r.Match(req, match)
+		if matched {
+			t.Error("Should not have matched route for methods")
+		}
+		if match.MatchErr != ErrNotFound {
+			t.Error("Should have ErrNotFound error. Found:", match.MatchErr)
+		}
+	})
+
+	t.Run("A mismach method of a valid path should return ErrMethodMismatch", func(t *testing.T) {
+		r := NewRouter()
+		r.HandleFunc("/api2", emptyHandler).Methods("POST")
+		req, _ := http.NewRequest("GET", "http://localhost/api2", nil)
+		match := new(RouteMatch)
+		matched := r.Match(req, match)
+		if matched {
+			t.Error("Should not have matched route for methods")
+		}
+		if match.MatchErr != ErrMethodMismatch {
+			t.Error("Should have ErrMethodMismatch error. Found:", match.MatchErr)
+		}
+	})
+
+}
+
 func TestErrMatchNotFound(t *testing.T) {
 	emptyHandler := func(w http.ResponseWriter, r *http.Request) {}