forked from derekdowling/go-json-spec-handler
-
Notifications
You must be signed in to change notification settings - Fork 1
/
middleware.go
113 lines (92 loc) · 3.35 KB
/
middleware.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
package goji
import (
"net/http"
"golang.org/x/net/context"
)
/*
Use appends a middleware to the Mux's middleware stack.
Middleware are composable pieces of functionality that augment Handlers. Common
examples of middleware include request loggers, authentication checkers, and
metrics gatherers.
Middleware are evaluated in the reverse order in which they were added, but the
resulting Handlers execute in "normal" order (i.e., the Handler returned by the
first Middleware to be added gets called first).
For instance, given middleware A, B, and C, added in that order, Goji's behavior
will look something like this:
augmentedHandler := A(B(C(yourHandler)))
augmentedHandler.ServeHTTPC(ctx, w, r)
Assuming each of A, B, and C look something like this:
func A(inner goji.Handler) goji.Handler {
log.Print("A: called")
mw := func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
log.Print("A: before")
inner.ServeHTTPC(ctx, w, r)
log.Print("A: after")
}
return goji.HandlerFunc(mw)
}
we'd expect to see the following in the log:
C: called
B: called
A: called
---
A: before
B: before
C: before
yourHandler: called
C: after
B: after
A: after
Note that augmentedHandler may be called many times. Put another way, you will
see many invocations of the portion of the log below the divider, and perhaps
only see the portion above the divider a single time. Also note that as an
implementation detail, net/http-style middleware will be called once per
request, even though the Goji-style middleware around them might only ever be
called a single time.
Middleware in Goji is called after routing has been performed. Therefore it is
possible to examine any routing information placed into the context by Patterns,
or to view or modify the Handler that will be routed to.
The http.Handler returned by the given middleware must be safe for concurrent
use by multiple goroutines. It is not safe to concurrently register middleware
from multiple goroutines.
*/
func (m *Mux) Use(middleware func(http.Handler) http.Handler) {
m.middleware = append(m.middleware, func(h Handler) Handler {
return outerBridge{middleware, h}
})
m.buildChain()
}
/*
UseC appends a context-aware middleware to the Mux's middleware stack. See the
documentation for Use for more information about the semantics of middleware.
The Handler returned by the given middleware must be safe for concurrent use by
multiple goroutines. It is not safe to concurrently register middleware from
multiple goroutines.
*/
func (m *Mux) UseC(middleware func(Handler) Handler) {
m.middleware = append(m.middleware, middleware)
m.buildChain()
}
// Pre-compile a Handler for us to use during dispatch. Yes, this means that
// adding middleware is quadratic, but it (a) happens during configuration time,
// not at "runtime", and (b) n should ~always be small.
func (m *Mux) buildChain() {
m.handler = dispatch{}
for i := len(m.middleware) - 1; i >= 0; i-- {
m.handler = m.middleware[i](m.handler)
}
}
type innerBridge struct {
inner Handler
ctx context.Context
}
func (b innerBridge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
b.inner.ServeHTTPC(b.ctx, w, r)
}
type outerBridge struct {
mware func(http.Handler) http.Handler
inner Handler
}
func (b outerBridge) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
b.mware(innerBridge{b.inner, ctx}).ServeHTTP(w, r)
}