-
Notifications
You must be signed in to change notification settings - Fork 30
/
middleware.go
163 lines (146 loc) · 3.97 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
package golf
import (
"fmt"
"io"
"log"
"net/http/httputil"
"time"
)
// MiddlewareHandlerFunc defines the middleware function type that Golf uses.
type MiddlewareHandlerFunc func(next HandlerFunc) HandlerFunc
// Chain contains a sequence of middlewares.
type Chain struct {
middlewareHandlers []MiddlewareHandlerFunc
}
// NewChain Creates a new middleware chain.
func NewChain(handlerArray ...MiddlewareHandlerFunc) *Chain {
c := new(Chain)
c.middlewareHandlers = handlerArray
return c
}
// Final indicates a final Handler, chain the multiple middlewares together with the
// handler, and return them together as a handler.
func (c Chain) Final(fn HandlerFunc) HandlerFunc {
for i := len(c.middlewareHandlers) - 1; i >= 0; i-- {
fn = c.middlewareHandlers[i](fn)
}
return fn
}
// Append a middleware to the middleware chain
func (c *Chain) Append(fn MiddlewareHandlerFunc) {
c.middlewareHandlers = append(c.middlewareHandlers, fn)
}
var (
green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
reset = string([]byte{27, 91, 48, 109})
)
// LoggingMiddleware is the built-in middleware for logging.
// This method is referred from https://github.com/gin-gonic/gin/blob/develop/logger.go#L46
func LoggingMiddleware(out io.Writer) MiddlewareHandlerFunc {
return func(next HandlerFunc) HandlerFunc {
fn := func(ctx *Context) {
start := time.Now()
path := ctx.Request.URL.Path
next(ctx)
end := time.Now()
latency := end.Sub(start)
clientIP := ctx.ClientIP()
method := ctx.Request.Method
statusCode := ctx.statusCode
statusColor := colorForStatus(statusCode)
methodColor := colorForMethod(method)
fmt.Fprintf(out, "%v |%s %3d %s| %13v | %s |%s %s %-7s %s\n",
end.Format("2006/01/02 - 15:04:05"),
statusColor, statusCode, reset,
latency,
clientIP,
methodColor, reset, method,
path,
)
}
return fn
}
}
func colorForStatus(code int) string {
switch {
case code >= 200 && code < 300:
return green
case code >= 300 && code < 400:
return white
case code >= 400 && code < 500:
return yellow
default:
return red
}
}
func colorForMethod(method string) string {
switch method {
case "GET":
return blue
case "POST":
return cyan
case "PUT":
return yellow
case "DELETE":
return red
case "PATCH":
return green
case "HEAD":
return magenta
case "OPTIONS":
return white
default:
return reset
}
}
// XSRFProtectionMiddleware is the built-in middleware for XSRF protection.
func XSRFProtectionMiddleware(next HandlerFunc) HandlerFunc {
fn := func(ctx *Context) {
if ctx.Request.Method == "POST" || ctx.Request.Method == "PUT" || ctx.Request.Method == "DELETE" {
if !ctx.checkXSRFToken() {
ctx.Abort(403)
return
}
}
next(ctx)
}
return fn
}
// RecoverMiddleware is the built-in middleware for recovering from errors.
func RecoverMiddleware(next HandlerFunc) HandlerFunc {
fn := func(ctx *Context) {
defer func() {
if err := recover(); err != nil {
e := NewError(err)
httpRequest, _ := httputil.DumpRequest(ctx.Request, true)
log.Printf("[Recovery] panic recovered:\n%s\n%s\n%s", string(httpRequest), err, e.StackTraceString())
ctx.statusCode = 500
ctx.Abort(500, map[string]interface{}{
"Code": ctx.statusCode,
"Title": "Internal Server Error",
"HTTPRequest": string(httpRequest),
"Message": e.Error(),
"StackTrace": e.Stack,
})
}
}()
next(ctx)
}
return fn
}
// SessionMiddleware handles session of the request
func SessionMiddleware(next HandlerFunc) HandlerFunc {
fn := func(ctx *Context) {
if ctx.App.SessionManager != nil {
ctx.retrieveSession()
}
next(ctx)
}
return fn
}