-
Notifications
You must be signed in to change notification settings - Fork 0
/
context.go
131 lines (108 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
package httpserve
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
// newContext will initialize and return a new Context
func newContext(w http.ResponseWriter, r *http.Request, p Params) *Context {
var c Context
// Initialize internal storage
c.s = make(Storage)
// Associate provided http.ResponseWriter
c.Writer = w
// Associate provided *http.Request
c.Request = r
// Associate provided httprouter.Params
c.Params = p
return &c
}
// Context is the request context
type Context struct {
// Internal context storage, used by Context.Get and Context.Put
s Storage
// hooks are a list of hook functions added during the lifespam of the context
hooks []Hook
Writer http.ResponseWriter
Request *http.Request
Params Params
}
func (c *Context) getResponse(hs []Handler) (resp Response) {
// Iterate through the provided handlers
for _, h := range hs {
// Call handler and pass Context
if resp = h(c); resp != nil {
// A non-nil response was provided, return
return
}
}
return
}
func (c *Context) respond(resp Response) {
// Response is nil, no further action is needed
if resp == nil {
return
}
if c.redirect(resp) {
return
}
// Write content type!
c.Writer.Header().Set("Content-Type", resp.ContentType())
// Write status code to header
c.Writer.WriteHeader(resp.StatusCode())
// Write response to http.ResponseWriter
if _, err := resp.WriteTo(c.Writer); err != nil {
// Write error to stderr
fmt.Fprintf(os.Stderr, "Error writing to http.ResponseWriter: %v\n", err)
}
}
func (c *Context) redirect(resp Response) (ok bool) {
var redirect *RedirectResponse
if redirect, ok = resp.(*RedirectResponse); !ok {
return
}
c.Writer.Header().Add("Location", redirect.url)
c.Writer.WriteHeader(redirect.code)
return
}
func (c *Context) wasAdopted(resp Response) (ok bool) {
if _, ok = resp.(*AdoptResponse); !ok {
return
}
return
}
func (c *Context) processHooks(statusCode int) {
for i := len(c.hooks) - 1; i > -1; i-- {
c.hooks[i](statusCode, c.s)
}
}
// Write will write a byteslice
func (c *Context) Write(bs []byte) (n int, err error) {
return c.Writer.Write(bs)
}
// WriteString will write a string
func (c *Context) WriteString(str string) (n int, err error) {
return c.Writer.Write([]byte(str))
}
// Param will return the associated parameter value with the provided key
func (c *Context) Param(key string) (value string) {
return c.Params.ByName(key)
}
// Get will retrieve a value for a provided key from the Context's internal storage
func (c *Context) Get(key string) (value string) {
return c.s[key]
}
// Put will set a value for a provided key into the Context's internal storage
func (c *Context) Put(key, value string) {
c.s[key] = value
}
// BindJSON is a helper function which binds the request body to a provided value to be parsed as JSON
func (c *Context) BindJSON(value interface{}) (err error) {
defer c.Request.Body.Close()
return json.NewDecoder(c.Request.Body).Decode(value)
}
// AddHook will add a hook function to be ran after the context has completed
func (c *Context) AddHook(fn Hook) {
c.hooks = append(c.hooks, fn)
}