-
Notifications
You must be signed in to change notification settings - Fork 7
/
response.go
152 lines (127 loc) · 3.21 KB
/
response.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
package vox
import (
"mime"
"net/http"
"net/url"
"path"
"strings"
)
var (
explicitSetBody = struct{}{}
explicitSetStatus = 0
)
var htmlReplacer = strings.NewReplacer(
"&", "&",
"<", "<",
">", ">",
`"`, """,
"'", "'",
)
func htmlEscape(s string) string {
return htmlReplacer.Replace(s)
}
// A Response object contains all the information which will written to current
// HTTP client.
type Response struct {
request *Request
// Don't write headers, status and body from Response struct to client. In
// the case of you're using the go's origin http.Response.
DontRespond bool
// Writer is the raw http.ResponseWriter for current request. You should
// assign the Body / Status / Header value instead of using this field.
Writer http.ResponseWriter
// Body is the container for HTTP response's body.
Body interface{}
// The status code which will respond as the HTTP Response's status code.
// 200 will be used as the default value if not set.
Status int
// Headers which will be written to the response.
Header http.Header
}
func (response *Response) setImplicitContentType() {
if response.Header.Get("Content-Type") != "" {
return
}
if response.Body == explicitSetBody {
return
}
switch response.Body.(type) {
case []byte:
case string:
default:
response.Header.Set("Content-Type", mime.TypeByExtension(".json"))
}
}
var parseURL = url.Parse
// Redirect request to another url.
func (response *Response) Redirect(url string, code int) {
request := response.request
if u, err := parseURL(url); err == nil {
if u.Scheme == "" && u.Host == "" {
oldpath := request.URL.Path
if oldpath == "" {
oldpath = "/"
}
if url == "" || url[0] != '/' {
olddir, _ := path.Split(oldpath)
url = olddir + url
}
var query string
if i := strings.Index(url, "?"); i != -1 {
url, query = url[:i], url[i:]
}
trailing := strings.HasSuffix(url, "/")
url = path.Clean(url)
if trailing && !strings.HasSuffix(url, "/") {
url += "/"
}
url += query
}
}
response.Header.Set("Location", url)
if request.Method == "GET" || request.Method == "HEAD" {
response.Header.Set("Content-Type", "text/html; charset=utf-8")
}
response.Status = code
if request.Method == "GET" {
response.Body = "<a href=\"" + htmlEscape(url) + "\">" + http.StatusText(code) + "</a>.\n"
}
}
// SetCookie sets cookies on response.
func (response *Response) SetCookie(cookie *http.Cookie) {
if v := cookie.String(); v != "" {
response.Header.Add("Set-Cookie", v)
}
}
func (response *Response) setImplicitBody() {
if response.Body == explicitSetBody {
response.Body = http.StatusText(404)
}
}
func (response *Response) setImplicitStatus() {
if response.Status != explicitSetStatus {
return
}
if response.Body == explicitSetBody {
response.Status = 404
return
}
if _, ok := response.Body.(error); ok {
response.Status = 500
return
}
response.Status = 200
}
func (response *Response) setImplicit() {
response.setImplicitContentType()
response.setImplicitStatus()
response.setImplicitBody()
}
func createResponse(rw http.ResponseWriter) *Response {
return &Response{
Writer: rw,
Body: explicitSetBody,
Status: explicitSetStatus,
Header: rw.Header(),
}
}