github.com/gotstago/buffalo@v0.9.5/middleware.go (about) 1 package buffalo 2 3 import ( 4 "reflect" 5 "runtime" 6 "strings" 7 ) 8 9 // MiddlewareFunc defines the interface for a piece of Buffalo 10 // Middleware. 11 /* 12 func DoSomething(next Handler) Handler { 13 return func(c Context) error { 14 // do something before calling the next handler 15 err := next(c) 16 // do something after call the handler 17 return err 18 } 19 } 20 */ 21 type MiddlewareFunc func(Handler) Handler 22 23 // Use the specified Middleware for the App. 24 // When defined on an `*App` the specified middleware will be 25 // inherited by any `Group` calls that are made on that on 26 // the App. 27 func (a *App) Use(mw ...MiddlewareFunc) { 28 a.Middleware.Use(mw...) 29 } 30 31 // MiddlewareStack manages the middleware stack for an App/Group. 32 type MiddlewareStack struct { 33 stack []MiddlewareFunc 34 skips map[string]bool 35 } 36 37 func (ms MiddlewareStack) String() string { 38 s := []string{} 39 for _, m := range ms.stack { 40 s = append(s, funcKey(m)) 41 } 42 43 return strings.Join(s, "\n") 44 } 45 46 func (ms *MiddlewareStack) clone() *MiddlewareStack { 47 n := newMiddlewareStack() 48 n.stack = append(n.stack, ms.stack...) 49 for k, v := range ms.skips { 50 n.skips[k] = v 51 } 52 return n 53 } 54 55 // Clear wipes out the current middleware stack for the App/Group, 56 // any middleware previously defined will be removed leaving an empty 57 // middleware stack. 58 func (ms *MiddlewareStack) Clear() { 59 ms.stack = []MiddlewareFunc{} 60 ms.skips = map[string]bool{} 61 } 62 63 // Use the specified Middleware for the App. 64 // When defined on an `*App` the specified middleware will be 65 // inherited by any `Group` calls that are made on that on 66 // the App. 67 func (ms *MiddlewareStack) Use(mw ...MiddlewareFunc) { 68 ms.stack = append(ms.stack, mw...) 69 } 70 71 // Skip a specified piece of middleware the specified Handlers. 72 // This is useful for things like wrapping your application in an 73 // authorization middleware, but skipping it for things the home 74 // page, the login page, etc... 75 /* 76 a.Middleware.Skip(Authorization, HomeHandler, LoginHandler, RegistrationHandler) 77 */ 78 func (ms *MiddlewareStack) Skip(mw MiddlewareFunc, handlers ...Handler) { 79 for _, h := range handlers { 80 key := funcKey(mw, h) 81 ms.skips[key] = true 82 } 83 } 84 85 // Replace a piece of middleware with another piece of middleware. Great for 86 // testing. 87 func (ms *MiddlewareStack) Replace(mw1 MiddlewareFunc, mw2 MiddlewareFunc) { 88 m1k := funcKey(mw1) 89 stack := []MiddlewareFunc{} 90 for _, mw := range ms.stack { 91 if funcKey(mw) == m1k { 92 stack = append(stack, mw2) 93 } else { 94 stack = append(stack, mw) 95 } 96 } 97 ms.stack = stack 98 } 99 100 func (ms *MiddlewareStack) handler(info RouteInfo) Handler { 101 h := info.Handler 102 if len(ms.stack) > 0 { 103 mh := func(_ Handler) Handler { 104 return h 105 } 106 107 tstack := []MiddlewareFunc{mh} 108 109 sl := len(ms.stack) - 1 110 for i := sl; i >= 0; i-- { 111 mw := ms.stack[i] 112 key := funcKey(mw, info) 113 if !ms.skips[key] { 114 tstack = append(tstack, mw) 115 } 116 } 117 118 for _, mw := range tstack { 119 h = mw(h) 120 } 121 return h 122 } 123 return h 124 } 125 126 func newMiddlewareStack(mws ...MiddlewareFunc) *MiddlewareStack { 127 return &MiddlewareStack{ 128 stack: mws, 129 skips: map[string]bool{}, 130 } 131 } 132 133 func funcKey(funcs ...interface{}) string { 134 names := []string{} 135 for _, f := range funcs { 136 if n, ok := f.(RouteInfo); ok { 137 names = append(names, n.HandlerName) 138 continue 139 } 140 rv := reflect.ValueOf(f) 141 ptr := rv.Pointer() 142 if n, ok := keyMap[ptr]; ok { 143 names = append(names, n) 144 continue 145 } 146 n := ptrName(ptr) 147 keyMap[ptr] = n 148 names = append(names, n) 149 } 150 return strings.Join(names, "/") 151 } 152 153 func ptrName(ptr uintptr) string { 154 fnc := runtime.FuncForPC(ptr) 155 n := fnc.Name() 156 157 n = strings.Replace(n, "-fm", "", 1) 158 n = strings.Replace(n, "(", "", 1) 159 n = strings.Replace(n, ")", "", 1) 160 return n 161 } 162 163 func setFuncKey(f interface{}, name string) { 164 rv := reflect.ValueOf(f) 165 if rv.Kind() == reflect.Ptr { 166 rv = rv.Elem() 167 } 168 ptr := rv.Pointer() 169 keyMap[ptr] = name 170 } 171 172 var keyMap = map[uintptr]string{}