aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/zenazn/goji/web/middleware.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zenazn/goji/web/middleware.go')
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware.go154
1 files changed, 154 insertions, 0 deletions
diff --git a/vendor/github.com/zenazn/goji/web/middleware.go b/vendor/github.com/zenazn/goji/web/middleware.go
new file mode 100644
index 0000000..7ec545d
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware.go
@@ -0,0 +1,154 @@
+package web
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "sync"
+)
+
+// mLayer is a single middleware stack layer. It contains a canonicalized
+// middleware representation, as well as the original function as passed to us.
+type mLayer struct {
+ fn func(*C, http.Handler) http.Handler
+ orig interface{}
+}
+
+// mStack is an entire middleware stack. It contains a slice of middleware
+// layers (outermost first) protected by a mutex, a cache of pre-built stack
+// instances, and a final routing function.
+type mStack struct {
+ lock sync.Mutex
+ stack []mLayer
+ pool *cPool
+ router internalRouter
+}
+
+type internalRouter interface {
+ route(*C, http.ResponseWriter, *http.Request)
+}
+
+/*
+cStack is a cached middleware stack instance. Constructing a middleware stack
+involves a lot of allocations: at the very least each layer will have to close
+over the layer after (inside) it and a stack N levels deep will incur at least N
+separate allocations. Instead of doing this on every request, we keep a pool of
+pre-built stacks around for reuse.
+*/
+type cStack struct {
+ C
+ m http.Handler
+ pool *cPool
+}
+
+func (s *cStack) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ s.C = C{}
+ s.m.ServeHTTP(w, r)
+}
+func (s *cStack) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ s.C = c
+ s.m.ServeHTTP(w, r)
+}
+
+const unknownMiddleware = `Unknown middleware type %T. See http://godoc.org/github.com/zenazn/goji/web#MiddlewareType for a list of acceptable types.`
+
+func (m *mStack) appendLayer(fn interface{}) {
+ ml := mLayer{orig: fn}
+ switch f := fn.(type) {
+ case func(http.Handler) http.Handler:
+ ml.fn = func(c *C, h http.Handler) http.Handler {
+ return f(h)
+ }
+ case func(*C, http.Handler) http.Handler:
+ ml.fn = f
+ default:
+ log.Fatalf(unknownMiddleware, fn)
+ }
+ m.stack = append(m.stack, ml)
+}
+
+func (m *mStack) findLayer(l interface{}) int {
+ for i, middleware := range m.stack {
+ if funcEqual(l, middleware.orig) {
+ return i
+ }
+ }
+ return -1
+}
+
+func (m *mStack) invalidate() {
+ m.pool = makeCPool()
+}
+
+func (m *mStack) newStack() *cStack {
+ cs := cStack{}
+ router := m.router
+
+ cs.m = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ router.route(&cs.C, w, r)
+ })
+ for i := len(m.stack) - 1; i >= 0; i-- {
+ cs.m = m.stack[i].fn(&cs.C, cs.m)
+ }
+
+ return &cs
+}
+
+func (m *mStack) alloc() *cStack {
+ p := m.pool
+ cs := p.alloc()
+ if cs == nil {
+ cs = m.newStack()
+ }
+
+ cs.pool = p
+ return cs
+}
+
+func (m *mStack) release(cs *cStack) {
+ cs.C = C{}
+ if cs.pool != m.pool {
+ return
+ }
+ cs.pool.release(cs)
+ cs.pool = nil
+}
+
+func (m *mStack) Use(middleware interface{}) {
+ m.lock.Lock()
+ defer m.lock.Unlock()
+ m.appendLayer(middleware)
+ m.invalidate()
+}
+
+func (m *mStack) Insert(middleware, before interface{}) error {
+ m.lock.Lock()
+ defer m.lock.Unlock()
+ i := m.findLayer(before)
+ if i < 0 {
+ return fmt.Errorf("web: unknown middleware %v", before)
+ }
+
+ m.appendLayer(middleware)
+ inserted := m.stack[len(m.stack)-1]
+ copy(m.stack[i+1:], m.stack[i:])
+ m.stack[i] = inserted
+
+ m.invalidate()
+ return nil
+}
+
+func (m *mStack) Abandon(middleware interface{}) error {
+ m.lock.Lock()
+ defer m.lock.Unlock()
+ i := m.findLayer(middleware)
+ if i < 0 {
+ return fmt.Errorf("web: unknown middleware %v", middleware)
+ }
+
+ copy(m.stack[i:], m.stack[i+1:])
+ m.stack = m.stack[:len(m.stack)-1 : len(m.stack)]
+
+ m.invalidate()
+ return nil
+}