-
Notifications
You must be signed in to change notification settings - Fork 11
/
context.go
186 lines (161 loc) · 5.78 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
181
182
183
184
185
186
package zebra
import (
"fmt"
"encoding/json"
"net/http"
"net/url"
)
type Handler func(*Context) error
type Handlers []Handler
// combineHandlers merges two lists of handlers into a new list.
func combineHandlers(h1 []Handler, h2 []Handler) []Handler {
hh := make([]Handler, len(h1)+len(h2))
copy(hh, h1)
copy(hh[len(h1):], h2)
return hh
}
// SerializeFunc serializes the given data of arbitrary type into a byte array.
type SerializeFunc func(data interface{}) ([]byte, error)
// Context represents the contextual data and environment while processing an incoming HTTP request.
type Context struct {
ResponseWriter http.ResponseWriter
Request *http.Request
Serialize SerializeFunc // the function serializing the given data of arbitrary type into a byte array.
data map[string]interface{} // data items managed by Get and Set
index int // the index of the currently executing handler in handlers
handlers []Handler // the handlers associated with the current route
//
attrs map[string]interface{}
attrKeys []string // list of route parameter names
attrValues []string // list of parameter values corresponding to pnames
}
func NewContext(w http.ResponseWriter, req *http.Request, handlers []Handler) *Context {
return &Context{
ResponseWriter: w,
Request: req,
handlers: handlers,
Serialize: func(data interface{}) ([]byte, error) {
return json.Marshal(data)
},
}
}
// Param returns the named parameter value that is found in the URL path matching the current route.
// If the named parameter cannot be found, an empty string will be returned.
func (c *Context) Attr(key string) string {
for i, n := range c.attrKeys {
if n == key {
return c.attrValues[i]
}
}
return ""
}
// GetCookie returns cookie's value by it's name
// returns empty string if nothing was found.
func (ctx *Context) Cookie(name string) string {
cookie, err := ctx.Request.Cookie(name)
if err != nil {
return ""
}
return cookie.Value
}
// Get returns the named data item previously registered with the context by calling Set.
// If the named data item cannot be found, nil will be returned.
func (c *Context) Get(name string) interface{} {
return c.data[name]
}
// Set stores the named data item in the context so that it can be retrieved later.
func (c *Context) Set(name string, value interface{}) {
if c.data == nil {
c.data = make(map[string]interface{})
}
c.data[name] = value
}
// Next calls the rest of the handlers associated with the current route.
// If any of these handlers returns an error, Next will return the error and skip the following handlers.
// Next is normally used when a handler needs to do some postprocessing after the rest of the handlers
// are executed.
func (c *Context) Next() error {
c.index++
for n := len(c.handlers); c.index < n; c.index++ {
if err := c.handlers[c.index](c); err != nil {
return err
}
}
return nil
}
// Abort skips the rest of the handlers associated with the current route.
// Abort is normally used when a handler handles the request normally and wants to skip the rest of the handlers.
// If a handler wants to indicate an error condition, it should simply return the error without calling Abort.
func (c *Context) Abort() {
c.index = len(c.handlers)
}
// WriteData writes the given data of arbitrary type to the response.
// The method calls the Serialize() method to convert the data into a byte array and then writes
// the byte array to the response.
func (c *Context) WriteData(data interface{}) (err error) {
var bytes []byte
if bytes, err = c.Serialize(data); err == nil {
_, err = c.ResponseWriter.Write(bytes)
}
return
}
func (c *Context) Write(data []byte) (int, error) {
return c.ResponseWriter.Write(data)
}
func (c *Context) WriteString(str string) (int, error) {
return c.ResponseWriter.Write([]byte(str))
}
// Method returns the request.Method, the client's http method to the server.
func (ctx *Context) Method() string {
return ctx.Request.Method
}
// Path returns the full request path,
// escaped if EnablePathEscape config field is true.
func (ctx *Context) Path() string {
return ctx.Request.URL.Path
}
// SetStatusCode sets response status code.
func (ctx *Context) SetStatusCode(statusCode int) {
ctx.ResponseWriter.WriteHeader(statusCode)
}
// SetContentType sets response Content-Type.
func (ctx *Context) SetContentType(contentType string) {
ctx.ResponseWriter.Header().Add("Content-Type", contentType)
}
// RequestURI returns RequestURI.
//
// This uri is valid until returning from RequestHandler.
func (ctx *Context) RequestURI() string {
return ctx.Request.RequestURI
}
// URI returns requested uri.
//
// The uri is valid until returning from RequestHandler.
func (ctx *Context) URL() *url.URL {
return ctx.Request.URL
}
// Referer returns request referer.
//
// The referer is valid until returning from RequestHandler.
func (ctx *Context) Referer() string {
return ctx.Request.Header.Get("referer")
}
// UserAgent returns User-Agent header value from the request.
func (ctx *Context) UserAgent() string {
return ctx.Request.UserAgent()
}
// Serialize converts the given data into a byte array.
// If the data is neither a byte array nor a string, it will call fmt.Sprint to convert it into a string.
func Serialize(data interface{}) (bytes []byte, err error) {
switch data.(type) {
case []byte:
return data.([]byte), nil
case string:
return []byte(data.(string)), nil
default:
if data != nil {
return []byte(fmt.Sprint(data)), nil
}
}
return nil, nil
}