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