Skip to content

Commit 7f08801

Browse files
Roberto Santallakisielk
authored andcommitted
MatchErr is set to ErrNotFound if NotFoundHandler is used (#311)
1 parent 9f48112 commit 7f08801

File tree

3 files changed

+106
-43
lines changed

3 files changed

+106
-43
lines changed

mux.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
var (
1616
ErrMethodMismatch = errors.New("method is not allowed")
17+
ErrNotFound = errors.New("no matching route was found")
1718
)
1819

1920
// NewRouter returns a new router instance.
@@ -82,16 +83,23 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
8283
}
8384
}
8485

85-
if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
86-
match.Handler = r.MethodNotAllowedHandler
87-
return true
86+
if match.MatchErr == ErrMethodMismatch {
87+
if r.MethodNotAllowedHandler != nil {
88+
match.Handler = r.MethodNotAllowedHandler
89+
return true
90+
} else {
91+
return false
92+
}
8893
}
8994

9095
// Closest match for a router (includes sub-routers)
9196
if r.NotFoundHandler != nil {
9297
match.Handler = r.NotFoundHandler
98+
match.MatchErr = ErrNotFound
9399
return true
94100
}
101+
102+
match.MatchErr = ErrNotFound
95103
return false
96104
}
97105

mux_test.go

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,96 @@ func TestSubrouterHeader(t *testing.T) {
18771877
}
18781878
}
18791879

1880+
func TestNoMatchMethodErrorHandler(t *testing.T) {
1881+
func1 := func(w http.ResponseWriter, r *http.Request) {}
1882+
1883+
r := NewRouter()
1884+
r.HandleFunc("/", func1).Methods("GET", "POST")
1885+
1886+
req, _ := http.NewRequest("PUT", "http://localhost/", nil)
1887+
match := new(RouteMatch)
1888+
matched := r.Match(req, match)
1889+
1890+
if matched {
1891+
t.Error("Should not have matched route for methods")
1892+
}
1893+
1894+
if match.MatchErr != ErrMethodMismatch {
1895+
t.Error("Should get ErrMethodMismatch error")
1896+
}
1897+
1898+
resp := NewRecorder()
1899+
r.ServeHTTP(resp, req)
1900+
if resp.Code != 405 {
1901+
t.Errorf("Expecting code %v", 405)
1902+
}
1903+
1904+
// Add matching route
1905+
r.HandleFunc("/", func1).Methods("PUT")
1906+
1907+
match = new(RouteMatch)
1908+
matched = r.Match(req, match)
1909+
1910+
if !matched {
1911+
t.Error("Should have matched route for methods")
1912+
}
1913+
1914+
if match.MatchErr != nil {
1915+
t.Error("Should not have any matching error. Found:", match.MatchErr)
1916+
}
1917+
}
1918+
1919+
func TestErrMatchNotFound(t *testing.T) {
1920+
emptyHandler := func(w http.ResponseWriter, r *http.Request) {}
1921+
1922+
r := NewRouter()
1923+
r.HandleFunc("/", emptyHandler)
1924+
s := r.PathPrefix("/sub/").Subrouter()
1925+
s.HandleFunc("/", emptyHandler)
1926+
1927+
// Regular 404 not found
1928+
req, _ := http.NewRequest("GET", "/sub/whatever", nil)
1929+
match := new(RouteMatch)
1930+
matched := r.Match(req, match)
1931+
1932+
if matched {
1933+
t.Errorf("Subrouter should not have matched that, got %v", match.Route)
1934+
}
1935+
// Even without a custom handler, MatchErr is set to ErrNotFound
1936+
if match.MatchErr != ErrNotFound {
1937+
t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
1938+
}
1939+
1940+
// Now lets add a 404 handler to subrouter
1941+
s.NotFoundHandler = http.NotFoundHandler()
1942+
req, _ = http.NewRequest("GET", "/sub/whatever", nil)
1943+
1944+
// Test the subrouter first
1945+
match = new(RouteMatch)
1946+
matched = s.Match(req, match)
1947+
// Now we should get a match
1948+
if !matched {
1949+
t.Errorf("Subrouter should have matched %s", req.RequestURI)
1950+
}
1951+
// But MatchErr should be set to ErrNotFound anyway
1952+
if match.MatchErr != ErrNotFound {
1953+
t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
1954+
}
1955+
1956+
// Now test the parent (MatchErr should propagate)
1957+
match = new(RouteMatch)
1958+
matched = r.Match(req, match)
1959+
1960+
// Now we should get a match
1961+
if !matched {
1962+
t.Errorf("Router should have matched %s via subrouter", req.RequestURI)
1963+
}
1964+
// But MatchErr should be set to ErrNotFound anyway
1965+
if match.MatchErr != ErrNotFound {
1966+
t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
1967+
}
1968+
}
1969+
18801970
// mapToPairs converts a string map to a slice of string pairs
18811971
func mapToPairs(m map[string]string) []string {
18821972
var i int
@@ -1943,42 +2033,3 @@ func newRequest(method, url string) *http.Request {
19432033
}
19442034
return req
19452035
}
1946-
1947-
func TestNoMatchMethodErrorHandler(t *testing.T) {
1948-
func1 := func(w http.ResponseWriter, r *http.Request) {}
1949-
1950-
r := NewRouter()
1951-
r.HandleFunc("/", func1).Methods("GET", "POST")
1952-
1953-
req, _ := http.NewRequest("PUT", "http://localhost/", nil)
1954-
match := new(RouteMatch)
1955-
matched := r.Match(req, match)
1956-
1957-
if matched {
1958-
t.Error("Should not have matched route for methods")
1959-
}
1960-
1961-
if match.MatchErr != ErrMethodMismatch {
1962-
t.Error("Should get ErrMethodMismatch error")
1963-
}
1964-
1965-
resp := NewRecorder()
1966-
r.ServeHTTP(resp, req)
1967-
if resp.Code != 405 {
1968-
t.Errorf("Expecting code %v", 405)
1969-
}
1970-
1971-
// Add matching route
1972-
r.HandleFunc("/", func1).Methods("PUT")
1973-
1974-
match = new(RouteMatch)
1975-
matched = r.Match(req, match)
1976-
1977-
if !matched {
1978-
t.Error("Should have matched route for methods")
1979-
}
1980-
1981-
if match.MatchErr != nil {
1982-
t.Error("Should not have any matching error. Found:", match.MatchErr)
1983-
}
1984-
}

route.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
7272
return false
7373
}
7474

75-
match.MatchErr = nil
75+
if match.MatchErr == ErrMethodMismatch {
76+
// We found a route which matches request method, clear MatchErr
77+
match.MatchErr = nil
78+
}
79+
7680
// Yay, we have a match. Let's collect some info about it.
7781
if match.Route == nil {
7882
match.Route = r

0 commit comments

Comments
 (0)