From daa42afc9d103e60b373da22091d6f22a2f880da Mon Sep 17 00:00:00 2001 From: BlasterAlex Date: Thu, 21 Dec 2023 17:05:57 +0400 Subject: [PATCH 1/2] Fix gorilla#739: Fixed handling of invalid query params --- mux_test.go | 17 +++++++++++++++++ route.go | 23 +++++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/mux_test.go b/mux_test.go index cb3bbe0a..7f123f02 100644 --- a/mux_test.go +++ b/mux_test.go @@ -2784,6 +2784,23 @@ func TestMethodNotAllowed(t *testing.T) { } } +func TestMethodNotAllowedSubrouterWithSeveralRoutes(t *testing.T) { + handler := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } + + router := NewRouter() + subrouter := router.PathPrefix("/v1").Subrouter() + subrouter.HandleFunc("/api", handler).Methods(http.MethodGet) + subrouter.HandleFunc("/api/{id}", handler).Methods(http.MethodGet) + + w := NewRecorder() + req := newRequest(http.MethodPut, "/v1/api") + router.ServeHTTP(w, req) + + if w.Code != http.StatusMethodNotAllowed { + t.Errorf("Expected status code 405 (got %d)", w.Code) + } +} + type customMethodNotAllowedHandler struct { msg string } diff --git a/route.go b/route.go index 8a9e754a..cb89ebb8 100644 --- a/route.go +++ b/route.go @@ -53,6 +53,19 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool { continue } + // 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 rr, ok := m.(*routeRegexp); ok { + if rr.regexpType == regexpTypeQuery { + matchErr = ErrNotFound + break + } + } + // Ignore ErrNotFound errors. These errors arise from match call // to Subrouters. // @@ -66,16 +79,6 @@ 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 - } } } From 20c90d33b0fc44741b00dffca1acc4574a0ebc1a Mon Sep 17 00:00:00 2001 From: BlasterAlex Date: Fri, 22 Dec 2023 02:27:58 +0400 Subject: [PATCH 2/2] Fixed processing of multiple queries for the same path --- mux_test.go | 18 ++++++++++++++++++ route.go | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mux_test.go b/mux_test.go index 7f123f02..0845d7f7 100644 --- a/mux_test.go +++ b/mux_test.go @@ -2116,6 +2116,24 @@ func TestMultipleDefinitionOfSamePathWithDifferentMethods(t *testing.T) { } +func TestMultipleDefinitionOfSamePathWithDifferentQueries(t *testing.T) { + emptyHandler := func(w http.ResponseWriter, r *http.Request) {} + + r := NewRouter() + r.HandleFunc("/api", emptyHandler).Queries("foo", "{foo:[0-9]+}").Methods(http.MethodGet) + r.HandleFunc("/api", emptyHandler).Queries("bar", "{bar:[0-9]+}").Methods(http.MethodGet) + + req := newRequest(http.MethodGet, "/api?bar=4") + 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 have no error. Found:", match.MatchErr) + } +} + func TestErrMatchNotFound(t *testing.T) { emptyHandler := func(w http.ResponseWriter, r *http.Request) {} diff --git a/route.go b/route.go index cb89ebb8..b6582dae 100644 --- a/route.go +++ b/route.go @@ -87,7 +87,7 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool { return false } - if match.MatchErr == ErrMethodMismatch && r.handler != nil { + if match.MatchErr != nil && r.handler != nil { // We found a route which matches request method, clear MatchErr match.MatchErr = nil // Then override the mis-matched handler