-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontext.go
180 lines (158 loc) · 4.1 KB
/
context.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
package goapi
import (
"bufio"
"math"
"net"
"net/http"
"strings"
"sync"
"time"
)
type Context struct {
Request *http.Request
Writer http.ResponseWriter
writermem ResponseWriter
Values map[string]any
log Logger
mux sync.RWMutex
middlewares []Middleware
paths map[string]string
index int
fullPath string
mediaType string
handleServer *handlerServer
}
func (c *Context) reset() {
c.Writer = &c.writermem
c.Values = nil
c.middlewares = c.middlewares[:]
c.paths = nil
c.index = -1
c.fullPath = ""
}
func (c *Context) Deadline() (deadline time.Time, ok bool) {
if c.Request != nil && c.Request.Context() != nil {
return c.Request.Context().Deadline()
}
return
}
func (c *Context) Done() <-chan struct{} {
if c.Request != nil && c.Request.Context() != nil {
return c.Request.Context().Done()
}
return nil
}
func (c *Context) Err() error {
if c.Request != nil && c.Request.Context() != nil {
return c.Request.Context().Err()
}
return nil
}
// Set It is a method for setting context values
func (c *Context) Set(key string, value any) {
c.mux.Lock()
defer c.mux.Unlock()
if c.Values == nil {
c.Values = map[string]any{}
}
c.Values[key] = value
}
// Get It is a method for obtaining context values
func (c *Context) Get(key string) (value any, ok bool) {
c.mux.RLock()
defer c.mux.RUnlock()
value, ok = c.Values[key]
return
}
func (c *Context) Value(key any) any {
if k, ok := key.(string); ok {
if value, keyOk := c.Get(k); keyOk {
return value
}
}
if c.Request != nil && c.Request.Context() != nil {
return c.Request.Context().Value(key)
}
return nil
}
// FullPath returns a matched route full path. For not found routes
// returns an empty string.
func (c *Context) FullPath() string {
return c.fullPath
}
// Next It is used in middleware, before Next is before interface request, and after Next is after interface request
func (c *Context) Next() {
defer func() {
if err := recover(); err != nil {
c.index = math.MaxUint16
c.handleServer.handleException(c.Writer, err, c.mediaType)
}
}()
c.index++
for ; c.index < len(c.middlewares); c.index++ {
c.middlewares[c.index](c)
}
}
// Logger It is a method of obtaining logs
func (c *Context) Logger() Logger {
return c.log
}
// RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port).
func (c *Context) RemoteIP() string {
ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr))
if err != nil {
return ""
}
return ip
}
// ClientIP implements one best effort algorithm to return the real client IP.
// It is it will then try to parse the headers defined in http.Header (defaulting to [X-Forwarded-For, X-Real-Ip]).
// else the remote IP (coming from Request.RemoteAddr) is returned.
func (c *Context) ClientIP() string {
remoteIP := net.ParseIP(c.RemoteIP())
if remoteIP == nil {
return ""
}
if xForwardedFor := c.Request.Header.Get("X-Forwarded-For"); xForwardedFor != "" {
ip := net.ParseIP(strings.Split(xForwardedFor, ",")[0])
if ip != nil && ip.To4() != nil {
return ip.String()
}
}
if xRealIP := c.Request.Header.Get("X-Real-IP"); xRealIP != "" {
ip := net.ParseIP(strings.Split(xRealIP, ",")[0])
if ip != nil && ip.To4() != nil {
return ip.String()
}
}
return remoteIP.String()
}
type ResponseWriter struct {
http.ResponseWriter
status int
}
func (r *ResponseWriter) reset(w http.ResponseWriter) {
r.ResponseWriter = w
r.status = 200
}
// Hijack implements the http.Hijacker interface.
func (r *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return r.ResponseWriter.(http.Hijacker).Hijack()
}
// Flush implements the http.Flusher interface.
func (r *ResponseWriter) Flush() {
r.ResponseWriter.(http.Flusher).Flush()
}
func (r *ResponseWriter) Header() http.Header {
return r.ResponseWriter.Header()
}
func (r *ResponseWriter) Write(b []byte) (int, error) {
return r.ResponseWriter.Write(b)
}
func (r *ResponseWriter) WriteHeader(statusCode int) {
r.ResponseWriter.WriteHeader(statusCode)
r.status = statusCode
}
func (r *ResponseWriter) Status() int {
return r.status
}