diff options
Diffstat (limited to 'router.go')
-rw-r--r-- | router.go | 60 |
1 files changed, 30 insertions, 30 deletions
@@ -2,8 +2,6 @@ package gus import ( "context" - "crypto/tls" - "net/url" "strings" "tildegit.org/tjp/gus/internal" @@ -27,11 +25,18 @@ import ( // The zero value is a usable Router which will fail to match any requst path. type Router struct { tree internal.PathTree[Handler] + + middleware []Middleware + routeAdded bool } // Route adds a handler to the router under a path pattern. -func (r Router) Route(pattern string, handler Handler) { +func (r *Router) Route(pattern string, handler Handler) { + for i := len(r.middleware) - 1; i >= 0; i-- { + handler = r.middleware[i](handler) + } r.tree.Add(pattern, handler) + r.routeAdded = true } // Handler matches against the request path and dipatches to a route handler. @@ -59,6 +64,8 @@ func (r Router) Handler(ctx context.Context, request *Request) *Response { } // Match returns the matched handler and captured path parameters, or nils. +// +// The returned handlers will be wrapped with any middleware attached to the router. func (r Router) Match(request *Request) (Handler, map[string]string) { handler, params := r.tree.Match(request.Path) if handler == nil { @@ -72,19 +79,27 @@ func (r Router) Match(request *Request) (Handler, map[string]string) { // The prefix pattern may include segment :wildcards, but no *remainder segment. The // mounted sub-router should have patterns which only include the portion of the path // after whatever was matched by the prefix pattern. -func (r Router) Mount(prefix string, subrouter *Router) { +func (r *Router) Mount(prefix string, subrouter *Router) { prefix = strings.TrimSuffix(prefix, "/") - r.Route(prefix+"/*"+subrouterPathKey, func(ctx context.Context, request *Request) *Response { - r := cloneRequest(request) - r.Path = "/" + RouteParams(ctx)[subrouterPathKey] - return subrouter.Handler(ctx, r) - }) - - // TODO: better approach. the above works but it's a little hacky - // - add a method to PathTree that returns all the registered patterns - // and their associated handlers - // - have Mount pull those out of the subrouter, prepend the prefix to - // all its patterns, and re-add them to the parent router. + + for _, subroute := range subrouter.tree.Routes() { + r.Route(prefix+"/"+subroute.Pattern, subroute.Value) + } +} + +// Use attaches a middleware to the router. +// +// Any routes set on the router will have their handlers decorated by the attached +// middlewares in reverse order (the first middleware attached will be the outer-most: +// first to see requests and the last to see responses). +// +// Use will panic if Route or Mount have already been called on the router - +// middlewares must be set before any routes. +func (r *Router) Use(mw Middleware) { + if r.routeAdded { + panic("all middlewares must be added prior to adding routes") + } + r.middleware = append(r.middleware, mw) } // RouteParams gathers captured path parameters from the request context. @@ -104,18 +119,3 @@ const subrouterPathKey = "subrouter_path" type routeParamsKeyType struct{} var routeParamsKey = routeParamsKeyType{} - -func cloneRequest(start *Request) *Request { - end := &Request{} - *end = *start - - end.URL = &url.URL{} - *end.URL = *start.URL - - if start.TLSState != nil { - end.TLSState = &tls.ConnectionState{} - *end.TLSState = *start.TLSState - } - - return end -} |