...
Source file src/net/http/httptest/recorder.go
1
2
3
4
5 package httptest
6
7 import (
8 "bytes"
9 "fmt"
10 "io/ioutil"
11 "net/http"
12 "strconv"
13 "strings"
14
15 "golang.org/x/net/http/httpguts"
16 )
17
18
19
20 type ResponseRecorder struct {
21
22
23
24
25
26
27 Code int
28
29
30
31
32
33
34
35 HeaderMap http.Header
36
37
38
39 Body *bytes.Buffer
40
41
42 Flushed bool
43
44 result *http.Response
45 snapHeader http.Header
46 wroteHeader bool
47 }
48
49
50 func NewRecorder() *ResponseRecorder {
51 return &ResponseRecorder{
52 HeaderMap: make(http.Header),
53 Body: new(bytes.Buffer),
54 Code: 200,
55 }
56 }
57
58
59
60 const DefaultRemoteAddr = "1.2.3.4"
61
62
63
64
65
66 func (rw *ResponseRecorder) Header() http.Header {
67 m := rw.HeaderMap
68 if m == nil {
69 m = make(http.Header)
70 rw.HeaderMap = m
71 }
72 return m
73 }
74
75
76
77
78
79
80
81
82 func (rw *ResponseRecorder) writeHeader(b []byte, str string) {
83 if rw.wroteHeader {
84 return
85 }
86 if len(str) > 512 {
87 str = str[:512]
88 }
89
90 m := rw.Header()
91
92 _, hasType := m["Content-Type"]
93 hasTE := m.Get("Transfer-Encoding") != ""
94 if !hasType && !hasTE {
95 if b == nil {
96 b = []byte(str)
97 }
98 m.Set("Content-Type", http.DetectContentType(b))
99 }
100
101 rw.WriteHeader(200)
102 }
103
104
105
106 func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
107 rw.writeHeader(buf, "")
108 if rw.Body != nil {
109 rw.Body.Write(buf)
110 }
111 return len(buf), nil
112 }
113
114
115
116 func (rw *ResponseRecorder) WriteString(str string) (int, error) {
117 rw.writeHeader(nil, str)
118 if rw.Body != nil {
119 rw.Body.WriteString(str)
120 }
121 return len(str), nil
122 }
123
124
125 func (rw *ResponseRecorder) WriteHeader(code int) {
126 if rw.wroteHeader {
127 return
128 }
129 rw.Code = code
130 rw.wroteHeader = true
131 if rw.HeaderMap == nil {
132 rw.HeaderMap = make(http.Header)
133 }
134 rw.snapHeader = rw.HeaderMap.Clone()
135 }
136
137
138
139 func (rw *ResponseRecorder) Flush() {
140 if !rw.wroteHeader {
141 rw.WriteHeader(200)
142 }
143 rw.Flushed = true
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 func (rw *ResponseRecorder) Result() *http.Response {
162 if rw.result != nil {
163 return rw.result
164 }
165 if rw.snapHeader == nil {
166 rw.snapHeader = rw.HeaderMap.Clone()
167 }
168 res := &http.Response{
169 Proto: "HTTP/1.1",
170 ProtoMajor: 1,
171 ProtoMinor: 1,
172 StatusCode: rw.Code,
173 Header: rw.snapHeader,
174 }
175 rw.result = res
176 if res.StatusCode == 0 {
177 res.StatusCode = 200
178 }
179 res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
180 if rw.Body != nil {
181 res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes()))
182 } else {
183 res.Body = http.NoBody
184 }
185 res.ContentLength = parseContentLength(res.Header.Get("Content-Length"))
186
187 if trailers, ok := rw.snapHeader["Trailer"]; ok {
188 res.Trailer = make(http.Header, len(trailers))
189 for _, k := range trailers {
190 k = http.CanonicalHeaderKey(k)
191 if !httpguts.ValidTrailerHeader(k) {
192
193 continue
194 }
195 vv, ok := rw.HeaderMap[k]
196 if !ok {
197 continue
198 }
199 vv2 := make([]string, len(vv))
200 copy(vv2, vv)
201 res.Trailer[k] = vv2
202 }
203 }
204 for k, vv := range rw.HeaderMap {
205 if !strings.HasPrefix(k, http.TrailerPrefix) {
206 continue
207 }
208 if res.Trailer == nil {
209 res.Trailer = make(http.Header)
210 }
211 for _, v := range vv {
212 res.Trailer.Add(strings.TrimPrefix(k, http.TrailerPrefix), v)
213 }
214 }
215 return res
216 }
217
218
219
220
221
222
223 func parseContentLength(cl string) int64 {
224 cl = strings.TrimSpace(cl)
225 if cl == "" {
226 return -1
227 }
228 n, err := strconv.ParseInt(cl, 10, 64)
229 if err != nil {
230 return -1
231 }
232 return n
233 }
234
View as plain text