1package negroni 2 3import ( 4 "log" 5 "net/http" 6 "os" 7) 8 9// Handler handler is an interface that objects can implement to be registered to serve as middleware 10// in the Negroni middleware stack. 11// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc 12// passed in. 13// 14// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked. 15type Handler interface { 16 ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) 17} 18 19// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers. 20// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f. 21type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) 22 23func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 24 h(rw, r, next) 25} 26 27type middleware struct { 28 handler Handler 29 next *middleware 30} 31 32func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) { 33 m.handler.ServeHTTP(rw, r, m.next.ServeHTTP) 34} 35 36// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni 37// middleware. The next http.HandlerFunc is automatically called after the Handler 38// is executed. 39func Wrap(handler http.Handler) Handler { 40 return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 41 handler.ServeHTTP(rw, r) 42 next(rw, r) 43 }) 44} 45 46// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler. 47// Negroni middleware is evaluated in the order that they are added to the stack using 48// the Use and UseHandler methods. 49type Negroni struct { 50 middleware middleware 51 handlers []Handler 52} 53 54// New returns a new Negroni instance with no middleware preconfigured. 55func New(handlers ...Handler) *Negroni { 56 return &Negroni{ 57 handlers: handlers, 58 middleware: build(handlers), 59 } 60} 61 62// Classic returns a new Negroni instance with the default middleware already 63// in the stack. 64// 65// Recovery - Panic Recovery Middleware 66// Logger - Request/Response Logging 67// Static - Static File Serving 68func Classic() *Negroni { 69 return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public"))) 70} 71 72func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) { 73 n.middleware.ServeHTTP(NewResponseWriter(rw), r) 74} 75 76// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. 77func (n *Negroni) Use(handler Handler) { 78 n.handlers = append(n.handlers, handler) 79 n.middleware = build(n.handlers) 80} 81 82// UseFunc adds a Negroni-style handler function onto the middleware stack. 83func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) { 84 n.Use(HandlerFunc(handlerFunc)) 85} 86 87// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. 88func (n *Negroni) UseHandler(handler http.Handler) { 89 n.Use(Wrap(handler)) 90} 91 92// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack. 93func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) { 94 n.UseHandler(http.HandlerFunc(handlerFunc)) 95} 96 97// Run is a convenience function that runs the negroni stack as an HTTP 98// server. The addr string takes the same format as http.ListenAndServe. 99func (n *Negroni) Run(addr string) { 100 l := log.New(os.Stdout, "[negroni] ", 0) 101 l.Printf("listening on %s", addr) 102 l.Fatal(http.ListenAndServe(addr, n)) 103} 104 105// Returns a list of all the handlers in the current Negroni middleware chain. 106func (n *Negroni) Handlers() []Handler { 107 return n.handlers 108} 109 110func build(handlers []Handler) middleware { 111 var next middleware 112 113 if len(handlers) == 0 { 114 return voidMiddleware() 115 } else if len(handlers) > 1 { 116 next = build(handlers[1:]) 117 } else { 118 next = voidMiddleware() 119 } 120 121 return middleware{handlers[0], &next} 122} 123 124func voidMiddleware() middleware { 125 return middleware{ 126 HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}), 127 &middleware{}, 128 } 129} 130