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) {}