Reintroduce (optional) 405 handling Based on #51 Fixes #30 Fixed #52
diff --git a/router.go b/router.go index 7716dc7..ac3d680 100644 --- a/router.go +++ b/router.go
@@ -123,13 +123,21 @@ // handle is registered for it. // First superfluous path elements like ../ or // are removed. // Afterwards the router does a case-insensitive lookup of the cleaned path. - // If a handle can be found for this route, the router makes a redirection + // If a handle can be found for this route, the router makes a redirection // to the corrected path with status code 301 for GET requests and 307 for // all other request methods. // For example /FOO and /..//Foo could be redirected to /foo. // RedirectTrailingSlash is independent of this option. RedirectFixedPath bool + // If enabled, the router checks if another method is allowed for the + // current route, if the current request can not be routed. + // If this is the case, the request is answered with 'Method Not Allowed' + // and HTTP status code 405. + // If no other Method is allowed, the request is delegated to the NotFound + // handler. + HandleMethodNotAllowed bool + // Configurable http.HandlerFunc which is called when no matching route is // found. If it is not set, http.NotFound is used. NotFound http.HandlerFunc @@ -149,8 +157,9 @@ // Path auto-correction, including trailing slashes, is enabled by default. func New() *Router { return &Router{ - RedirectTrailingSlash: true, - RedirectFixedPath: true, + RedirectTrailingSlash: true, + RedirectFixedPath: true, + HandleMethodNotAllowed: true, } } @@ -313,6 +322,25 @@ } } + // Handle 405 + if r.HandleMethodNotAllowed { + for method := range r.trees { + // Skip the requested method - we already tried this one + if method == req.Method { + continue + } + + handle, _, _ := r.trees[method].getValue(req.URL.Path) + if handle != nil { + http.Error(w, + http.StatusText(http.StatusMethodNotAllowed), + http.StatusMethodNotAllowed, + ) + return + } + } + } + // Handle 404 if r.NotFound != nil { r.NotFound(w, req)
diff --git a/router_test.go b/router_test.go index 7c8ac09..6292ba8 100644 --- a/router_test.go +++ b/router_test.go
@@ -165,6 +165,21 @@ } } +func TestRouterNotAllowed(t *testing.T) { + handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {} + + router := New() + router.POST("/path", handlerFunc) + + // Test not allowed + r, _ := http.NewRequest("GET", "/path", nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, r) + if !(w.Code == http.StatusMethodNotAllowed) { + t.Errorf("NotAllowed handling route %s failed: Code=%d, Header=%v", w.Code, w.Header()) + } +} + func TestRouterNotFound(t *testing.T) { handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {}