1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
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
}
p := cs.pool
cs.pool = nil
p.release(cs)
}
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
}
|