|
|
|
@ -13,6 +13,10 @@ import ( |
|
|
|
"strings" |
|
|
|
"strings" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
ErrMethodMismatch = errors.New("method is not allowed") |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// NewRouter returns a new router instance.
|
|
|
|
// NewRouter returns a new router instance.
|
|
|
|
func NewRouter() *Router { |
|
|
|
func NewRouter() *Router { |
|
|
|
return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} |
|
|
|
return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} |
|
|
|
@ -39,6 +43,10 @@ func NewRouter() *Router { |
|
|
|
type Router struct { |
|
|
|
type Router struct { |
|
|
|
// Configurable Handler to be used when no route matches.
|
|
|
|
// Configurable Handler to be used when no route matches.
|
|
|
|
NotFoundHandler http.Handler |
|
|
|
NotFoundHandler http.Handler |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Configurable Handler to be used when the request method does not match the route.
|
|
|
|
|
|
|
|
MethodNotAllowedHandler http.Handler |
|
|
|
|
|
|
|
|
|
|
|
// Parent route, if this is a subrouter.
|
|
|
|
// Parent route, if this is a subrouter.
|
|
|
|
parent parentRoute |
|
|
|
parent parentRoute |
|
|
|
// Routes to be matched, in order.
|
|
|
|
// Routes to be matched, in order.
|
|
|
|
@ -65,6 +73,11 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil { |
|
|
|
|
|
|
|
match.Handler = r.MethodNotAllowedHandler |
|
|
|
|
|
|
|
return true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Closest match for a router (includes sub-routers)
|
|
|
|
// Closest match for a router (includes sub-routers)
|
|
|
|
if r.NotFoundHandler != nil { |
|
|
|
if r.NotFoundHandler != nil { |
|
|
|
match.Handler = r.NotFoundHandler |
|
|
|
match.Handler = r.NotFoundHandler |
|
|
|
@ -105,9 +118,15 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
|
|
|
req = setVars(req, match.Vars) |
|
|
|
req = setVars(req, match.Vars) |
|
|
|
req = setCurrentRoute(req, match.Route) |
|
|
|
req = setCurrentRoute(req, match.Route) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if handler == nil && match.MatchErr == ErrMethodMismatch { |
|
|
|
|
|
|
|
handler = methodNotAllowedHandler() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if handler == nil { |
|
|
|
if handler == nil { |
|
|
|
handler = http.NotFoundHandler() |
|
|
|
handler = http.NotFoundHandler() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !r.KeepContext { |
|
|
|
if !r.KeepContext { |
|
|
|
defer contextClear(req) |
|
|
|
defer contextClear(req) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -344,6 +363,11 @@ type RouteMatch struct { |
|
|
|
Route *Route |
|
|
|
Route *Route |
|
|
|
Handler http.Handler |
|
|
|
Handler http.Handler |
|
|
|
Vars map[string]string |
|
|
|
Vars map[string]string |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MatchErr is set to appropriate matching error
|
|
|
|
|
|
|
|
// It is set to ErrMethodMismatch if there is a mismatch in
|
|
|
|
|
|
|
|
// the request method and route method
|
|
|
|
|
|
|
|
MatchErr error |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type contextKey int |
|
|
|
type contextKey int |
|
|
|
@ -545,3 +569,12 @@ func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]s |
|
|
|
} |
|
|
|
} |
|
|
|
return true |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// methodNotAllowed replies to the request with an HTTP status code 405.
|
|
|
|
|
|
|
|
func methodNotAllowed(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
|
|
|
w.WriteHeader(http.StatusMethodNotAllowed) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// methodNotAllowedHandler returns a simple request handler
|
|
|
|
|
|
|
|
// that replies to each request with a status code 405.
|
|
|
|
|
|
|
|
func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) } |
|
|
|
|