aeb17182b4
Signed-off-by: Emile Vauge <emile@vauge.com>
141 lines
4.3 KiB
Go
141 lines
4.3 KiB
Go
package negroni
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
)
|
|
|
|
// Handler handler is an interface that objects can implement to be registered to serve as middleware
|
|
// in the Negroni middleware stack.
|
|
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
|
|
// passed in.
|
|
//
|
|
// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
|
|
type Handler interface {
|
|
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
|
}
|
|
|
|
// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
|
|
// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
|
|
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
|
|
|
func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
h(rw, r, next)
|
|
}
|
|
|
|
type middleware struct {
|
|
handler Handler
|
|
next *middleware
|
|
}
|
|
|
|
func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|
m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
|
|
}
|
|
|
|
// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
|
|
// middleware. The next http.HandlerFunc is automatically called after the Handler
|
|
// is executed.
|
|
func Wrap(handler http.Handler) Handler {
|
|
return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
|
handler.ServeHTTP(rw, r)
|
|
next(rw, r)
|
|
})
|
|
}
|
|
|
|
// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
|
|
// Negroni middleware is evaluated in the order that they are added to the stack using
|
|
// the Use and UseHandler methods.
|
|
type Negroni struct {
|
|
middleware middleware
|
|
handlers []Handler
|
|
}
|
|
|
|
// New returns a new Negroni instance with no middleware preconfigured.
|
|
func New(handlers ...Handler) *Negroni {
|
|
return &Negroni{
|
|
handlers: handlers,
|
|
middleware: build(handlers),
|
|
}
|
|
}
|
|
|
|
// With returns a new Negroni instance that is a combination of the negroni
|
|
// receiver's handlers and the provided handlers.
|
|
func (n *Negroni) With(handlers ...Handler) *Negroni {
|
|
return New(
|
|
append(n.handlers, handlers...)...,
|
|
)
|
|
}
|
|
|
|
// Classic returns a new Negroni instance with the default middleware already
|
|
// in the stack.
|
|
//
|
|
// Recovery - Panic Recovery Middleware
|
|
// Logger - Request/Response Logging
|
|
// Static - Static File Serving
|
|
func Classic() *Negroni {
|
|
return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
|
|
}
|
|
|
|
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
|
|
}
|
|
|
|
// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
|
func (n *Negroni) Use(handler Handler) {
|
|
if handler == nil {
|
|
panic("handler cannot be nil")
|
|
}
|
|
|
|
n.handlers = append(n.handlers, handler)
|
|
n.middleware = build(n.handlers)
|
|
}
|
|
|
|
// UseFunc adds a Negroni-style handler function onto the middleware stack.
|
|
func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
|
|
n.Use(HandlerFunc(handlerFunc))
|
|
}
|
|
|
|
// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
|
func (n *Negroni) UseHandler(handler http.Handler) {
|
|
n.Use(Wrap(handler))
|
|
}
|
|
|
|
// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack.
|
|
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
|
|
n.UseHandler(http.HandlerFunc(handlerFunc))
|
|
}
|
|
|
|
// Run is a convenience function that runs the negroni stack as an HTTP
|
|
// server. The addr string takes the same format as http.ListenAndServe.
|
|
func (n *Negroni) Run(addr string) {
|
|
l := log.New(os.Stdout, "[negroni] ", 0)
|
|
l.Printf("listening on %s", addr)
|
|
l.Fatal(http.ListenAndServe(addr, n))
|
|
}
|
|
|
|
// Returns a list of all the handlers in the current Negroni middleware chain.
|
|
func (n *Negroni) Handlers() []Handler {
|
|
return n.handlers
|
|
}
|
|
|
|
func build(handlers []Handler) middleware {
|
|
var next middleware
|
|
|
|
if len(handlers) == 0 {
|
|
return voidMiddleware()
|
|
} else if len(handlers) > 1 {
|
|
next = build(handlers[1:])
|
|
} else {
|
|
next = voidMiddleware()
|
|
}
|
|
|
|
return middleware{handlers[0], &next}
|
|
}
|
|
|
|
func voidMiddleware() middleware {
|
|
return middleware{
|
|
HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
|
|
&middleware{},
|
|
}
|
|
}
|