-
Notifications
You must be signed in to change notification settings - Fork 10
/
middleware.go
165 lines (139 loc) · 4.71 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
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
package web
import (
"fmt"
"github.com/mylxsw/glacier/infra"
"net/http"
"strings"
"time"
"github.com/gorilla/sessions"
"github.com/pkg/errors"
)
// HandlerDecorator 该函数是http handler的装饰器
type HandlerDecorator func(WebHandler) WebHandler
// RequestMiddleware is a middleware collections
type RequestMiddleware struct{}
// NewRequestMiddleware create a new RequestMiddleware
func NewRequestMiddleware() RequestMiddleware {
return RequestMiddleware{}
}
// AccessLog create an access log middleware
func (rm RequestMiddleware) AccessLog(logger infra.Logger) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) Response {
startTs := time.Now()
resp := handler(ctx)
logger.Infof(
"[glacier] %s %s [%d] [%.4fms]",
ctx.Method(),
ctx.Request().Raw().URL.String(),
resp.Code(),
time.Since(startTs).Seconds()*1000,
)
return resp
}
}
}
type CustomAccessLog struct {
Context Context `json:"-"`
Method string `json:"method"`
URL string `json:"url"`
ResponseCode int `json:"response_code"`
Elapse time.Duration `json:"elapse"`
}
// CustomAccessLog create a custom access log handler middleware
func (rm RequestMiddleware) CustomAccessLog(fn func(cal CustomAccessLog)) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) Response {
startTs := time.Now()
resp := handler(ctx)
go fn(CustomAccessLog{
Context: ctx,
Method: ctx.Method(),
URL: ctx.Request().Raw().URL.String(),
ResponseCode: resp.Code(),
Elapse: time.Since(startTs),
})
return resp
}
}
}
// BeforeInterceptor is a interceptor intercept a request before processing
func (rm RequestMiddleware) BeforeInterceptor(fn func(ctx Context) Response) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) Response {
if resp := fn(ctx); resp != nil {
return resp
}
return handler(ctx)
}
}
}
// AfterInterceptor is a interceptor intercept a response before it's been sent to user
func (rm RequestMiddleware) AfterInterceptor(fn func(ctx Context, resp Response) Response) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) Response {
return fn(ctx, handler(ctx))
}
}
}
// CORS create a CORS middleware
func (rm RequestMiddleware) CORS(origin string) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) Response {
ctx.Response().Header("Access-Control-Allow-Origin", origin)
ctx.Response().Header("Access-Control-Allow-Headers", "*")
ctx.Response().Header("Access-Control-Allow-Methods", "GET,POST,OPTIONS,HEAD,PUT,PATCH,DELETE")
return handler(ctx)
}
}
}
// AuthHandler is a middleware for http auth
// typ is one of:
// Basic (see RFC 7617, base64-encoded credentials. See below for more information.),
// Bearer (see RFC 6750, bearer tokens to access OAuth 2.0-protected resources),
// Digest (see RFC 7616, only md5 hashing is supported in Firefox, see bug 472823 for SHA encryption support),
// HOBA (see RFC 7486, Section 3, HTTP Origin-Bound Authentication, digital-signature-based),
// Mutual (see RFC 8120),
// AWS4-HMAC-SHA256 (see AWS docs).
func (rm RequestMiddleware) AuthHandler(cb func(ctx Context, typ string, credential string) error) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) (resp Response) {
segs := strings.SplitN(ctx.Header("Authorization"), " ", 2)
if len(segs) != 2 {
return ctx.JSONError("auth failed: invalid auth header", http.StatusUnauthorized)
}
if !inStringArray(segs[0], []string{"Basic", "Bearer", "Digest", "HOBA", "Mutual", "AWS4-HMAC-SHA256"}) {
return ctx.JSONError("auth failed: invalid auth type", http.StatusUnauthorized)
}
if err := cb(ctx, segs[0], segs[1]); err != nil {
return ctx.JSONError(fmt.Sprintf("auth failed: %s", err), http.StatusUnauthorized)
}
return handler(ctx)
}
}
}
// Session is a middleware for session support
func (rm RequestMiddleware) Session(store sessions.Store, name string, options *sessions.Options) HandlerDecorator {
return func(handler WebHandler) WebHandler {
return func(ctx Context) Response {
session, _ := store.Get(ctx.Request().Raw(), name)
if options != nil {
session.Options = options
}
ctx.Request().SetSession(session)
resp := handler(ctx)
if err := session.Save(ctx.Request().Raw(), ctx.Response().Raw()); err != nil {
panic(errors.Wrap(err, "can not save session"))
}
return resp
}
}
}
func inStringArray(key string, items []string) bool {
for _, item := range items {
if item == key {
return true
}
}
return false
}