-
Notifications
You must be signed in to change notification settings - Fork 0
/
interceptor.go
208 lines (176 loc) · 5.22 KB
/
interceptor.go
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// Copyright (c) 2019,CAO HONGJU. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package apirouter
import "net/http"
// Interceptor provides a hook to intercept the execution of the HTTP request handler.
type Interceptor interface {
// PreHandle achieve the preprocessing of the HTTP request handler (such as check login).
// return value:
// true - continue the process (such as calling the next interceptor or Handler);
// false - interrupte the process(such as the logon check fails)
// and will not continue to invoke other interceptors or Handler,
// in which case we need to generate a response through w.
PreHandle(w http.ResponseWriter, r *http.Request) bool
// PostHandle achieve the post-processing of the HTTP request handler.
PostHandle(r *http.Request)
}
var (
_ Interceptor = PreInterceptor(nil)
_ Interceptor = PostInterceptor(nil)
_ Interceptor = &chainInterceptor{}
nopIt Interceptor = nopInterceptor{}
)
// PreInterceptor provides a hook function to intercept before the HTTP request handler is executed.
type PreInterceptor func(w http.ResponseWriter, r *http.Request) bool
// PreHandle implements Intercetor.PreHandle.
func (f PreInterceptor) PreHandle(w http.ResponseWriter, r *http.Request) bool {
return f(w, r)
}
// PostHandle implements Intercetor.PostHandle with no-op.
func (f PreInterceptor) PostHandle(r *http.Request) {
return
}
// PostInterceptor provides a hook function to intercept after the HTTP request handler is executed.
type PostInterceptor func(r *http.Request)
// PreHandle implements Intercetor.PreHandle with no-op.
// It always returns true.
func (f PostInterceptor) PreHandle(w http.ResponseWriter, r *http.Request) bool {
return true
}
// PostHandle implements Intercetor.PostHandle.
func (f PostInterceptor) PostHandle(r *http.Request) {
f(r)
}
// nopInterceptor is a no-op Interceptor.
type nopInterceptor struct{}
func (nopInterceptor) PreHandle(w http.ResponseWriter, r *http.Request) bool { return true }
func (nopInterceptor) PostHandle(r *http.Request) {}
// NewInterceptor returns a new Interceptor.
func NewInterceptor(pre PreInterceptor, post PostInterceptor) Interceptor {
if pre == nil && post == nil {
return nopIt
}
if pre == nil {
return post
}
if post == nil {
return pre
}
return interceptor{pre, post}
}
type interceptor struct {
pre PreInterceptor
post PostInterceptor
}
func (it interceptor) PreHandle(w http.ResponseWriter, r *http.Request) bool {
return it.pre(w, r)
}
func (it interceptor) PostHandle(r *http.Request) {
it.post(r)
}
// ChainInterceptor creates a single interceptor out of a chain of many interceptors.
//
// PreHandle's Execution is done in left-to-right order.
// For example ChainInterceptor(one, two, three) will execute one before two before three, and three
// will see r changes of one and two.
// PostHandle's Execution is done in right-to-left order.
func ChainInterceptor(its ...Interceptor) Interceptor {
switch len(its) {
case 0:
return nopIt
case 1:
return its[0]
}
ci := &chainInterceptor{make([]Interceptor, 0, len(its))}
for _, it := range its {
ci.addInterceptor(it)
}
switch len(ci.its) {
case 0:
return nopIt
case 1:
return ci.its[0]
}
return ci
}
type chainInterceptor struct {
its []Interceptor
}
func (ci *chainInterceptor) addInterceptor(it Interceptor) {
if it == nil {
return
}
if subci, ok := it.(*chainInterceptor); ok {
ci.its = append(ci.its, subci.its...)
} else {
ci.its = append(ci.its, it)
}
}
func (ci *chainInterceptor) PreHandle(w http.ResponseWriter, r *http.Request) bool {
for _, it := range ci.its {
if !it.PreHandle(w, r) {
return false
}
}
return true
}
func (ci *chainInterceptor) PostHandle(r *http.Request) {
for i := len(ci.its) - 1; i >= 0; i-- {
it := ci.its[i]
it.PostHandle(r)
}
}
// Wrap wraps the hanndler with the interceptors and transforms it into a different handler
func Wrap(h Handler, interceptors ...Interceptor) Handler {
if len(interceptors) == 0 {
return h
}
it := ChainInterceptor(interceptors...)
if it == nopIt {
return h
}
return func(w http.ResponseWriter, r *http.Request, ps Params) {
if it.PreHandle(w, r) {
h(w, r, ps)
it.PostHandle(r)
}
}
}
// WrapHandler wraps the http.Handler with the interceptors and transforms it into a different http.Handler
func WrapHandler(h http.Handler, interceptors ...Interceptor) http.Handler {
if len(interceptors) == 0 {
return h
}
it := ChainInterceptor(interceptors...)
if it == nopIt {
return h
}
return wrapHandler{h, it}
}
type wrapHandler struct {
h http.Handler
it Interceptor
}
func (wh wrapHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if wh.it.PreHandle(w, r) {
wh.h.ServeHTTP(w, r)
wh.it.PostHandle(r)
}
}
// WrapHandlerFunc wraps the http.HandlerFunc with the interceptors and transforms it into a different http.HandlerFunc
func WrapHandlerFunc(h http.HandlerFunc, interceptors ...Interceptor) http.HandlerFunc {
if len(interceptors) == 0 {
return h
}
it := ChainInterceptor(interceptors...)
if it == nopIt {
return h
}
return func(w http.ResponseWriter, r *http.Request) {
if it.PreHandle(w, r) {
h(w, r)
it.PostHandle(r)
}
}
}