package sliderule import "context" // Handler is a type which can turn a request into a response. // // Handle may return a nil response, in which case the Server is expected // to build the protocol-appropriate "Not Found" response. type Handler interface { Handle(context.Context, *Request) *Response } type handlerFunc func(context.Context, *Request) *Response // HandlerFunc is a wrapper to allow using a function as a Handler. func HandlerFunc(f func(context.Context, *Request) *Response) Handler { return handlerFunc(f) } // Handle implements Handler. func (f handlerFunc) Handle(ctx context.Context, request *Request) *Response { return f(ctx, request) } // Middleware is a handler decorator. // // It returns a handler which may call the passed-in handler or not, or may // transform the request or response in some way. type Middleware func(Handler) Handler // FallthroughHandler builds a handler which tries multiple child handlers. // // The returned handler will invoke each of the passed-in handlers in order, // stopping when it receives a non-nil response. func FallthroughHandler(handlers ...Handler) Handler { return HandlerFunc(func(ctx context.Context, request *Request) *Response { for _, handler := range handlers { if response := handler.Handle(ctx, request); response != nil { return response } } return nil }) } // Filter builds a middleware which only calls the wrapped Handler under a condition. // // When the condition function returns false it instead invokes the test-failure // handler. The failure handler may also be nil, in which case the final handler will // return a nil response whenever the condition fails. func Filter( condition func(context.Context, *Request) bool, failure Handler, ) Middleware { return func(success Handler) Handler { return HandlerFunc(func(ctx context.Context, request *Request) *Response { if condition(ctx, request) { return success.Handle(ctx, request) } if failure == nil { return nil } return failure.Handle(ctx, request) }) } } // VirtualHosts builds a handler which dispatches to site handlers by hostname. // // The 'catchall' argument may be used to specify a handler for use when no hostname // match is found. If the catchall is nil and no match is found, the VirtualHosts // handler returns a nil response. func VirtualHosts(hosts map[string]Handler, catchall Handler) Handler { return HandlerFunc(func(ctx context.Context, request *Request) *Response { if h := hosts[request.Hostname()]; h != nil { return h.Handle(ctx, request) } if catchall != nil { return catchall.Handle(ctx, request) } return nil }) }