-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcontext.go
149 lines (123 loc) · 3.07 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
package otto
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)
// Context defines interface for otto Context
type Context interface {
JSON(int, interface{}) error
HTML(int, string) error
String(int, string) error
Error(int, error) error
NoContent() error
Redirect(code int, location string) error
Request() *http.Request
Response() *Response
FormParams() (*ValueParams, error)
QueryParams() *ValueParams
QueryString() string
Bind(interface{}) error
Params() Params
Set(key string, val interface{})
Get(key string) interface{}
}
// Store is a generic map
type Store map[string]interface{}
type context struct {
res *Response
req *http.Request
charset string
query url.Values
bindFunc BindFunc
store map[string]interface{}
}
func (c *context) Request() *http.Request {
return c.req
}
func (c *context) Response() *Response {
return c.res
}
func (c *context) JSON(code int, val interface{}) error {
b, err := json.Marshal(val)
if err != nil {
return errors.Wrap(err, "failed to parse json")
}
return c.render(code, "application/json", b)
}
func (c *context) HTML(code int, val string) error {
return c.render(code, "text/html", []byte(val))
}
func (c *context) String(code int, val string) error {
return c.render(code, "text/plain", []byte(val))
}
func (c *context) Error(code int, err error) error {
if err == nil {
return nil
}
return HTTPError{
Code: code,
Err: err,
}
}
func (c *context) NoContent() error {
return c.render(http.StatusNoContent, "", []byte{})
}
func (c *context) Redirect(code int, location string) error {
if (code < 300 || code > 308) && code != 201 {
return errors.New("invalid redirect status code")
}
c.res.Header().Set(HeaderLocation, location)
return c.render(code, "", []byte{})
}
func (c *context) FormParams() (*ValueParams, error) {
if err := c.parseForm(); err != nil {
return nil, errors.Wrap(err, "failed to parse form from request")
}
return &ValueParams{vals: c.req.Form}, nil
}
func (c *context) QueryParams() *ValueParams {
if c.query == nil {
c.query = c.req.URL.Query()
}
return &ValueParams{vals: c.query}
}
func (c *context) QueryString() string {
return c.req.URL.RawQuery
}
func (c *context) Bind(dest interface{}) error {
return c.bindFunc(c, dest)
}
func (c *context) Params() Params {
return Params(mux.Vars(c.req))
}
func (c *context) Set(key string, val interface{}) {
if c.store == nil {
c.store = make(Store)
}
c.store[key] = val
}
func (c *context) Get(key string) interface{} {
return c.store[key]
}
func (c *context) render(code int, ct string, b []byte) error {
if ct != "" {
c.res.Header().Set(HeaderContentType, fmt.Sprintf("%s; charset=%s", ct, c.charset))
}
c.res.WriteHeader(code)
_, err := c.res.Write(b)
if err != nil {
return errors.Wrap(err, "failed to write body to response")
}
return nil
}
func (c *context) parseForm() error {
if strings.Contains(c.req.Header.Get(HeaderContentType), MIMEMultipartForm) {
return c.req.ParseMultipartForm(30 << 20) // 32MB
}
return c.req.ParseForm()
}