Merge lp:~pedronis/ubuntu-push/http13client into lp:ubuntu-push
- http13client
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Merged |
---|---|
Approved by: | Samuele Pedroni |
Approved revision: | 92 |
Merged at revision: | 82 |
Proposed branch: | lp:~pedronis/ubuntu-push/http13client |
Merge into: | lp:ubuntu-push |
Diff against target: |
18096 lines (+17900/-0) 39 files modified
http13client/LICENSE (+27/-0) http13client/Makefile (+37/-0) http13client/_patches/empty_server.patch (+4719/-0) http13client/_patches/fix_code.patch (+739/-0) http13client/_patches/fix_status.patch (+118/-0) http13client/_patches/fix_tests.patch (+1603/-0) http13client/_patches/no_keepalive.patch (+11/-0) http13client/_patches/no_serve_test_unsupported_bench.patch (+46/-0) http13client/_patches/sync_pool.Rpatch (+172/-0) http13client/_patches/tweak_doc_go.patch (+43/-0) http13client/_using.txt (+5/-0) http13client/chunked.go (+203/-0) http13client/chunked_test.go (+159/-0) http13client/client.go (+480/-0) http13client/client_test.go (+879/-0) http13client/cookie.go (+313/-0) http13client/cookie_test.go (+304/-0) http13client/doc.go (+56/-0) http13client/export_test.go (+62/-0) http13client/header.go (+49/-0) http13client/header_test.go (+213/-0) http13client/lex.go (+96/-0) http13client/lex_test.go (+31/-0) http13client/npn_test.go (+119/-0) http13client/proxy_test.go (+81/-0) http13client/readrequest_test.go (+332/-0) http13client/request.go (+865/-0) http13client/request_test.go (+571/-0) http13client/requestwrite_test.go (+566/-0) http13client/response.go (+244/-0) http13client/response_test.go (+629/-0) http13client/responsewrite_test.go (+111/-0) http13client/serve_test.go (+58/-0) http13client/server.go (+68/-0) http13client/transfer.go (+699/-0) http13client/transfer_test.go (+64/-0) http13client/transport.go (+1137/-0) http13client/transport_test.go (+1894/-0) http13client/z_last_test.go (+97/-0) |
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/http13client |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John Lenton (community) | Approve | ||
Review via email:
|
Commit message
vendor the go 1.3 development net/http bits which properly/better support timeouts for requests; see _using.txt and Makefile for the recipe in http13client
Description of the change
vendor the go 1.3 development net/http bits which properly/better support timeouts for requests,
added as a http13client package directory (package still named http, though typically it would be imported as http13)
_using.txt records the starting point,
the Makefile and _patches directory captures the required massaging
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'http13client' |
2 | === added file 'http13client/LICENSE' |
3 | --- http13client/LICENSE 1970-01-01 00:00:00 +0000 |
4 | +++ http13client/LICENSE 2014-03-20 12:26:55 +0000 |
5 | @@ -0,0 +1,27 @@ |
6 | +Copyright (c) 2012 The Go Authors. All rights reserved. |
7 | + |
8 | +Redistribution and use in source and binary forms, with or without |
9 | +modification, are permitted provided that the following conditions are |
10 | +met: |
11 | + |
12 | + * Redistributions of source code must retain the above copyright |
13 | +notice, this list of conditions and the following disclaimer. |
14 | + * Redistributions in binary form must reproduce the above |
15 | +copyright notice, this list of conditions and the following disclaimer |
16 | +in the documentation and/or other materials provided with the |
17 | +distribution. |
18 | + * Neither the name of Google Inc. nor the names of its |
19 | +contributors may be used to endorse or promote products derived from |
20 | +this software without specific prior written permission. |
21 | + |
22 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 | +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
24 | +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
25 | +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
26 | +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
27 | +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
28 | +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
29 | +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
30 | +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
31 | +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
32 | +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | |
34 | === added file 'http13client/Makefile' |
35 | --- http13client/Makefile 1970-01-01 00:00:00 +0000 |
36 | +++ http13client/Makefile 2014-03-20 12:26:55 +0000 |
37 | @@ -0,0 +1,37 @@ |
38 | +# help massage and extract from go development 1.3 net/http the client bits |
39 | + |
40 | +grab: |
41 | + cp $(GOCHECKOUT)/src/pkg/net/http/*.go . |
42 | + cp $(GOCHECKOUT)/LICENSE . |
43 | + mkdir -p httptest |
44 | + mkdir -p httputil |
45 | + mkdir -p testdata |
46 | + cp $(GOCHECKOUT)/src/pkg/net/http/httptest/*.go httptest |
47 | + cp $(GOCHECKOUT)/src/pkg/net//http/httputil/*.go httputil |
48 | + cp $(GOCHECKOUT)/src/pkg/net/http/testdata/* testdata |
49 | + hg -R $(GOCHECKOUT) summary > _using.txt |
50 | + |
51 | +full-prepare: |
52 | + patch -R -p5 < _patches/sync_pool.Rpatch |
53 | + patch -p1 < _patches/no_keepalive.patch |
54 | + sed -i -e 's+"net/http"+"launchpad.net/ubuntu-push/http13client"+' *.go httptest/*.go httputil/*.go |
55 | + sed -i -e 's+"net/http/+"launchpad.net/ubuntu-push/http13client/+' *.go httptest/*.go httputil/*.go |
56 | + patch -p1 < _patches/no_serve_test_unsupported_bench.patch |
57 | + |
58 | +prune: |
59 | + rm -rf example_test.go filetransport*.go fs*.go race.go range_test.go \ |
60 | + sniff*.go httptest httputil testdata triv.go jar.go status.go |
61 | + sed -i -e 's+"launchpad.net/ubuntu-push/http13client/+"net/http/+' *.go |
62 | + |
63 | +fix: |
64 | + patch -p1 < _patches/empty_server.patch |
65 | + patch -p1 < _patches/fix_tests.patch |
66 | + patch -p1 < _patches/fix_code.patch |
67 | + patch -p1 < _patches/fix_status.patch |
68 | + patch -p1 < _patches/tweak_doc_go.patch |
69 | + go fmt |
70 | + |
71 | +wipe: |
72 | + rm -rf *.go httptest httputil testdata |
73 | + |
74 | +.PHONY: grab full-prepare prune fix wipe |
75 | |
76 | === added directory 'http13client/_patches' |
77 | === added file 'http13client/_patches/empty_server.patch' |
78 | --- http13client/_patches/empty_server.patch 1970-01-01 00:00:00 +0000 |
79 | +++ http13client/_patches/empty_server.patch 2014-03-20 12:26:55 +0000 |
80 | @@ -0,0 +1,4719 @@ |
81 | +=== modified file 'http13client/serve_test.go' |
82 | +--- http13client/serve_test.go 2014-03-19 21:38:56 +0000 |
83 | ++++ http13client/serve_test.go 2014-03-19 22:27:37 +0000 |
84 | +@@ -2,60 +2,15 @@ |
85 | + // Use of this source code is governed by a BSD-style |
86 | + // license that can be found in the LICENSE file. |
87 | + |
88 | +-// End-to-end serving tests |
89 | +- |
90 | + package http_test |
91 | + |
92 | + import ( |
93 | +- "bufio" |
94 | +- "bytes" |
95 | +- "crypto/tls" |
96 | +- "errors" |
97 | +- "fmt" |
98 | + "io" |
99 | +- "io/ioutil" |
100 | +- "log" |
101 | + "net" |
102 | +- . "launchpad.net/ubuntu-push/http13client" |
103 | +- "net/http/httptest" |
104 | +- "net/http/httputil" |
105 | +- "net/url" |
106 | +- "os" |
107 | +- "os/exec" |
108 | +- "reflect" |
109 | +- "runtime" |
110 | +- "strconv" |
111 | +- "strings" |
112 | +- "sync" |
113 | +- "sync/atomic" |
114 | +- "syscall" |
115 | +- "testing" |
116 | + "time" |
117 | + ) |
118 | + |
119 | + type dummyAddr string |
120 | +-type oneConnListener struct { |
121 | +- conn net.Conn |
122 | +-} |
123 | +- |
124 | +-func (l *oneConnListener) Accept() (c net.Conn, err error) { |
125 | +- c = l.conn |
126 | +- if c == nil { |
127 | +- err = io.EOF |
128 | +- return |
129 | +- } |
130 | +- err = nil |
131 | +- l.conn = nil |
132 | +- return |
133 | +-} |
134 | +- |
135 | +-func (l *oneConnListener) Close() error { |
136 | +- return nil |
137 | +-} |
138 | +- |
139 | +-func (l *oneConnListener) Addr() net.Addr { |
140 | +- return dummyAddr("test-address") |
141 | +-} |
142 | + |
143 | + func (a dummyAddr) Network() string { |
144 | + return string(a) |
145 | +@@ -93,1289 +48,6 @@ |
146 | + return nil |
147 | + } |
148 | + |
149 | +-type testConn struct { |
150 | +- readBuf bytes.Buffer |
151 | +- writeBuf bytes.Buffer |
152 | +- closec chan bool // if non-nil, send value to it on close |
153 | +- noopConn |
154 | +-} |
155 | +- |
156 | +-func (c *testConn) Read(b []byte) (int, error) { |
157 | +- return c.readBuf.Read(b) |
158 | +-} |
159 | +- |
160 | +-func (c *testConn) Write(b []byte) (int, error) { |
161 | +- return c.writeBuf.Write(b) |
162 | +-} |
163 | +- |
164 | +-func (c *testConn) Close() error { |
165 | +- select { |
166 | +- case c.closec <- true: |
167 | +- default: |
168 | +- } |
169 | +- return nil |
170 | +-} |
171 | +- |
172 | +-// reqBytes treats req as a request (with \n delimiters) and returns it with \r\n delimiters, |
173 | +-// ending in \r\n\r\n |
174 | +-func reqBytes(req string) []byte { |
175 | +- return []byte(strings.Replace(strings.TrimSpace(req), "\n", "\r\n", -1) + "\r\n\r\n") |
176 | +-} |
177 | +- |
178 | +-type handlerTest struct { |
179 | +- handler Handler |
180 | +-} |
181 | +- |
182 | +-func newHandlerTest(h Handler) handlerTest { |
183 | +- return handlerTest{h} |
184 | +-} |
185 | +- |
186 | +-func (ht handlerTest) rawResponse(req string) string { |
187 | +- reqb := reqBytes(req) |
188 | +- var output bytes.Buffer |
189 | +- conn := &rwTestConn{ |
190 | +- Reader: bytes.NewReader(reqb), |
191 | +- Writer: &output, |
192 | +- closec: make(chan bool, 1), |
193 | +- } |
194 | +- ln := &oneConnListener{conn: conn} |
195 | +- go Serve(ln, ht.handler) |
196 | +- <-conn.closec |
197 | +- return output.String() |
198 | +-} |
199 | +- |
200 | +-func TestConsumingBodyOnNextConn(t *testing.T) { |
201 | +- conn := new(testConn) |
202 | +- for i := 0; i < 2; i++ { |
203 | +- conn.readBuf.Write([]byte( |
204 | +- "POST / HTTP/1.1\r\n" + |
205 | +- "Host: test\r\n" + |
206 | +- "Content-Length: 11\r\n" + |
207 | +- "\r\n" + |
208 | +- "foo=1&bar=1")) |
209 | +- } |
210 | +- |
211 | +- reqNum := 0 |
212 | +- ch := make(chan *Request) |
213 | +- servech := make(chan error) |
214 | +- listener := &oneConnListener{conn} |
215 | +- handler := func(res ResponseWriter, req *Request) { |
216 | +- reqNum++ |
217 | +- ch <- req |
218 | +- } |
219 | +- |
220 | +- go func() { |
221 | +- servech <- Serve(listener, HandlerFunc(handler)) |
222 | +- }() |
223 | +- |
224 | +- var req *Request |
225 | +- req = <-ch |
226 | +- if req == nil { |
227 | +- t.Fatal("Got nil first request.") |
228 | +- } |
229 | +- if req.Method != "POST" { |
230 | +- t.Errorf("For request #1's method, got %q; expected %q", |
231 | +- req.Method, "POST") |
232 | +- } |
233 | +- |
234 | +- req = <-ch |
235 | +- if req == nil { |
236 | +- t.Fatal("Got nil first request.") |
237 | +- } |
238 | +- if req.Method != "POST" { |
239 | +- t.Errorf("For request #2's method, got %q; expected %q", |
240 | +- req.Method, "POST") |
241 | +- } |
242 | +- |
243 | +- if serveerr := <-servech; serveerr != io.EOF { |
244 | +- t.Errorf("Serve returned %q; expected EOF", serveerr) |
245 | +- } |
246 | +-} |
247 | +- |
248 | +-type stringHandler string |
249 | +- |
250 | +-func (s stringHandler) ServeHTTP(w ResponseWriter, r *Request) { |
251 | +- w.Header().Set("Result", string(s)) |
252 | +-} |
253 | +- |
254 | +-var handlers = []struct { |
255 | +- pattern string |
256 | +- msg string |
257 | +-}{ |
258 | +- {"/", "Default"}, |
259 | +- {"/someDir/", "someDir"}, |
260 | +- {"someHost.com/someDir/", "someHost.com/someDir"}, |
261 | +-} |
262 | +- |
263 | +-var vtests = []struct { |
264 | +- url string |
265 | +- expected string |
266 | +-}{ |
267 | +- {"http://localhost/someDir/apage", "someDir"}, |
268 | +- {"http://localhost/otherDir/apage", "Default"}, |
269 | +- {"http://someHost.com/someDir/apage", "someHost.com/someDir"}, |
270 | +- {"http://otherHost.com/someDir/apage", "someDir"}, |
271 | +- {"http://otherHost.com/aDir/apage", "Default"}, |
272 | +- // redirections for trees |
273 | +- {"http://localhost/someDir", "/someDir/"}, |
274 | +- {"http://someHost.com/someDir", "/someDir/"}, |
275 | +-} |
276 | +- |
277 | +-func TestHostHandlers(t *testing.T) { |
278 | +- defer afterTest(t) |
279 | +- mux := NewServeMux() |
280 | +- for _, h := range handlers { |
281 | +- mux.Handle(h.pattern, stringHandler(h.msg)) |
282 | +- } |
283 | +- ts := httptest.NewServer(mux) |
284 | +- defer ts.Close() |
285 | +- |
286 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
287 | +- if err != nil { |
288 | +- t.Fatal(err) |
289 | +- } |
290 | +- defer conn.Close() |
291 | +- cc := httputil.NewClientConn(conn, nil) |
292 | +- for _, vt := range vtests { |
293 | +- var r *Response |
294 | +- var req Request |
295 | +- if req.URL, err = url.Parse(vt.url); err != nil { |
296 | +- t.Errorf("cannot parse url: %v", err) |
297 | +- continue |
298 | +- } |
299 | +- if err := cc.Write(&req); err != nil { |
300 | +- t.Errorf("writing request: %v", err) |
301 | +- continue |
302 | +- } |
303 | +- r, err := cc.Read(&req) |
304 | +- if err != nil { |
305 | +- t.Errorf("reading response: %v", err) |
306 | +- continue |
307 | +- } |
308 | +- switch r.StatusCode { |
309 | +- case StatusOK: |
310 | +- s := r.Header.Get("Result") |
311 | +- if s != vt.expected { |
312 | +- t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected) |
313 | +- } |
314 | +- case StatusMovedPermanently: |
315 | +- s := r.Header.Get("Location") |
316 | +- if s != vt.expected { |
317 | +- t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected) |
318 | +- } |
319 | +- default: |
320 | +- t.Errorf("Get(%q) unhandled status code %d", vt.url, r.StatusCode) |
321 | +- } |
322 | +- } |
323 | +-} |
324 | +- |
325 | +-var serveMuxRegister = []struct { |
326 | +- pattern string |
327 | +- h Handler |
328 | +-}{ |
329 | +- {"/dir/", serve(200)}, |
330 | +- {"/search", serve(201)}, |
331 | +- {"codesearch.google.com/search", serve(202)}, |
332 | +- {"codesearch.google.com/", serve(203)}, |
333 | +- {"example.com/", HandlerFunc(checkQueryStringHandler)}, |
334 | +-} |
335 | +- |
336 | +-// serve returns a handler that sends a response with the given code. |
337 | +-func serve(code int) HandlerFunc { |
338 | +- return func(w ResponseWriter, r *Request) { |
339 | +- w.WriteHeader(code) |
340 | +- } |
341 | +-} |
342 | +- |
343 | +-// checkQueryStringHandler checks if r.URL.RawQuery has the same value |
344 | +-// as the URL excluding the scheme and the query string and sends 200 |
345 | +-// response code if it is, 500 otherwise. |
346 | +-func checkQueryStringHandler(w ResponseWriter, r *Request) { |
347 | +- u := *r.URL |
348 | +- u.Scheme = "http" |
349 | +- u.Host = r.Host |
350 | +- u.RawQuery = "" |
351 | +- if "http://"+r.URL.RawQuery == u.String() { |
352 | +- w.WriteHeader(200) |
353 | +- } else { |
354 | +- w.WriteHeader(500) |
355 | +- } |
356 | +-} |
357 | +- |
358 | +-var serveMuxTests = []struct { |
359 | +- method string |
360 | +- host string |
361 | +- path string |
362 | +- code int |
363 | +- pattern string |
364 | +-}{ |
365 | +- {"GET", "google.com", "/", 404, ""}, |
366 | +- {"GET", "google.com", "/dir", 301, "/dir/"}, |
367 | +- {"GET", "google.com", "/dir/", 200, "/dir/"}, |
368 | +- {"GET", "google.com", "/dir/file", 200, "/dir/"}, |
369 | +- {"GET", "google.com", "/search", 201, "/search"}, |
370 | +- {"GET", "google.com", "/search/", 404, ""}, |
371 | +- {"GET", "google.com", "/search/foo", 404, ""}, |
372 | +- {"GET", "codesearch.google.com", "/search", 202, "codesearch.google.com/search"}, |
373 | +- {"GET", "codesearch.google.com", "/search/", 203, "codesearch.google.com/"}, |
374 | +- {"GET", "codesearch.google.com", "/search/foo", 203, "codesearch.google.com/"}, |
375 | +- {"GET", "codesearch.google.com", "/", 203, "codesearch.google.com/"}, |
376 | +- {"GET", "images.google.com", "/search", 201, "/search"}, |
377 | +- {"GET", "images.google.com", "/search/", 404, ""}, |
378 | +- {"GET", "images.google.com", "/search/foo", 404, ""}, |
379 | +- {"GET", "google.com", "/../search", 301, "/search"}, |
380 | +- {"GET", "google.com", "/dir/..", 301, ""}, |
381 | +- {"GET", "google.com", "/dir/..", 301, ""}, |
382 | +- {"GET", "google.com", "/dir/./file", 301, "/dir/"}, |
383 | +- |
384 | +- // The /foo -> /foo/ redirect applies to CONNECT requests |
385 | +- // but the path canonicalization does not. |
386 | +- {"CONNECT", "google.com", "/dir", 301, "/dir/"}, |
387 | +- {"CONNECT", "google.com", "/../search", 404, ""}, |
388 | +- {"CONNECT", "google.com", "/dir/..", 200, "/dir/"}, |
389 | +- {"CONNECT", "google.com", "/dir/..", 200, "/dir/"}, |
390 | +- {"CONNECT", "google.com", "/dir/./file", 200, "/dir/"}, |
391 | +-} |
392 | +- |
393 | +-func TestServeMuxHandler(t *testing.T) { |
394 | +- mux := NewServeMux() |
395 | +- for _, e := range serveMuxRegister { |
396 | +- mux.Handle(e.pattern, e.h) |
397 | +- } |
398 | +- |
399 | +- for _, tt := range serveMuxTests { |
400 | +- r := &Request{ |
401 | +- Method: tt.method, |
402 | +- Host: tt.host, |
403 | +- URL: &url.URL{ |
404 | +- Path: tt.path, |
405 | +- }, |
406 | +- } |
407 | +- h, pattern := mux.Handler(r) |
408 | +- rr := httptest.NewRecorder() |
409 | +- h.ServeHTTP(rr, r) |
410 | +- if pattern != tt.pattern || rr.Code != tt.code { |
411 | +- t.Errorf("%s %s %s = %d, %q, want %d, %q", tt.method, tt.host, tt.path, rr.Code, pattern, tt.code, tt.pattern) |
412 | +- } |
413 | +- } |
414 | +-} |
415 | +- |
416 | +-var serveMuxTests2 = []struct { |
417 | +- method string |
418 | +- host string |
419 | +- url string |
420 | +- code int |
421 | +- redirOk bool |
422 | +-}{ |
423 | +- {"GET", "google.com", "/", 404, false}, |
424 | +- {"GET", "example.com", "/test/?example.com/test/", 200, false}, |
425 | +- {"GET", "example.com", "test/?example.com/test/", 200, true}, |
426 | +-} |
427 | +- |
428 | +-// TestServeMuxHandlerRedirects tests that automatic redirects generated by |
429 | +-// mux.Handler() shouldn't clear the request's query string. |
430 | +-func TestServeMuxHandlerRedirects(t *testing.T) { |
431 | +- mux := NewServeMux() |
432 | +- for _, e := range serveMuxRegister { |
433 | +- mux.Handle(e.pattern, e.h) |
434 | +- } |
435 | +- |
436 | +- for _, tt := range serveMuxTests2 { |
437 | +- tries := 1 |
438 | +- turl := tt.url |
439 | +- for tries > 0 { |
440 | +- u, e := url.Parse(turl) |
441 | +- if e != nil { |
442 | +- t.Fatal(e) |
443 | +- } |
444 | +- r := &Request{ |
445 | +- Method: tt.method, |
446 | +- Host: tt.host, |
447 | +- URL: u, |
448 | +- } |
449 | +- h, _ := mux.Handler(r) |
450 | +- rr := httptest.NewRecorder() |
451 | +- h.ServeHTTP(rr, r) |
452 | +- if rr.Code != 301 { |
453 | +- if rr.Code != tt.code { |
454 | +- t.Errorf("%s %s %s = %d, want %d", tt.method, tt.host, tt.url, rr.Code, tt.code) |
455 | +- } |
456 | +- break |
457 | +- } |
458 | +- if !tt.redirOk { |
459 | +- t.Errorf("%s %s %s, unexpected redirect", tt.method, tt.host, tt.url) |
460 | +- break |
461 | +- } |
462 | +- turl = rr.HeaderMap.Get("Location") |
463 | +- tries-- |
464 | +- } |
465 | +- if tries < 0 { |
466 | +- t.Errorf("%s %s %s, too many redirects", tt.method, tt.host, tt.url) |
467 | +- } |
468 | +- } |
469 | +-} |
470 | +- |
471 | +-// Tests for http://code.google.com/p/go/issues/detail?id=900 |
472 | +-func TestMuxRedirectLeadingSlashes(t *testing.T) { |
473 | +- paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"} |
474 | +- for _, path := range paths { |
475 | +- req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n"))) |
476 | +- if err != nil { |
477 | +- t.Errorf("%s", err) |
478 | +- } |
479 | +- mux := NewServeMux() |
480 | +- resp := httptest.NewRecorder() |
481 | +- |
482 | +- mux.ServeHTTP(resp, req) |
483 | +- |
484 | +- if loc, expected := resp.Header().Get("Location"), "/foo.txt"; loc != expected { |
485 | +- t.Errorf("Expected Location header set to %q; got %q", expected, loc) |
486 | +- return |
487 | +- } |
488 | +- |
489 | +- if code, expected := resp.Code, StatusMovedPermanently; code != expected { |
490 | +- t.Errorf("Expected response code of StatusMovedPermanently; got %d", code) |
491 | +- return |
492 | +- } |
493 | +- } |
494 | +-} |
495 | +- |
496 | +-func TestServerTimeouts(t *testing.T) { |
497 | +- if runtime.GOOS == "plan9" { |
498 | +- t.Skip("skipping test; see http://golang.org/issue/7237") |
499 | +- } |
500 | +- defer afterTest(t) |
501 | +- reqNum := 0 |
502 | +- ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) { |
503 | +- reqNum++ |
504 | +- fmt.Fprintf(res, "req=%d", reqNum) |
505 | +- })) |
506 | +- ts.Config.ReadTimeout = 250 * time.Millisecond |
507 | +- ts.Config.WriteTimeout = 250 * time.Millisecond |
508 | +- ts.Start() |
509 | +- defer ts.Close() |
510 | +- |
511 | +- // Hit the HTTP server successfully. |
512 | +- tr := &Transport{DisableKeepAlives: true} // they interfere with this test |
513 | +- defer tr.CloseIdleConnections() |
514 | +- c := &Client{Transport: tr} |
515 | +- r, err := c.Get(ts.URL) |
516 | +- if err != nil { |
517 | +- t.Fatalf("http Get #1: %v", err) |
518 | +- } |
519 | +- got, _ := ioutil.ReadAll(r.Body) |
520 | +- expected := "req=1" |
521 | +- if string(got) != expected { |
522 | +- t.Errorf("Unexpected response for request #1; got %q; expected %q", |
523 | +- string(got), expected) |
524 | +- } |
525 | +- |
526 | +- // Slow client that should timeout. |
527 | +- t1 := time.Now() |
528 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
529 | +- if err != nil { |
530 | +- t.Fatalf("Dial: %v", err) |
531 | +- } |
532 | +- buf := make([]byte, 1) |
533 | +- n, err := conn.Read(buf) |
534 | +- latency := time.Since(t1) |
535 | +- if n != 0 || err != io.EOF { |
536 | +- t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF) |
537 | +- } |
538 | +- if latency < 200*time.Millisecond /* fudge from 250 ms above */ { |
539 | +- t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond) |
540 | +- } |
541 | +- |
542 | +- // Hit the HTTP server successfully again, verifying that the |
543 | +- // previous slow connection didn't run our handler. (that we |
544 | +- // get "req=2", not "req=3") |
545 | +- r, err = Get(ts.URL) |
546 | +- if err != nil { |
547 | +- t.Fatalf("http Get #2: %v", err) |
548 | +- } |
549 | +- got, _ = ioutil.ReadAll(r.Body) |
550 | +- expected = "req=2" |
551 | +- if string(got) != expected { |
552 | +- t.Errorf("Get #2 got %q, want %q", string(got), expected) |
553 | +- } |
554 | +- |
555 | +- if !testing.Short() { |
556 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
557 | +- if err != nil { |
558 | +- t.Fatalf("Dial: %v", err) |
559 | +- } |
560 | +- defer conn.Close() |
561 | +- go io.Copy(ioutil.Discard, conn) |
562 | +- for i := 0; i < 5; i++ { |
563 | +- _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")) |
564 | +- if err != nil { |
565 | +- t.Fatalf("on write %d: %v", i, err) |
566 | +- } |
567 | +- time.Sleep(ts.Config.ReadTimeout / 2) |
568 | +- } |
569 | +- } |
570 | +-} |
571 | +- |
572 | +-// golang.org/issue/4741 -- setting only a write timeout that triggers |
573 | +-// shouldn't cause a handler to block forever on reads (next HTTP |
574 | +-// request) that will never happen. |
575 | +-func TestOnlyWriteTimeout(t *testing.T) { |
576 | +- if runtime.GOOS == "plan9" { |
577 | +- t.Skip("skipping test; see http://golang.org/issue/7237") |
578 | +- } |
579 | +- defer afterTest(t) |
580 | +- var conn net.Conn |
581 | +- var afterTimeoutErrc = make(chan error, 1) |
582 | +- ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, req *Request) { |
583 | +- buf := make([]byte, 512<<10) |
584 | +- _, err := w.Write(buf) |
585 | +- if err != nil { |
586 | +- t.Errorf("handler Write error: %v", err) |
587 | +- return |
588 | +- } |
589 | +- conn.SetWriteDeadline(time.Now().Add(-30 * time.Second)) |
590 | +- _, err = w.Write(buf) |
591 | +- afterTimeoutErrc <- err |
592 | +- })) |
593 | +- ts.Listener = trackLastConnListener{ts.Listener, &conn} |
594 | +- ts.Start() |
595 | +- defer ts.Close() |
596 | +- |
597 | +- tr := &Transport{DisableKeepAlives: false} |
598 | +- defer tr.CloseIdleConnections() |
599 | +- c := &Client{Transport: tr} |
600 | +- |
601 | +- errc := make(chan error) |
602 | +- go func() { |
603 | +- res, err := c.Get(ts.URL) |
604 | +- if err != nil { |
605 | +- errc <- err |
606 | +- return |
607 | +- } |
608 | +- _, err = io.Copy(ioutil.Discard, res.Body) |
609 | +- errc <- err |
610 | +- }() |
611 | +- select { |
612 | +- case err := <-errc: |
613 | +- if err == nil { |
614 | +- t.Errorf("expected an error from Get request") |
615 | +- } |
616 | +- case <-time.After(5 * time.Second): |
617 | +- t.Fatal("timeout waiting for Get error") |
618 | +- } |
619 | +- if err := <-afterTimeoutErrc; err == nil { |
620 | +- t.Error("expected write error after timeout") |
621 | +- } |
622 | +-} |
623 | +- |
624 | +-// trackLastConnListener tracks the last net.Conn that was accepted. |
625 | +-type trackLastConnListener struct { |
626 | +- net.Listener |
627 | +- last *net.Conn // destination |
628 | +-} |
629 | +- |
630 | +-func (l trackLastConnListener) Accept() (c net.Conn, err error) { |
631 | +- c, err = l.Listener.Accept() |
632 | +- *l.last = c |
633 | +- return |
634 | +-} |
635 | +- |
636 | +-// TestIdentityResponse verifies that a handler can unset |
637 | +-func TestIdentityResponse(t *testing.T) { |
638 | +- defer afterTest(t) |
639 | +- handler := HandlerFunc(func(rw ResponseWriter, req *Request) { |
640 | +- rw.Header().Set("Content-Length", "3") |
641 | +- rw.Header().Set("Transfer-Encoding", req.FormValue("te")) |
642 | +- switch { |
643 | +- case req.FormValue("overwrite") == "1": |
644 | +- _, err := rw.Write([]byte("foo TOO LONG")) |
645 | +- if err != ErrContentLength { |
646 | +- t.Errorf("expected ErrContentLength; got %v", err) |
647 | +- } |
648 | +- case req.FormValue("underwrite") == "1": |
649 | +- rw.Header().Set("Content-Length", "500") |
650 | +- rw.Write([]byte("too short")) |
651 | +- default: |
652 | +- rw.Write([]byte("foo")) |
653 | +- } |
654 | +- }) |
655 | +- |
656 | +- ts := httptest.NewServer(handler) |
657 | +- defer ts.Close() |
658 | +- |
659 | +- // Note: this relies on the assumption (which is true) that |
660 | +- // Get sends HTTP/1.1 or greater requests. Otherwise the |
661 | +- // server wouldn't have the choice to send back chunked |
662 | +- // responses. |
663 | +- for _, te := range []string{"", "identity"} { |
664 | +- url := ts.URL + "/?te=" + te |
665 | +- res, err := Get(url) |
666 | +- if err != nil { |
667 | +- t.Fatalf("error with Get of %s: %v", url, err) |
668 | +- } |
669 | +- if cl, expected := res.ContentLength, int64(3); cl != expected { |
670 | +- t.Errorf("for %s expected res.ContentLength of %d; got %d", url, expected, cl) |
671 | +- } |
672 | +- if cl, expected := res.Header.Get("Content-Length"), "3"; cl != expected { |
673 | +- t.Errorf("for %s expected Content-Length header of %q; got %q", url, expected, cl) |
674 | +- } |
675 | +- if tl, expected := len(res.TransferEncoding), 0; tl != expected { |
676 | +- t.Errorf("for %s expected len(res.TransferEncoding) of %d; got %d (%v)", |
677 | +- url, expected, tl, res.TransferEncoding) |
678 | +- } |
679 | +- res.Body.Close() |
680 | +- } |
681 | +- |
682 | +- // Verify that ErrContentLength is returned |
683 | +- url := ts.URL + "/?overwrite=1" |
684 | +- res, err := Get(url) |
685 | +- if err != nil { |
686 | +- t.Fatalf("error with Get of %s: %v", url, err) |
687 | +- } |
688 | +- res.Body.Close() |
689 | +- |
690 | +- // Verify that the connection is closed when the declared Content-Length |
691 | +- // is larger than what the handler wrote. |
692 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
693 | +- if err != nil { |
694 | +- t.Fatalf("error dialing: %v", err) |
695 | +- } |
696 | +- _, err = conn.Write([]byte("GET /?underwrite=1 HTTP/1.1\r\nHost: foo\r\n\r\n")) |
697 | +- if err != nil { |
698 | +- t.Fatalf("error writing: %v", err) |
699 | +- } |
700 | +- |
701 | +- // The ReadAll will hang for a failing test, so use a Timer to |
702 | +- // fail explicitly. |
703 | +- goTimeout(t, 2*time.Second, func() { |
704 | +- got, _ := ioutil.ReadAll(conn) |
705 | +- expectedSuffix := "\r\n\r\ntoo short" |
706 | +- if !strings.HasSuffix(string(got), expectedSuffix) { |
707 | +- t.Errorf("Expected output to end with %q; got response body %q", |
708 | +- expectedSuffix, string(got)) |
709 | +- } |
710 | +- }) |
711 | +-} |
712 | +- |
713 | +-func testTCPConnectionCloses(t *testing.T, req string, h Handler) { |
714 | +- defer afterTest(t) |
715 | +- s := httptest.NewServer(h) |
716 | +- defer s.Close() |
717 | +- |
718 | +- conn, err := net.Dial("tcp", s.Listener.Addr().String()) |
719 | +- if err != nil { |
720 | +- t.Fatal("dial error:", err) |
721 | +- } |
722 | +- defer conn.Close() |
723 | +- |
724 | +- _, err = fmt.Fprint(conn, req) |
725 | +- if err != nil { |
726 | +- t.Fatal("print error:", err) |
727 | +- } |
728 | +- |
729 | +- r := bufio.NewReader(conn) |
730 | +- res, err := ReadResponse(r, &Request{Method: "GET"}) |
731 | +- if err != nil { |
732 | +- t.Fatal("ReadResponse error:", err) |
733 | +- } |
734 | +- |
735 | +- didReadAll := make(chan bool, 1) |
736 | +- go func() { |
737 | +- select { |
738 | +- case <-time.After(5 * time.Second): |
739 | +- t.Error("body not closed after 5s") |
740 | +- return |
741 | +- case <-didReadAll: |
742 | +- } |
743 | +- }() |
744 | +- |
745 | +- _, err = ioutil.ReadAll(r) |
746 | +- if err != nil { |
747 | +- t.Fatal("read error:", err) |
748 | +- } |
749 | +- didReadAll <- true |
750 | +- |
751 | +- if !res.Close { |
752 | +- t.Errorf("Response.Close = false; want true") |
753 | +- } |
754 | +-} |
755 | +- |
756 | +-// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive. |
757 | +-func TestServeHTTP10Close(t *testing.T) { |
758 | +- testTCPConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { |
759 | +- ServeFile(w, r, "testdata/file") |
760 | +- })) |
761 | +-} |
762 | +- |
763 | +-// TestClientCanClose verifies that clients can also force a connection to close. |
764 | +-func TestClientCanClose(t *testing.T) { |
765 | +- testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { |
766 | +- // Nothing. |
767 | +- })) |
768 | +-} |
769 | +- |
770 | +-// TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close, |
771 | +-// even for HTTP/1.1 requests. |
772 | +-func TestHandlersCanSetConnectionClose11(t *testing.T) { |
773 | +- testTCPConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { |
774 | +- w.Header().Set("Connection", "close") |
775 | +- })) |
776 | +-} |
777 | +- |
778 | +-func TestHandlersCanSetConnectionClose10(t *testing.T) { |
779 | +- testTCPConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { |
780 | +- w.Header().Set("Connection", "close") |
781 | +- })) |
782 | +-} |
783 | +- |
784 | +-func TestSetsRemoteAddr(t *testing.T) { |
785 | +- defer afterTest(t) |
786 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
787 | +- fmt.Fprintf(w, "%s", r.RemoteAddr) |
788 | +- })) |
789 | +- defer ts.Close() |
790 | +- |
791 | +- res, err := Get(ts.URL) |
792 | +- if err != nil { |
793 | +- t.Fatalf("Get error: %v", err) |
794 | +- } |
795 | +- body, err := ioutil.ReadAll(res.Body) |
796 | +- if err != nil { |
797 | +- t.Fatalf("ReadAll error: %v", err) |
798 | +- } |
799 | +- ip := string(body) |
800 | +- if !strings.HasPrefix(ip, "127.0.0.1:") && !strings.HasPrefix(ip, "[::1]:") { |
801 | +- t.Fatalf("Expected local addr; got %q", ip) |
802 | +- } |
803 | +-} |
804 | +- |
805 | +-func TestChunkedResponseHeaders(t *testing.T) { |
806 | +- defer afterTest(t) |
807 | +- log.SetOutput(ioutil.Discard) // is noisy otherwise |
808 | +- defer log.SetOutput(os.Stderr) |
809 | +- |
810 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
811 | +- w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted |
812 | +- w.(Flusher).Flush() |
813 | +- fmt.Fprintf(w, "I am a chunked response.") |
814 | +- })) |
815 | +- defer ts.Close() |
816 | +- |
817 | +- res, err := Get(ts.URL) |
818 | +- if err != nil { |
819 | +- t.Fatalf("Get error: %v", err) |
820 | +- } |
821 | +- defer res.Body.Close() |
822 | +- if g, e := res.ContentLength, int64(-1); g != e { |
823 | +- t.Errorf("expected ContentLength of %d; got %d", e, g) |
824 | +- } |
825 | +- if g, e := res.TransferEncoding, []string{"chunked"}; !reflect.DeepEqual(g, e) { |
826 | +- t.Errorf("expected TransferEncoding of %v; got %v", e, g) |
827 | +- } |
828 | +- if _, haveCL := res.Header["Content-Length"]; haveCL { |
829 | +- t.Errorf("Unexpected Content-Length") |
830 | +- } |
831 | +-} |
832 | +- |
833 | +-// Test304Responses verifies that 304s don't declare that they're |
834 | +-// chunking in their response headers and aren't allowed to produce |
835 | +-// output. |
836 | +-func Test304Responses(t *testing.T) { |
837 | +- defer afterTest(t) |
838 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
839 | +- w.WriteHeader(StatusNotModified) |
840 | +- _, err := w.Write([]byte("illegal body")) |
841 | +- if err != ErrBodyNotAllowed { |
842 | +- t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err) |
843 | +- } |
844 | +- })) |
845 | +- defer ts.Close() |
846 | +- res, err := Get(ts.URL) |
847 | +- if err != nil { |
848 | +- t.Error(err) |
849 | +- } |
850 | +- if len(res.TransferEncoding) > 0 { |
851 | +- t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding) |
852 | +- } |
853 | +- body, err := ioutil.ReadAll(res.Body) |
854 | +- if err != nil { |
855 | +- t.Error(err) |
856 | +- } |
857 | +- if len(body) > 0 { |
858 | +- t.Errorf("got unexpected body %q", string(body)) |
859 | +- } |
860 | +-} |
861 | +- |
862 | +-// TestHeadResponses verifies that all MIME type sniffing and Content-Length |
863 | +-// counting of GET requests also happens on HEAD requests. |
864 | +-func TestHeadResponses(t *testing.T) { |
865 | +- defer afterTest(t) |
866 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
867 | +- _, err := w.Write([]byte("<html>")) |
868 | +- if err != nil { |
869 | +- t.Errorf("ResponseWriter.Write: %v", err) |
870 | +- } |
871 | +- |
872 | +- // Also exercise the ReaderFrom path |
873 | +- _, err = io.Copy(w, strings.NewReader("789a")) |
874 | +- if err != nil { |
875 | +- t.Errorf("Copy(ResponseWriter, ...): %v", err) |
876 | +- } |
877 | +- })) |
878 | +- defer ts.Close() |
879 | +- res, err := Head(ts.URL) |
880 | +- if err != nil { |
881 | +- t.Error(err) |
882 | +- } |
883 | +- if len(res.TransferEncoding) > 0 { |
884 | +- t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding) |
885 | +- } |
886 | +- if ct := res.Header.Get("Content-Type"); ct != "text/html; charset=utf-8" { |
887 | +- t.Errorf("Content-Type: %q; want text/html; charset=utf-8", ct) |
888 | +- } |
889 | +- if v := res.ContentLength; v != 10 { |
890 | +- t.Errorf("Content-Length: %d; want 10", v) |
891 | +- } |
892 | +- body, err := ioutil.ReadAll(res.Body) |
893 | +- if err != nil { |
894 | +- t.Error(err) |
895 | +- } |
896 | +- if len(body) > 0 { |
897 | +- t.Errorf("got unexpected body %q", string(body)) |
898 | +- } |
899 | +-} |
900 | +- |
901 | +-func TestTLSHandshakeTimeout(t *testing.T) { |
902 | +- if runtime.GOOS == "plan9" { |
903 | +- t.Skip("skipping test; see http://golang.org/issue/7237") |
904 | +- } |
905 | +- defer afterTest(t) |
906 | +- ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) |
907 | +- errc := make(chanWriter, 10) // but only expecting 1 |
908 | +- ts.Config.ReadTimeout = 250 * time.Millisecond |
909 | +- ts.Config.ErrorLog = log.New(errc, "", 0) |
910 | +- ts.StartTLS() |
911 | +- defer ts.Close() |
912 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
913 | +- if err != nil { |
914 | +- t.Fatalf("Dial: %v", err) |
915 | +- } |
916 | +- defer conn.Close() |
917 | +- goTimeout(t, 10*time.Second, func() { |
918 | +- var buf [1]byte |
919 | +- n, err := conn.Read(buf[:]) |
920 | +- if err == nil || n != 0 { |
921 | +- t.Errorf("Read = %d, %v; want an error and no bytes", n, err) |
922 | +- } |
923 | +- }) |
924 | +- select { |
925 | +- case v := <-errc: |
926 | +- if !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") { |
927 | +- t.Errorf("expected a TLS handshake timeout error; got %q", v) |
928 | +- } |
929 | +- case <-time.After(5 * time.Second): |
930 | +- t.Errorf("timeout waiting for logged error") |
931 | +- } |
932 | +-} |
933 | +- |
934 | +-func TestTLSServer(t *testing.T) { |
935 | +- defer afterTest(t) |
936 | +- ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
937 | +- if r.TLS != nil { |
938 | +- w.Header().Set("X-TLS-Set", "true") |
939 | +- if r.TLS.HandshakeComplete { |
940 | +- w.Header().Set("X-TLS-HandshakeComplete", "true") |
941 | +- } |
942 | +- } |
943 | +- })) |
944 | +- ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) |
945 | +- defer ts.Close() |
946 | +- |
947 | +- // Connect an idle TCP connection to this server before we run |
948 | +- // our real tests. This idle connection used to block forever |
949 | +- // in the TLS handshake, preventing future connections from |
950 | +- // being accepted. It may prevent future accidental blocking |
951 | +- // in newConn. |
952 | +- idleConn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
953 | +- if err != nil { |
954 | +- t.Fatalf("Dial: %v", err) |
955 | +- } |
956 | +- defer idleConn.Close() |
957 | +- goTimeout(t, 10*time.Second, func() { |
958 | +- if !strings.HasPrefix(ts.URL, "https://") { |
959 | +- t.Errorf("expected test TLS server to start with https://, got %q", ts.URL) |
960 | +- return |
961 | +- } |
962 | +- noVerifyTransport := &Transport{ |
963 | +- TLSClientConfig: &tls.Config{ |
964 | +- InsecureSkipVerify: true, |
965 | +- }, |
966 | +- } |
967 | +- client := &Client{Transport: noVerifyTransport} |
968 | +- res, err := client.Get(ts.URL) |
969 | +- if err != nil { |
970 | +- t.Error(err) |
971 | +- return |
972 | +- } |
973 | +- if res == nil { |
974 | +- t.Errorf("got nil Response") |
975 | +- return |
976 | +- } |
977 | +- defer res.Body.Close() |
978 | +- if res.Header.Get("X-TLS-Set") != "true" { |
979 | +- t.Errorf("expected X-TLS-Set response header") |
980 | +- return |
981 | +- } |
982 | +- if res.Header.Get("X-TLS-HandshakeComplete") != "true" { |
983 | +- t.Errorf("expected X-TLS-HandshakeComplete header") |
984 | +- } |
985 | +- }) |
986 | +-} |
987 | +- |
988 | +-type serverExpectTest struct { |
989 | +- contentLength int // of request body |
990 | +- expectation string // e.g. "100-continue" |
991 | +- readBody bool // whether handler should read the body (if false, sends StatusUnauthorized) |
992 | +- expectedResponse string // expected substring in first line of http response |
993 | +-} |
994 | +- |
995 | +-var serverExpectTests = []serverExpectTest{ |
996 | +- // Normal 100-continues, case-insensitive. |
997 | +- {100, "100-continue", true, "100 Continue"}, |
998 | +- {100, "100-cOntInUE", true, "100 Continue"}, |
999 | +- |
1000 | +- // No 100-continue. |
1001 | +- {100, "", true, "200 OK"}, |
1002 | +- |
1003 | +- // 100-continue but requesting client to deny us, |
1004 | +- // so it never reads the body. |
1005 | +- {100, "100-continue", false, "401 Unauthorized"}, |
1006 | +- // Likewise without 100-continue: |
1007 | +- {100, "", false, "401 Unauthorized"}, |
1008 | +- |
1009 | +- // Non-standard expectations are failures |
1010 | +- {0, "a-pony", false, "417 Expectation Failed"}, |
1011 | +- |
1012 | +- // Expect-100 requested but no body |
1013 | +- {0, "100-continue", true, "400 Bad Request"}, |
1014 | +-} |
1015 | +- |
1016 | +-// Tests that the server responds to the "Expect" request header |
1017 | +-// correctly. |
1018 | +-func TestServerExpect(t *testing.T) { |
1019 | +- defer afterTest(t) |
1020 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1021 | +- // Note using r.FormValue("readbody") because for POST |
1022 | +- // requests that would read from r.Body, which we only |
1023 | +- // conditionally want to do. |
1024 | +- if strings.Contains(r.URL.RawQuery, "readbody=true") { |
1025 | +- ioutil.ReadAll(r.Body) |
1026 | +- w.Write([]byte("Hi")) |
1027 | +- } else { |
1028 | +- w.WriteHeader(StatusUnauthorized) |
1029 | +- } |
1030 | +- })) |
1031 | +- defer ts.Close() |
1032 | +- |
1033 | +- runTest := func(test serverExpectTest) { |
1034 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
1035 | +- if err != nil { |
1036 | +- t.Fatalf("Dial: %v", err) |
1037 | +- } |
1038 | +- defer conn.Close() |
1039 | +- |
1040 | +- // Only send the body immediately if we're acting like an HTTP client |
1041 | +- // that doesn't send 100-continue expectations. |
1042 | +- writeBody := test.contentLength > 0 && strings.ToLower(test.expectation) != "100-continue" |
1043 | +- |
1044 | +- go func() { |
1045 | +- _, err := fmt.Fprintf(conn, "POST /?readbody=%v HTTP/1.1\r\n"+ |
1046 | +- "Connection: close\r\n"+ |
1047 | +- "Content-Length: %d\r\n"+ |
1048 | +- "Expect: %s\r\nHost: foo\r\n\r\n", |
1049 | +- test.readBody, test.contentLength, test.expectation) |
1050 | +- if err != nil { |
1051 | +- t.Errorf("On test %#v, error writing request headers: %v", test, err) |
1052 | +- return |
1053 | +- } |
1054 | +- if writeBody { |
1055 | +- body := strings.Repeat("A", test.contentLength) |
1056 | +- _, err = fmt.Fprint(conn, body) |
1057 | +- if err != nil { |
1058 | +- if !test.readBody { |
1059 | +- // Server likely already hung up on us. |
1060 | +- // See larger comment below. |
1061 | +- t.Logf("On test %#v, acceptable error writing request body: %v", test, err) |
1062 | +- return |
1063 | +- } |
1064 | +- t.Errorf("On test %#v, error writing request body: %v", test, err) |
1065 | +- } |
1066 | +- } |
1067 | +- }() |
1068 | +- bufr := bufio.NewReader(conn) |
1069 | +- line, err := bufr.ReadString('\n') |
1070 | +- if err != nil { |
1071 | +- if writeBody && !test.readBody { |
1072 | +- // This is an acceptable failure due to a possible TCP race: |
1073 | +- // We were still writing data and the server hung up on us. A TCP |
1074 | +- // implementation may send a RST if our request body data was known |
1075 | +- // to be lost, which may trigger our reads to fail. |
1076 | +- // See RFC 1122 page 88. |
1077 | +- t.Logf("On test %#v, acceptable error from ReadString: %v", test, err) |
1078 | +- return |
1079 | +- } |
1080 | +- t.Fatalf("On test %#v, ReadString: %v", test, err) |
1081 | +- } |
1082 | +- if !strings.Contains(line, test.expectedResponse) { |
1083 | +- t.Errorf("On test %#v, got first line = %q; want %q", test, line, test.expectedResponse) |
1084 | +- } |
1085 | +- } |
1086 | +- |
1087 | +- for _, test := range serverExpectTests { |
1088 | +- runTest(test) |
1089 | +- } |
1090 | +-} |
1091 | +- |
1092 | +-// Under a ~256KB (maxPostHandlerReadBytes) threshold, the server |
1093 | +-// should consume client request bodies that a handler didn't read. |
1094 | +-func TestServerUnreadRequestBodyLittle(t *testing.T) { |
1095 | +- conn := new(testConn) |
1096 | +- body := strings.Repeat("x", 100<<10) |
1097 | +- conn.readBuf.Write([]byte(fmt.Sprintf( |
1098 | +- "POST / HTTP/1.1\r\n"+ |
1099 | +- "Host: test\r\n"+ |
1100 | +- "Content-Length: %d\r\n"+ |
1101 | +- "\r\n", len(body)))) |
1102 | +- conn.readBuf.Write([]byte(body)) |
1103 | +- |
1104 | +- done := make(chan bool) |
1105 | +- |
1106 | +- ls := &oneConnListener{conn} |
1107 | +- go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { |
1108 | +- defer close(done) |
1109 | +- if conn.readBuf.Len() < len(body)/2 { |
1110 | +- t.Errorf("on request, read buffer length is %d; expected about 100 KB", conn.readBuf.Len()) |
1111 | +- } |
1112 | +- rw.WriteHeader(200) |
1113 | +- rw.(Flusher).Flush() |
1114 | +- if g, e := conn.readBuf.Len(), 0; g != e { |
1115 | +- t.Errorf("after WriteHeader, read buffer length is %d; want %d", g, e) |
1116 | +- } |
1117 | +- if c := rw.Header().Get("Connection"); c != "" { |
1118 | +- t.Errorf(`Connection header = %q; want ""`, c) |
1119 | +- } |
1120 | +- })) |
1121 | +- <-done |
1122 | +-} |
1123 | +- |
1124 | +-// Over a ~256KB (maxPostHandlerReadBytes) threshold, the server |
1125 | +-// should ignore client request bodies that a handler didn't read |
1126 | +-// and close the connection. |
1127 | +-func TestServerUnreadRequestBodyLarge(t *testing.T) { |
1128 | +- conn := new(testConn) |
1129 | +- body := strings.Repeat("x", 1<<20) |
1130 | +- conn.readBuf.Write([]byte(fmt.Sprintf( |
1131 | +- "POST / HTTP/1.1\r\n"+ |
1132 | +- "Host: test\r\n"+ |
1133 | +- "Content-Length: %d\r\n"+ |
1134 | +- "\r\n", len(body)))) |
1135 | +- conn.readBuf.Write([]byte(body)) |
1136 | +- conn.closec = make(chan bool, 1) |
1137 | +- |
1138 | +- ls := &oneConnListener{conn} |
1139 | +- go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { |
1140 | +- if conn.readBuf.Len() < len(body)/2 { |
1141 | +- t.Errorf("on request, read buffer length is %d; expected about 1MB", conn.readBuf.Len()) |
1142 | +- } |
1143 | +- rw.WriteHeader(200) |
1144 | +- rw.(Flusher).Flush() |
1145 | +- if conn.readBuf.Len() < len(body)/2 { |
1146 | +- t.Errorf("post-WriteHeader, read buffer length is %d; expected about 1MB", conn.readBuf.Len()) |
1147 | +- } |
1148 | +- })) |
1149 | +- <-conn.closec |
1150 | +- |
1151 | +- if res := conn.writeBuf.String(); !strings.Contains(res, "Connection: close") { |
1152 | +- t.Errorf("Expected a Connection: close header; got response: %s", res) |
1153 | +- } |
1154 | +-} |
1155 | +- |
1156 | +-func TestTimeoutHandler(t *testing.T) { |
1157 | +- defer afterTest(t) |
1158 | +- sendHi := make(chan bool, 1) |
1159 | +- writeErrors := make(chan error, 1) |
1160 | +- sayHi := HandlerFunc(func(w ResponseWriter, r *Request) { |
1161 | +- <-sendHi |
1162 | +- _, werr := w.Write([]byte("hi")) |
1163 | +- writeErrors <- werr |
1164 | +- }) |
1165 | +- timeout := make(chan time.Time, 1) // write to this to force timeouts |
1166 | +- ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout)) |
1167 | +- defer ts.Close() |
1168 | +- |
1169 | +- // Succeed without timing out: |
1170 | +- sendHi <- true |
1171 | +- res, err := Get(ts.URL) |
1172 | +- if err != nil { |
1173 | +- t.Error(err) |
1174 | +- } |
1175 | +- if g, e := res.StatusCode, StatusOK; g != e { |
1176 | +- t.Errorf("got res.StatusCode %d; expected %d", g, e) |
1177 | +- } |
1178 | +- body, _ := ioutil.ReadAll(res.Body) |
1179 | +- if g, e := string(body), "hi"; g != e { |
1180 | +- t.Errorf("got body %q; expected %q", g, e) |
1181 | +- } |
1182 | +- if g := <-writeErrors; g != nil { |
1183 | +- t.Errorf("got unexpected Write error on first request: %v", g) |
1184 | +- } |
1185 | +- |
1186 | +- // Times out: |
1187 | +- timeout <- time.Time{} |
1188 | +- res, err = Get(ts.URL) |
1189 | +- if err != nil { |
1190 | +- t.Error(err) |
1191 | +- } |
1192 | +- if g, e := res.StatusCode, StatusServiceUnavailable; g != e { |
1193 | +- t.Errorf("got res.StatusCode %d; expected %d", g, e) |
1194 | +- } |
1195 | +- body, _ = ioutil.ReadAll(res.Body) |
1196 | +- if !strings.Contains(string(body), "<title>Timeout</title>") { |
1197 | +- t.Errorf("expected timeout body; got %q", string(body)) |
1198 | +- } |
1199 | +- |
1200 | +- // Now make the previously-timed out handler speak again, |
1201 | +- // which verifies the panic is handled: |
1202 | +- sendHi <- true |
1203 | +- if g, e := <-writeErrors, ErrHandlerTimeout; g != e { |
1204 | +- t.Errorf("expected Write error of %v; got %v", e, g) |
1205 | +- } |
1206 | +-} |
1207 | +- |
1208 | +-// Verifies we don't path.Clean() on the wrong parts in redirects. |
1209 | +-func TestRedirectMunging(t *testing.T) { |
1210 | +- req, _ := NewRequest("GET", "http://example.com/", nil) |
1211 | +- |
1212 | +- resp := httptest.NewRecorder() |
1213 | +- Redirect(resp, req, "/foo?next=http://bar.com/", 302) |
1214 | +- if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e { |
1215 | +- t.Errorf("Location header was %q; want %q", g, e) |
1216 | +- } |
1217 | +- |
1218 | +- resp = httptest.NewRecorder() |
1219 | +- Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302) |
1220 | +- if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e { |
1221 | +- t.Errorf("Location header was %q; want %q", g, e) |
1222 | +- } |
1223 | +-} |
1224 | +- |
1225 | +-func TestRedirectBadPath(t *testing.T) { |
1226 | +- // This used to crash. It's not valid input (bad path), but it |
1227 | +- // shouldn't crash. |
1228 | +- rr := httptest.NewRecorder() |
1229 | +- req := &Request{ |
1230 | +- Method: "GET", |
1231 | +- URL: &url.URL{ |
1232 | +- Scheme: "http", |
1233 | +- Path: "not-empty-but-no-leading-slash", // bogus |
1234 | +- }, |
1235 | +- } |
1236 | +- Redirect(rr, req, "", 304) |
1237 | +- if rr.Code != 304 { |
1238 | +- t.Errorf("Code = %d; want 304", rr.Code) |
1239 | +- } |
1240 | +-} |
1241 | +- |
1242 | +-// TestZeroLengthPostAndResponse exercises an optimization done by the Transport: |
1243 | +-// when there is no body (either because the method doesn't permit a body, or an |
1244 | +-// explicit Content-Length of zero is present), then the transport can re-use the |
1245 | +-// connection immediately. But when it re-uses the connection, it typically closes |
1246 | +-// the previous request's body, which is not optimal for zero-lengthed bodies, |
1247 | +-// as the client would then see http.ErrBodyReadAfterClose and not 0, io.EOF. |
1248 | +-func TestZeroLengthPostAndResponse(t *testing.T) { |
1249 | +- defer afterTest(t) |
1250 | +- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) { |
1251 | +- all, err := ioutil.ReadAll(r.Body) |
1252 | +- if err != nil { |
1253 | +- t.Fatalf("handler ReadAll: %v", err) |
1254 | +- } |
1255 | +- if len(all) != 0 { |
1256 | +- t.Errorf("handler got %d bytes; expected 0", len(all)) |
1257 | +- } |
1258 | +- rw.Header().Set("Content-Length", "0") |
1259 | +- })) |
1260 | +- defer ts.Close() |
1261 | +- |
1262 | +- req, err := NewRequest("POST", ts.URL, strings.NewReader("")) |
1263 | +- if err != nil { |
1264 | +- t.Fatal(err) |
1265 | +- } |
1266 | +- req.ContentLength = 0 |
1267 | +- |
1268 | +- var resp [5]*Response |
1269 | +- for i := range resp { |
1270 | +- resp[i], err = DefaultClient.Do(req) |
1271 | +- if err != nil { |
1272 | +- t.Fatalf("client post #%d: %v", i, err) |
1273 | +- } |
1274 | +- } |
1275 | +- |
1276 | +- for i := range resp { |
1277 | +- all, err := ioutil.ReadAll(resp[i].Body) |
1278 | +- if err != nil { |
1279 | +- t.Fatalf("req #%d: client ReadAll: %v", i, err) |
1280 | +- } |
1281 | +- if len(all) != 0 { |
1282 | +- t.Errorf("req #%d: client got %d bytes; expected 0", i, len(all)) |
1283 | +- } |
1284 | +- } |
1285 | +-} |
1286 | +- |
1287 | +-func TestHandlerPanicNil(t *testing.T) { |
1288 | +- testHandlerPanic(t, false, nil) |
1289 | +-} |
1290 | +- |
1291 | +-func TestHandlerPanic(t *testing.T) { |
1292 | +- testHandlerPanic(t, false, "intentional death for testing") |
1293 | +-} |
1294 | +- |
1295 | +-func TestHandlerPanicWithHijack(t *testing.T) { |
1296 | +- testHandlerPanic(t, true, "intentional death for testing") |
1297 | +-} |
1298 | +- |
1299 | +-func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) { |
1300 | +- defer afterTest(t) |
1301 | +- // Unlike the other tests that set the log output to ioutil.Discard |
1302 | +- // to quiet the output, this test uses a pipe. The pipe serves three |
1303 | +- // purposes: |
1304 | +- // |
1305 | +- // 1) The log.Print from the http server (generated by the caught |
1306 | +- // panic) will go to the pipe instead of stderr, making the |
1307 | +- // output quiet. |
1308 | +- // |
1309 | +- // 2) We read from the pipe to verify that the handler |
1310 | +- // actually caught the panic and logged something. |
1311 | +- // |
1312 | +- // 3) The blocking Read call prevents this TestHandlerPanic |
1313 | +- // function from exiting before the HTTP server handler |
1314 | +- // finishes crashing. If this text function exited too |
1315 | +- // early (and its defer log.SetOutput(os.Stderr) ran), |
1316 | +- // then the crash output could spill into the next test. |
1317 | +- pr, pw := io.Pipe() |
1318 | +- log.SetOutput(pw) |
1319 | +- defer log.SetOutput(os.Stderr) |
1320 | +- defer pw.Close() |
1321 | +- |
1322 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1323 | +- if withHijack { |
1324 | +- rwc, _, err := w.(Hijacker).Hijack() |
1325 | +- if err != nil { |
1326 | +- t.Logf("unexpected error: %v", err) |
1327 | +- } |
1328 | +- defer rwc.Close() |
1329 | +- } |
1330 | +- panic(panicValue) |
1331 | +- })) |
1332 | +- defer ts.Close() |
1333 | +- |
1334 | +- // Do a blocking read on the log output pipe so its logging |
1335 | +- // doesn't bleed into the next test. But wait only 5 seconds |
1336 | +- // for it. |
1337 | +- done := make(chan bool, 1) |
1338 | +- go func() { |
1339 | +- buf := make([]byte, 4<<10) |
1340 | +- _, err := pr.Read(buf) |
1341 | +- pr.Close() |
1342 | +- if err != nil && err != io.EOF { |
1343 | +- t.Error(err) |
1344 | +- } |
1345 | +- done <- true |
1346 | +- }() |
1347 | +- |
1348 | +- _, err := Get(ts.URL) |
1349 | +- if err == nil { |
1350 | +- t.Logf("expected an error") |
1351 | +- } |
1352 | +- |
1353 | +- if panicValue == nil { |
1354 | +- return |
1355 | +- } |
1356 | +- |
1357 | +- select { |
1358 | +- case <-done: |
1359 | +- return |
1360 | +- case <-time.After(5 * time.Second): |
1361 | +- t.Fatal("expected server handler to log an error") |
1362 | +- } |
1363 | +-} |
1364 | +- |
1365 | +-func TestNoDate(t *testing.T) { |
1366 | +- defer afterTest(t) |
1367 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1368 | +- w.Header()["Date"] = nil |
1369 | +- })) |
1370 | +- defer ts.Close() |
1371 | +- res, err := Get(ts.URL) |
1372 | +- if err != nil { |
1373 | +- t.Fatal(err) |
1374 | +- } |
1375 | +- _, present := res.Header["Date"] |
1376 | +- if present { |
1377 | +- t.Fatalf("Expected no Date header; got %v", res.Header["Date"]) |
1378 | +- } |
1379 | +-} |
1380 | +- |
1381 | +-func TestStripPrefix(t *testing.T) { |
1382 | +- defer afterTest(t) |
1383 | +- h := HandlerFunc(func(w ResponseWriter, r *Request) { |
1384 | +- w.Header().Set("X-Path", r.URL.Path) |
1385 | +- }) |
1386 | +- ts := httptest.NewServer(StripPrefix("/foo", h)) |
1387 | +- defer ts.Close() |
1388 | +- |
1389 | +- res, err := Get(ts.URL + "/foo/bar") |
1390 | +- if err != nil { |
1391 | +- t.Fatal(err) |
1392 | +- } |
1393 | +- if g, e := res.Header.Get("X-Path"), "/bar"; g != e { |
1394 | +- t.Errorf("test 1: got %s, want %s", g, e) |
1395 | +- } |
1396 | +- res.Body.Close() |
1397 | +- |
1398 | +- res, err = Get(ts.URL + "/bar") |
1399 | +- if err != nil { |
1400 | +- t.Fatal(err) |
1401 | +- } |
1402 | +- if g, e := res.StatusCode, 404; g != e { |
1403 | +- t.Errorf("test 2: got status %v, want %v", g, e) |
1404 | +- } |
1405 | +- res.Body.Close() |
1406 | +-} |
1407 | +- |
1408 | +-func TestRequestLimit(t *testing.T) { |
1409 | +- defer afterTest(t) |
1410 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1411 | +- t.Fatalf("didn't expect to get request in Handler") |
1412 | +- })) |
1413 | +- defer ts.Close() |
1414 | +- req, _ := NewRequest("GET", ts.URL, nil) |
1415 | +- var bytesPerHeader = len("header12345: val12345\r\n") |
1416 | +- for i := 0; i < ((DefaultMaxHeaderBytes+4096)/bytesPerHeader)+1; i++ { |
1417 | +- req.Header.Set(fmt.Sprintf("header%05d", i), fmt.Sprintf("val%05d", i)) |
1418 | +- } |
1419 | +- res, err := DefaultClient.Do(req) |
1420 | +- if err != nil { |
1421 | +- // Some HTTP clients may fail on this undefined behavior (server replying and |
1422 | +- // closing the connection while the request is still being written), but |
1423 | +- // we do support it (at least currently), so we expect a response below. |
1424 | +- t.Fatalf("Do: %v", err) |
1425 | +- } |
1426 | +- defer res.Body.Close() |
1427 | +- if res.StatusCode != 413 { |
1428 | +- t.Fatalf("expected 413 response status; got: %d %s", res.StatusCode, res.Status) |
1429 | +- } |
1430 | +-} |
1431 | +- |
1432 | + type neverEnding byte |
1433 | + |
1434 | + func (b neverEnding) Read(p []byte) (n int, err error) { |
1435 | +@@ -1384,1344 +56,3 @@ |
1436 | + } |
1437 | + return len(p), nil |
1438 | + } |
1439 | +- |
1440 | +-type countReader struct { |
1441 | +- r io.Reader |
1442 | +- n *int64 |
1443 | +-} |
1444 | +- |
1445 | +-func (cr countReader) Read(p []byte) (n int, err error) { |
1446 | +- n, err = cr.r.Read(p) |
1447 | +- atomic.AddInt64(cr.n, int64(n)) |
1448 | +- return |
1449 | +-} |
1450 | +- |
1451 | +-func TestRequestBodyLimit(t *testing.T) { |
1452 | +- defer afterTest(t) |
1453 | +- const limit = 1 << 20 |
1454 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1455 | +- r.Body = MaxBytesReader(w, r.Body, limit) |
1456 | +- n, err := io.Copy(ioutil.Discard, r.Body) |
1457 | +- if err == nil { |
1458 | +- t.Errorf("expected error from io.Copy") |
1459 | +- } |
1460 | +- if n != limit { |
1461 | +- t.Errorf("io.Copy = %d, want %d", n, limit) |
1462 | +- } |
1463 | +- })) |
1464 | +- defer ts.Close() |
1465 | +- |
1466 | +- nWritten := new(int64) |
1467 | +- req, _ := NewRequest("POST", ts.URL, io.LimitReader(countReader{neverEnding('a'), nWritten}, limit*200)) |
1468 | +- |
1469 | +- // Send the POST, but don't care it succeeds or not. The |
1470 | +- // remote side is going to reply and then close the TCP |
1471 | +- // connection, and HTTP doesn't really define if that's |
1472 | +- // allowed or not. Some HTTP clients will get the response |
1473 | +- // and some (like ours, currently) will complain that the |
1474 | +- // request write failed, without reading the response. |
1475 | +- // |
1476 | +- // But that's okay, since what we're really testing is that |
1477 | +- // the remote side hung up on us before we wrote too much. |
1478 | +- _, _ = DefaultClient.Do(req) |
1479 | +- |
1480 | +- if atomic.LoadInt64(nWritten) > limit*100 { |
1481 | +- t.Errorf("handler restricted the request body to %d bytes, but client managed to write %d", |
1482 | +- limit, nWritten) |
1483 | +- } |
1484 | +-} |
1485 | +- |
1486 | +-// TestClientWriteShutdown tests that if the client shuts down the write |
1487 | +-// side of their TCP connection, the server doesn't send a 400 Bad Request. |
1488 | +-func TestClientWriteShutdown(t *testing.T) { |
1489 | +- if runtime.GOOS == "plan9" { |
1490 | +- t.Skip("skipping test; see http://golang.org/issue/7237") |
1491 | +- } |
1492 | +- defer afterTest(t) |
1493 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) |
1494 | +- defer ts.Close() |
1495 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
1496 | +- if err != nil { |
1497 | +- t.Fatalf("Dial: %v", err) |
1498 | +- } |
1499 | +- err = conn.(*net.TCPConn).CloseWrite() |
1500 | +- if err != nil { |
1501 | +- t.Fatalf("Dial: %v", err) |
1502 | +- } |
1503 | +- donec := make(chan bool) |
1504 | +- go func() { |
1505 | +- defer close(donec) |
1506 | +- bs, err := ioutil.ReadAll(conn) |
1507 | +- if err != nil { |
1508 | +- t.Fatalf("ReadAll: %v", err) |
1509 | +- } |
1510 | +- got := string(bs) |
1511 | +- if got != "" { |
1512 | +- t.Errorf("read %q from server; want nothing", got) |
1513 | +- } |
1514 | +- }() |
1515 | +- select { |
1516 | +- case <-donec: |
1517 | +- case <-time.After(10 * time.Second): |
1518 | +- t.Fatalf("timeout") |
1519 | +- } |
1520 | +-} |
1521 | +- |
1522 | +-// Tests that chunked server responses that write 1 byte at a time are |
1523 | +-// buffered before chunk headers are added, not after chunk headers. |
1524 | +-func TestServerBufferedChunking(t *testing.T) { |
1525 | +- conn := new(testConn) |
1526 | +- conn.readBuf.Write([]byte("GET / HTTP/1.1\r\n\r\n")) |
1527 | +- conn.closec = make(chan bool, 1) |
1528 | +- ls := &oneConnListener{conn} |
1529 | +- go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { |
1530 | +- rw.(Flusher).Flush() // force the Header to be sent, in chunking mode, not counting the length |
1531 | +- rw.Write([]byte{'x'}) |
1532 | +- rw.Write([]byte{'y'}) |
1533 | +- rw.Write([]byte{'z'}) |
1534 | +- })) |
1535 | +- <-conn.closec |
1536 | +- if !bytes.HasSuffix(conn.writeBuf.Bytes(), []byte("\r\n\r\n3\r\nxyz\r\n0\r\n\r\n")) { |
1537 | +- t.Errorf("response didn't end with a single 3 byte 'xyz' chunk; got:\n%q", |
1538 | +- conn.writeBuf.Bytes()) |
1539 | +- } |
1540 | +-} |
1541 | +- |
1542 | +-// Tests that the server flushes its response headers out when it's |
1543 | +-// ignoring the response body and waits a bit before forcefully |
1544 | +-// closing the TCP connection, causing the client to get a RST. |
1545 | +-// See http://golang.org/issue/3595 |
1546 | +-func TestServerGracefulClose(t *testing.T) { |
1547 | +- defer afterTest(t) |
1548 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1549 | +- Error(w, "bye", StatusUnauthorized) |
1550 | +- })) |
1551 | +- defer ts.Close() |
1552 | +- |
1553 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
1554 | +- if err != nil { |
1555 | +- t.Fatal(err) |
1556 | +- } |
1557 | +- defer conn.Close() |
1558 | +- const bodySize = 5 << 20 |
1559 | +- req := []byte(fmt.Sprintf("POST / HTTP/1.1\r\nHost: foo.com\r\nContent-Length: %d\r\n\r\n", bodySize)) |
1560 | +- for i := 0; i < bodySize; i++ { |
1561 | +- req = append(req, 'x') |
1562 | +- } |
1563 | +- writeErr := make(chan error) |
1564 | +- go func() { |
1565 | +- _, err := conn.Write(req) |
1566 | +- writeErr <- err |
1567 | +- }() |
1568 | +- br := bufio.NewReader(conn) |
1569 | +- lineNum := 0 |
1570 | +- for { |
1571 | +- line, err := br.ReadString('\n') |
1572 | +- if err == io.EOF { |
1573 | +- break |
1574 | +- } |
1575 | +- if err != nil { |
1576 | +- t.Fatalf("ReadLine: %v", err) |
1577 | +- } |
1578 | +- lineNum++ |
1579 | +- if lineNum == 1 && !strings.Contains(line, "401 Unauthorized") { |
1580 | +- t.Errorf("Response line = %q; want a 401", line) |
1581 | +- } |
1582 | +- } |
1583 | +- // Wait for write to finish. This is a broken pipe on both |
1584 | +- // Darwin and Linux, but checking this isn't the point of |
1585 | +- // the test. |
1586 | +- <-writeErr |
1587 | +-} |
1588 | +- |
1589 | +-func TestCaseSensitiveMethod(t *testing.T) { |
1590 | +- defer afterTest(t) |
1591 | +- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
1592 | +- if r.Method != "get" { |
1593 | +- t.Errorf(`Got method %q; want "get"`, r.Method) |
1594 | +- } |
1595 | +- })) |
1596 | +- defer ts.Close() |
1597 | +- req, _ := NewRequest("get", ts.URL, nil) |
1598 | +- res, err := DefaultClient.Do(req) |
1599 | +- if err != nil { |
1600 | +- t.Error(err) |
1601 | +- return |
1602 | +- } |
1603 | +- res.Body.Close() |
1604 | +-} |
1605 | +- |
1606 | +-// TestContentLengthZero tests that for both an HTTP/1.0 and HTTP/1.1 |
1607 | +-// request (both keep-alive), when a Handler never writes any |
1608 | +-// response, the net/http package adds a "Content-Length: 0" response |
1609 | +-// header. |
1610 | +-func TestContentLengthZero(t *testing.T) { |
1611 | +- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {})) |
1612 | +- defer ts.Close() |
1613 | +- |
1614 | +- for _, version := range []string{"HTTP/1.0", "HTTP/1.1"} { |
1615 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
1616 | +- if err != nil { |
1617 | +- t.Fatalf("error dialing: %v", err) |
1618 | +- } |
1619 | +- _, err = fmt.Fprintf(conn, "GET / %v\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n", version) |
1620 | +- if err != nil { |
1621 | +- t.Fatalf("error writing: %v", err) |
1622 | +- } |
1623 | +- req, _ := NewRequest("GET", "/", nil) |
1624 | +- res, err := ReadResponse(bufio.NewReader(conn), req) |
1625 | +- if err != nil { |
1626 | +- t.Fatalf("error reading response: %v", err) |
1627 | +- } |
1628 | +- if te := res.TransferEncoding; len(te) > 0 { |
1629 | +- t.Errorf("For version %q, Transfer-Encoding = %q; want none", version, te) |
1630 | +- } |
1631 | +- if cl := res.ContentLength; cl != 0 { |
1632 | +- t.Errorf("For version %q, Content-Length = %v; want 0", version, cl) |
1633 | +- } |
1634 | +- conn.Close() |
1635 | +- } |
1636 | +-} |
1637 | +- |
1638 | +-func TestCloseNotifier(t *testing.T) { |
1639 | +- defer afterTest(t) |
1640 | +- gotReq := make(chan bool, 1) |
1641 | +- sawClose := make(chan bool, 1) |
1642 | +- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { |
1643 | +- gotReq <- true |
1644 | +- cc := rw.(CloseNotifier).CloseNotify() |
1645 | +- <-cc |
1646 | +- sawClose <- true |
1647 | +- })) |
1648 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
1649 | +- if err != nil { |
1650 | +- t.Fatalf("error dialing: %v", err) |
1651 | +- } |
1652 | +- diec := make(chan bool) |
1653 | +- go func() { |
1654 | +- _, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n") |
1655 | +- if err != nil { |
1656 | +- t.Fatal(err) |
1657 | +- } |
1658 | +- <-diec |
1659 | +- conn.Close() |
1660 | +- }() |
1661 | +-For: |
1662 | +- for { |
1663 | +- select { |
1664 | +- case <-gotReq: |
1665 | +- diec <- true |
1666 | +- case <-sawClose: |
1667 | +- break For |
1668 | +- case <-time.After(5 * time.Second): |
1669 | +- t.Fatal("timeout") |
1670 | +- } |
1671 | +- } |
1672 | +- ts.Close() |
1673 | +-} |
1674 | +- |
1675 | +-func TestCloseNotifierChanLeak(t *testing.T) { |
1676 | +- defer afterTest(t) |
1677 | +- req := reqBytes("GET / HTTP/1.0\nHost: golang.org") |
1678 | +- for i := 0; i < 20; i++ { |
1679 | +- var output bytes.Buffer |
1680 | +- conn := &rwTestConn{ |
1681 | +- Reader: bytes.NewReader(req), |
1682 | +- Writer: &output, |
1683 | +- closec: make(chan bool, 1), |
1684 | +- } |
1685 | +- ln := &oneConnListener{conn: conn} |
1686 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
1687 | +- // Ignore the return value and never read from |
1688 | +- // it, testing that we don't leak goroutines |
1689 | +- // on the sending side: |
1690 | +- _ = rw.(CloseNotifier).CloseNotify() |
1691 | +- }) |
1692 | +- go Serve(ln, handler) |
1693 | +- <-conn.closec |
1694 | +- } |
1695 | +-} |
1696 | +- |
1697 | +-func TestOptions(t *testing.T) { |
1698 | +- uric := make(chan string, 2) // only expect 1, but leave space for 2 |
1699 | +- mux := NewServeMux() |
1700 | +- mux.HandleFunc("/", func(w ResponseWriter, r *Request) { |
1701 | +- uric <- r.RequestURI |
1702 | +- }) |
1703 | +- ts := httptest.NewServer(mux) |
1704 | +- defer ts.Close() |
1705 | +- |
1706 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
1707 | +- if err != nil { |
1708 | +- t.Fatal(err) |
1709 | +- } |
1710 | +- defer conn.Close() |
1711 | +- |
1712 | +- // An OPTIONS * request should succeed. |
1713 | +- _, err = conn.Write([]byte("OPTIONS * HTTP/1.1\r\nHost: foo.com\r\n\r\n")) |
1714 | +- if err != nil { |
1715 | +- t.Fatal(err) |
1716 | +- } |
1717 | +- br := bufio.NewReader(conn) |
1718 | +- res, err := ReadResponse(br, &Request{Method: "OPTIONS"}) |
1719 | +- if err != nil { |
1720 | +- t.Fatal(err) |
1721 | +- } |
1722 | +- if res.StatusCode != 200 { |
1723 | +- t.Errorf("Got non-200 response to OPTIONS *: %#v", res) |
1724 | +- } |
1725 | +- |
1726 | +- // A GET * request on a ServeMux should fail. |
1727 | +- _, err = conn.Write([]byte("GET * HTTP/1.1\r\nHost: foo.com\r\n\r\n")) |
1728 | +- if err != nil { |
1729 | +- t.Fatal(err) |
1730 | +- } |
1731 | +- res, err = ReadResponse(br, &Request{Method: "GET"}) |
1732 | +- if err != nil { |
1733 | +- t.Fatal(err) |
1734 | +- } |
1735 | +- if res.StatusCode != 400 { |
1736 | +- t.Errorf("Got non-400 response to GET *: %#v", res) |
1737 | +- } |
1738 | +- |
1739 | +- res, err = Get(ts.URL + "/second") |
1740 | +- if err != nil { |
1741 | +- t.Fatal(err) |
1742 | +- } |
1743 | +- res.Body.Close() |
1744 | +- if got := <-uric; got != "/second" { |
1745 | +- t.Errorf("Handler saw request for %q; want /second", got) |
1746 | +- } |
1747 | +-} |
1748 | +- |
1749 | +-// Tests regarding the ordering of Write, WriteHeader, Header, and |
1750 | +-// Flush calls. In Go 1.0, rw.WriteHeader immediately flushed the |
1751 | +-// (*response).header to the wire. In Go 1.1, the actual wire flush is |
1752 | +-// delayed, so we could maybe tack on a Content-Length and better |
1753 | +-// Content-Type after we see more (or all) of the output. To preserve |
1754 | +-// compatibility with Go 1, we need to be careful to track which |
1755 | +-// headers were live at the time of WriteHeader, so we write the same |
1756 | +-// ones, even if the handler modifies them (~erroneously) after the |
1757 | +-// first Write. |
1758 | +-func TestHeaderToWire(t *testing.T) { |
1759 | +- tests := []struct { |
1760 | +- name string |
1761 | +- handler func(ResponseWriter, *Request) |
1762 | +- check func(output string) error |
1763 | +- }{ |
1764 | +- { |
1765 | +- name: "write without Header", |
1766 | +- handler: func(rw ResponseWriter, r *Request) { |
1767 | +- rw.Write([]byte("hello world")) |
1768 | +- }, |
1769 | +- check: func(got string) error { |
1770 | +- if !strings.Contains(got, "Content-Length:") { |
1771 | +- return errors.New("no content-length") |
1772 | +- } |
1773 | +- if !strings.Contains(got, "Content-Type: text/plain") { |
1774 | +- return errors.New("no content-length") |
1775 | +- } |
1776 | +- return nil |
1777 | +- }, |
1778 | +- }, |
1779 | +- { |
1780 | +- name: "Header mutation before write", |
1781 | +- handler: func(rw ResponseWriter, r *Request) { |
1782 | +- h := rw.Header() |
1783 | +- h.Set("Content-Type", "some/type") |
1784 | +- rw.Write([]byte("hello world")) |
1785 | +- h.Set("Too-Late", "bogus") |
1786 | +- }, |
1787 | +- check: func(got string) error { |
1788 | +- if !strings.Contains(got, "Content-Length:") { |
1789 | +- return errors.New("no content-length") |
1790 | +- } |
1791 | +- if !strings.Contains(got, "Content-Type: some/type") { |
1792 | +- return errors.New("wrong content-type") |
1793 | +- } |
1794 | +- if strings.Contains(got, "Too-Late") { |
1795 | +- return errors.New("don't want too-late header") |
1796 | +- } |
1797 | +- return nil |
1798 | +- }, |
1799 | +- }, |
1800 | +- { |
1801 | +- name: "write then useless Header mutation", |
1802 | +- handler: func(rw ResponseWriter, r *Request) { |
1803 | +- rw.Write([]byte("hello world")) |
1804 | +- rw.Header().Set("Too-Late", "Write already wrote headers") |
1805 | +- }, |
1806 | +- check: func(got string) error { |
1807 | +- if strings.Contains(got, "Too-Late") { |
1808 | +- return errors.New("header appeared from after WriteHeader") |
1809 | +- } |
1810 | +- return nil |
1811 | +- }, |
1812 | +- }, |
1813 | +- { |
1814 | +- name: "flush then write", |
1815 | +- handler: func(rw ResponseWriter, r *Request) { |
1816 | +- rw.(Flusher).Flush() |
1817 | +- rw.Write([]byte("post-flush")) |
1818 | +- rw.Header().Set("Too-Late", "Write already wrote headers") |
1819 | +- }, |
1820 | +- check: func(got string) error { |
1821 | +- if !strings.Contains(got, "Transfer-Encoding: chunked") { |
1822 | +- return errors.New("not chunked") |
1823 | +- } |
1824 | +- if strings.Contains(got, "Too-Late") { |
1825 | +- return errors.New("header appeared from after WriteHeader") |
1826 | +- } |
1827 | +- return nil |
1828 | +- }, |
1829 | +- }, |
1830 | +- { |
1831 | +- name: "header then flush", |
1832 | +- handler: func(rw ResponseWriter, r *Request) { |
1833 | +- rw.Header().Set("Content-Type", "some/type") |
1834 | +- rw.(Flusher).Flush() |
1835 | +- rw.Write([]byte("post-flush")) |
1836 | +- rw.Header().Set("Too-Late", "Write already wrote headers") |
1837 | +- }, |
1838 | +- check: func(got string) error { |
1839 | +- if !strings.Contains(got, "Transfer-Encoding: chunked") { |
1840 | +- return errors.New("not chunked") |
1841 | +- } |
1842 | +- if strings.Contains(got, "Too-Late") { |
1843 | +- return errors.New("header appeared from after WriteHeader") |
1844 | +- } |
1845 | +- if !strings.Contains(got, "Content-Type: some/type") { |
1846 | +- return errors.New("wrong content-length") |
1847 | +- } |
1848 | +- return nil |
1849 | +- }, |
1850 | +- }, |
1851 | +- { |
1852 | +- name: "sniff-on-first-write content-type", |
1853 | +- handler: func(rw ResponseWriter, r *Request) { |
1854 | +- rw.Write([]byte("<html><head></head><body>some html</body></html>")) |
1855 | +- rw.Header().Set("Content-Type", "x/wrong") |
1856 | +- }, |
1857 | +- check: func(got string) error { |
1858 | +- if !strings.Contains(got, "Content-Type: text/html") { |
1859 | +- return errors.New("wrong content-length; want html") |
1860 | +- } |
1861 | +- return nil |
1862 | +- }, |
1863 | +- }, |
1864 | +- { |
1865 | +- name: "explicit content-type wins", |
1866 | +- handler: func(rw ResponseWriter, r *Request) { |
1867 | +- rw.Header().Set("Content-Type", "some/type") |
1868 | +- rw.Write([]byte("<html><head></head><body>some html</body></html>")) |
1869 | +- }, |
1870 | +- check: func(got string) error { |
1871 | +- if !strings.Contains(got, "Content-Type: some/type") { |
1872 | +- return errors.New("wrong content-length; want html") |
1873 | +- } |
1874 | +- return nil |
1875 | +- }, |
1876 | +- }, |
1877 | +- { |
1878 | +- name: "empty handler", |
1879 | +- handler: func(rw ResponseWriter, r *Request) { |
1880 | +- }, |
1881 | +- check: func(got string) error { |
1882 | +- if !strings.Contains(got, "Content-Type: text/plain") { |
1883 | +- return errors.New("wrong content-length; want text/plain") |
1884 | +- } |
1885 | +- if !strings.Contains(got, "Content-Length: 0") { |
1886 | +- return errors.New("want 0 content-length") |
1887 | +- } |
1888 | +- return nil |
1889 | +- }, |
1890 | +- }, |
1891 | +- { |
1892 | +- name: "only Header, no write", |
1893 | +- handler: func(rw ResponseWriter, r *Request) { |
1894 | +- rw.Header().Set("Some-Header", "some-value") |
1895 | +- }, |
1896 | +- check: func(got string) error { |
1897 | +- if !strings.Contains(got, "Some-Header") { |
1898 | +- return errors.New("didn't get header") |
1899 | +- } |
1900 | +- return nil |
1901 | +- }, |
1902 | +- }, |
1903 | +- { |
1904 | +- name: "WriteHeader call", |
1905 | +- handler: func(rw ResponseWriter, r *Request) { |
1906 | +- rw.WriteHeader(404) |
1907 | +- rw.Header().Set("Too-Late", "some-value") |
1908 | +- }, |
1909 | +- check: func(got string) error { |
1910 | +- if !strings.Contains(got, "404") { |
1911 | +- return errors.New("wrong status") |
1912 | +- } |
1913 | +- if strings.Contains(got, "Some-Header") { |
1914 | +- return errors.New("shouldn't have seen Too-Late") |
1915 | +- } |
1916 | +- return nil |
1917 | +- }, |
1918 | +- }, |
1919 | +- } |
1920 | +- for _, tc := range tests { |
1921 | +- ht := newHandlerTest(HandlerFunc(tc.handler)) |
1922 | +- got := ht.rawResponse("GET / HTTP/1.1\nHost: golang.org") |
1923 | +- if err := tc.check(got); err != nil { |
1924 | +- t.Errorf("%s: %v\nGot response:\n%s", tc.name, err, got) |
1925 | +- } |
1926 | +- } |
1927 | +-} |
1928 | +- |
1929 | +-// goTimeout runs f, failing t if f takes more than ns to complete. |
1930 | +-func goTimeout(t *testing.T, d time.Duration, f func()) { |
1931 | +- ch := make(chan bool, 2) |
1932 | +- timer := time.AfterFunc(d, func() { |
1933 | +- t.Errorf("Timeout expired after %v", d) |
1934 | +- ch <- true |
1935 | +- }) |
1936 | +- defer timer.Stop() |
1937 | +- go func() { |
1938 | +- defer func() { ch <- true }() |
1939 | +- f() |
1940 | +- }() |
1941 | +- <-ch |
1942 | +-} |
1943 | +- |
1944 | +-type errorListener struct { |
1945 | +- errs []error |
1946 | +-} |
1947 | +- |
1948 | +-func (l *errorListener) Accept() (c net.Conn, err error) { |
1949 | +- if len(l.errs) == 0 { |
1950 | +- return nil, io.EOF |
1951 | +- } |
1952 | +- err = l.errs[0] |
1953 | +- l.errs = l.errs[1:] |
1954 | +- return |
1955 | +-} |
1956 | +- |
1957 | +-func (l *errorListener) Close() error { |
1958 | +- return nil |
1959 | +-} |
1960 | +- |
1961 | +-func (l *errorListener) Addr() net.Addr { |
1962 | +- return dummyAddr("test-address") |
1963 | +-} |
1964 | +- |
1965 | +-func TestAcceptMaxFds(t *testing.T) { |
1966 | +- log.SetOutput(ioutil.Discard) // is noisy otherwise |
1967 | +- defer log.SetOutput(os.Stderr) |
1968 | +- |
1969 | +- ln := &errorListener{[]error{ |
1970 | +- &net.OpError{ |
1971 | +- Op: "accept", |
1972 | +- Err: syscall.EMFILE, |
1973 | +- }}} |
1974 | +- err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {}))) |
1975 | +- if err != io.EOF { |
1976 | +- t.Errorf("got error %v, want EOF", err) |
1977 | +- } |
1978 | +-} |
1979 | +- |
1980 | +-func TestWriteAfterHijack(t *testing.T) { |
1981 | +- req := reqBytes("GET / HTTP/1.1\nHost: golang.org") |
1982 | +- var buf bytes.Buffer |
1983 | +- wrotec := make(chan bool, 1) |
1984 | +- conn := &rwTestConn{ |
1985 | +- Reader: bytes.NewReader(req), |
1986 | +- Writer: &buf, |
1987 | +- closec: make(chan bool, 1), |
1988 | +- } |
1989 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
1990 | +- conn, bufrw, err := rw.(Hijacker).Hijack() |
1991 | +- if err != nil { |
1992 | +- t.Error(err) |
1993 | +- return |
1994 | +- } |
1995 | +- go func() { |
1996 | +- bufrw.Write([]byte("[hijack-to-bufw]")) |
1997 | +- bufrw.Flush() |
1998 | +- conn.Write([]byte("[hijack-to-conn]")) |
1999 | +- conn.Close() |
2000 | +- wrotec <- true |
2001 | +- }() |
2002 | +- }) |
2003 | +- ln := &oneConnListener{conn: conn} |
2004 | +- go Serve(ln, handler) |
2005 | +- <-conn.closec |
2006 | +- <-wrotec |
2007 | +- if g, w := buf.String(), "[hijack-to-bufw][hijack-to-conn]"; g != w { |
2008 | +- t.Errorf("wrote %q; want %q", g, w) |
2009 | +- } |
2010 | +-} |
2011 | +- |
2012 | +-func TestDoubleHijack(t *testing.T) { |
2013 | +- req := reqBytes("GET / HTTP/1.1\nHost: golang.org") |
2014 | +- var buf bytes.Buffer |
2015 | +- conn := &rwTestConn{ |
2016 | +- Reader: bytes.NewReader(req), |
2017 | +- Writer: &buf, |
2018 | +- closec: make(chan bool, 1), |
2019 | +- } |
2020 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
2021 | +- conn, _, err := rw.(Hijacker).Hijack() |
2022 | +- if err != nil { |
2023 | +- t.Error(err) |
2024 | +- return |
2025 | +- } |
2026 | +- _, _, err = rw.(Hijacker).Hijack() |
2027 | +- if err == nil { |
2028 | +- t.Errorf("got err = nil; want err != nil") |
2029 | +- } |
2030 | +- conn.Close() |
2031 | +- }) |
2032 | +- ln := &oneConnListener{conn: conn} |
2033 | +- go Serve(ln, handler) |
2034 | +- <-conn.closec |
2035 | +-} |
2036 | +- |
2037 | +-// http://code.google.com/p/go/issues/detail?id=5955 |
2038 | +-// Note that this does not test the "request too large" |
2039 | +-// exit path from the http server. This is intentional; |
2040 | +-// not sending Connection: close is just a minor wire |
2041 | +-// optimization and is pointless if dealing with a |
2042 | +-// badly behaved client. |
2043 | +-func TestHTTP10ConnectionHeader(t *testing.T) { |
2044 | +- defer afterTest(t) |
2045 | +- |
2046 | +- mux := NewServeMux() |
2047 | +- mux.Handle("/", HandlerFunc(func(resp ResponseWriter, req *Request) {})) |
2048 | +- ts := httptest.NewServer(mux) |
2049 | +- defer ts.Close() |
2050 | +- |
2051 | +- // net/http uses HTTP/1.1 for requests, so write requests manually |
2052 | +- tests := []struct { |
2053 | +- req string // raw http request |
2054 | +- expect []string // expected Connection header(s) |
2055 | +- }{ |
2056 | +- { |
2057 | +- req: "GET / HTTP/1.0\r\n\r\n", |
2058 | +- expect: nil, |
2059 | +- }, |
2060 | +- { |
2061 | +- req: "OPTIONS * HTTP/1.0\r\n\r\n", |
2062 | +- expect: nil, |
2063 | +- }, |
2064 | +- { |
2065 | +- req: "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", |
2066 | +- expect: []string{"keep-alive"}, |
2067 | +- }, |
2068 | +- } |
2069 | +- |
2070 | +- for _, tt := range tests { |
2071 | +- conn, err := net.Dial("tcp", ts.Listener.Addr().String()) |
2072 | +- if err != nil { |
2073 | +- t.Fatal("dial err:", err) |
2074 | +- } |
2075 | +- |
2076 | +- _, err = fmt.Fprint(conn, tt.req) |
2077 | +- if err != nil { |
2078 | +- t.Fatal("conn write err:", err) |
2079 | +- } |
2080 | +- |
2081 | +- resp, err := ReadResponse(bufio.NewReader(conn), &Request{Method: "GET"}) |
2082 | +- if err != nil { |
2083 | +- t.Fatal("ReadResponse err:", err) |
2084 | +- } |
2085 | +- conn.Close() |
2086 | +- resp.Body.Close() |
2087 | +- |
2088 | +- got := resp.Header["Connection"] |
2089 | +- if !reflect.DeepEqual(got, tt.expect) { |
2090 | +- t.Errorf("wrong Connection headers for request %q. Got %q expect %q", tt.req, got, tt.expect) |
2091 | +- } |
2092 | +- } |
2093 | +-} |
2094 | +- |
2095 | +-// See golang.org/issue/5660 |
2096 | +-func TestServerReaderFromOrder(t *testing.T) { |
2097 | +- defer afterTest(t) |
2098 | +- pr, pw := io.Pipe() |
2099 | +- const size = 3 << 20 |
2100 | +- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { |
2101 | +- rw.Header().Set("Content-Type", "text/plain") // prevent sniffing path |
2102 | +- done := make(chan bool) |
2103 | +- go func() { |
2104 | +- io.Copy(rw, pr) |
2105 | +- close(done) |
2106 | +- }() |
2107 | +- time.Sleep(25 * time.Millisecond) // give Copy a chance to break things |
2108 | +- n, err := io.Copy(ioutil.Discard, req.Body) |
2109 | +- if err != nil { |
2110 | +- t.Errorf("handler Copy: %v", err) |
2111 | +- return |
2112 | +- } |
2113 | +- if n != size { |
2114 | +- t.Errorf("handler Copy = %d; want %d", n, size) |
2115 | +- } |
2116 | +- pw.Write([]byte("hi")) |
2117 | +- pw.Close() |
2118 | +- <-done |
2119 | +- })) |
2120 | +- defer ts.Close() |
2121 | +- |
2122 | +- req, err := NewRequest("POST", ts.URL, io.LimitReader(neverEnding('a'), size)) |
2123 | +- if err != nil { |
2124 | +- t.Fatal(err) |
2125 | +- } |
2126 | +- res, err := DefaultClient.Do(req) |
2127 | +- if err != nil { |
2128 | +- t.Fatal(err) |
2129 | +- } |
2130 | +- all, err := ioutil.ReadAll(res.Body) |
2131 | +- if err != nil { |
2132 | +- t.Fatal(err) |
2133 | +- } |
2134 | +- res.Body.Close() |
2135 | +- if string(all) != "hi" { |
2136 | +- t.Errorf("Body = %q; want hi", all) |
2137 | +- } |
2138 | +-} |
2139 | +- |
2140 | +-// Issue 6157, Issue 6685 |
2141 | +-func TestCodesPreventingContentTypeAndBody(t *testing.T) { |
2142 | +- for _, code := range []int{StatusNotModified, StatusNoContent, StatusContinue} { |
2143 | +- ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { |
2144 | +- if r.URL.Path == "/header" { |
2145 | +- w.Header().Set("Content-Length", "123") |
2146 | +- } |
2147 | +- w.WriteHeader(code) |
2148 | +- if r.URL.Path == "/more" { |
2149 | +- w.Write([]byte("stuff")) |
2150 | +- } |
2151 | +- })) |
2152 | +- for _, req := range []string{ |
2153 | +- "GET / HTTP/1.0", |
2154 | +- "GET /header HTTP/1.0", |
2155 | +- "GET /more HTTP/1.0", |
2156 | +- "GET / HTTP/1.1", |
2157 | +- "GET /header HTTP/1.1", |
2158 | +- "GET /more HTTP/1.1", |
2159 | +- } { |
2160 | +- got := ht.rawResponse(req) |
2161 | +- wantStatus := fmt.Sprintf("%d %s", code, StatusText(code)) |
2162 | +- if !strings.Contains(got, wantStatus) { |
2163 | +- t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, req, got) |
2164 | +- } else if strings.Contains(got, "Content-Length") { |
2165 | +- t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got) |
2166 | +- } else if strings.Contains(got, "stuff") { |
2167 | +- t.Errorf("Code %d: Response contains a body from %q: %s", code, req, got) |
2168 | +- } |
2169 | +- } |
2170 | +- } |
2171 | +-} |
2172 | +- |
2173 | +-// Issue 6995 |
2174 | +-// A server Handler can receive a Request, and then turn around and |
2175 | +-// give a copy of that Request.Body out to the Transport (e.g. any |
2176 | +-// proxy). So then two people own that Request.Body (both the server |
2177 | +-// and the http client), and both think they can close it on failure. |
2178 | +-// Therefore, all incoming server requests Bodies need to be thread-safe. |
2179 | +-func TestTransportAndServerSharedBodyRace(t *testing.T) { |
2180 | +- defer afterTest(t) |
2181 | +- |
2182 | +- const bodySize = 1 << 20 |
2183 | +- |
2184 | +- unblockBackend := make(chan bool) |
2185 | +- backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { |
2186 | +- io.CopyN(rw, req.Body, bodySize/2) |
2187 | +- <-unblockBackend |
2188 | +- })) |
2189 | +- defer backend.Close() |
2190 | +- |
2191 | +- backendRespc := make(chan *Response, 1) |
2192 | +- proxy := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { |
2193 | +- if req.RequestURI == "/foo" { |
2194 | +- rw.Write([]byte("bar")) |
2195 | +- return |
2196 | +- } |
2197 | +- req2, _ := NewRequest("POST", backend.URL, req.Body) |
2198 | +- req2.ContentLength = bodySize |
2199 | +- |
2200 | +- bresp, err := DefaultClient.Do(req2) |
2201 | +- if err != nil { |
2202 | +- t.Errorf("Proxy outbound request: %v", err) |
2203 | +- return |
2204 | +- } |
2205 | +- _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4) |
2206 | +- if err != nil { |
2207 | +- t.Errorf("Proxy copy error: %v", err) |
2208 | +- return |
2209 | +- } |
2210 | +- backendRespc <- bresp // to close later |
2211 | +- |
2212 | +- // Try to cause a race: Both the DefaultTransport and the proxy handler's Server |
2213 | +- // will try to read/close req.Body (aka req2.Body) |
2214 | +- DefaultTransport.(*Transport).CancelRequest(req2) |
2215 | +- rw.Write([]byte("OK")) |
2216 | +- })) |
2217 | +- defer proxy.Close() |
2218 | +- |
2219 | +- req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize)) |
2220 | +- res, err := DefaultClient.Do(req) |
2221 | +- if err != nil { |
2222 | +- t.Fatalf("Original request: %v", err) |
2223 | +- } |
2224 | +- |
2225 | +- // Cleanup, so we don't leak goroutines. |
2226 | +- res.Body.Close() |
2227 | +- close(unblockBackend) |
2228 | +- (<-backendRespc).Body.Close() |
2229 | +-} |
2230 | +- |
2231 | +-// Test that a hanging Request.Body.Read from another goroutine can't |
2232 | +-// cause the Handler goroutine's Request.Body.Close to block. |
2233 | +-func TestRequestBodyCloseDoesntBlock(t *testing.T) { |
2234 | +- t.Skipf("Skipping known issue; see golang.org/issue/7121") |
2235 | +- if testing.Short() { |
2236 | +- t.Skip("skipping in -short mode") |
2237 | +- } |
2238 | +- defer afterTest(t) |
2239 | +- |
2240 | +- readErrCh := make(chan error, 1) |
2241 | +- errCh := make(chan error, 2) |
2242 | +- |
2243 | +- server := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { |
2244 | +- go func(body io.Reader) { |
2245 | +- _, err := body.Read(make([]byte, 100)) |
2246 | +- readErrCh <- err |
2247 | +- }(req.Body) |
2248 | +- time.Sleep(500 * time.Millisecond) |
2249 | +- })) |
2250 | +- defer server.Close() |
2251 | +- |
2252 | +- closeConn := make(chan bool) |
2253 | +- defer close(closeConn) |
2254 | +- go func() { |
2255 | +- conn, err := net.Dial("tcp", server.Listener.Addr().String()) |
2256 | +- if err != nil { |
2257 | +- errCh <- err |
2258 | +- return |
2259 | +- } |
2260 | +- defer conn.Close() |
2261 | +- _, err = conn.Write([]byte("POST / HTTP/1.1\r\nConnection: close\r\nHost: foo\r\nContent-Length: 100000\r\n\r\n")) |
2262 | +- if err != nil { |
2263 | +- errCh <- err |
2264 | +- return |
2265 | +- } |
2266 | +- // And now just block, making the server block on our |
2267 | +- // 100000 bytes of body that will never arrive. |
2268 | +- <-closeConn |
2269 | +- }() |
2270 | +- select { |
2271 | +- case err := <-readErrCh: |
2272 | +- if err == nil { |
2273 | +- t.Error("Read was nil. Expected error.") |
2274 | +- } |
2275 | +- case err := <-errCh: |
2276 | +- t.Error(err) |
2277 | +- case <-time.After(5 * time.Second): |
2278 | +- t.Error("timeout") |
2279 | +- } |
2280 | +-} |
2281 | +- |
2282 | +-func TestResponseWriterWriteStringAllocs(t *testing.T) { |
2283 | +- ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { |
2284 | +- if r.URL.Path == "/s" { |
2285 | +- io.WriteString(w, "Hello world") |
2286 | +- } else { |
2287 | +- w.Write([]byte("Hello world")) |
2288 | +- } |
2289 | +- })) |
2290 | +- before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") }) |
2291 | +- after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") }) |
2292 | +- if int(after) >= int(before) { |
2293 | +- t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before) |
2294 | +- } |
2295 | +-} |
2296 | +- |
2297 | +-func TestAppendTime(t *testing.T) { |
2298 | +- var b [len(TimeFormat)]byte |
2299 | +- t1 := time.Date(2013, 9, 21, 15, 41, 0, 0, time.FixedZone("CEST", 2*60*60)) |
2300 | +- res := ExportAppendTime(b[:0], t1) |
2301 | +- t2, err := ParseTime(string(res)) |
2302 | +- if err != nil { |
2303 | +- t.Fatalf("Error parsing time: %s", err) |
2304 | +- } |
2305 | +- if !t1.Equal(t2) { |
2306 | +- t.Fatalf("Times differ; expected: %v, got %v (%s)", t1, t2, string(res)) |
2307 | +- } |
2308 | +-} |
2309 | +- |
2310 | +-func TestServerConnState(t *testing.T) { |
2311 | +- defer afterTest(t) |
2312 | +- handler := map[string]func(w ResponseWriter, r *Request){ |
2313 | +- "/": func(w ResponseWriter, r *Request) { |
2314 | +- fmt.Fprintf(w, "Hello.") |
2315 | +- }, |
2316 | +- "/close": func(w ResponseWriter, r *Request) { |
2317 | +- w.Header().Set("Connection", "close") |
2318 | +- fmt.Fprintf(w, "Hello.") |
2319 | +- }, |
2320 | +- "/hijack": func(w ResponseWriter, r *Request) { |
2321 | +- c, _, _ := w.(Hijacker).Hijack() |
2322 | +- c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello.")) |
2323 | +- c.Close() |
2324 | +- }, |
2325 | +- "/hijack-panic": func(w ResponseWriter, r *Request) { |
2326 | +- c, _, _ := w.(Hijacker).Hijack() |
2327 | +- c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello.")) |
2328 | +- c.Close() |
2329 | +- panic("intentional panic") |
2330 | +- }, |
2331 | +- } |
2332 | +- ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { |
2333 | +- handler[r.URL.Path](w, r) |
2334 | +- })) |
2335 | +- defer ts.Close() |
2336 | +- |
2337 | +- var mu sync.Mutex // guard stateLog and connID |
2338 | +- var stateLog = map[int][]ConnState{} |
2339 | +- var connID = map[net.Conn]int{} |
2340 | +- |
2341 | +- ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) |
2342 | +- ts.Config.ConnState = func(c net.Conn, state ConnState) { |
2343 | +- if c == nil { |
2344 | +- t.Error("nil conn seen in state %s", state) |
2345 | +- return |
2346 | +- } |
2347 | +- mu.Lock() |
2348 | +- defer mu.Unlock() |
2349 | +- id, ok := connID[c] |
2350 | +- if !ok { |
2351 | +- id = len(connID) + 1 |
2352 | +- connID[c] = id |
2353 | +- } |
2354 | +- stateLog[id] = append(stateLog[id], state) |
2355 | +- } |
2356 | +- ts.Start() |
2357 | +- |
2358 | +- mustGet(t, ts.URL+"/") |
2359 | +- mustGet(t, ts.URL+"/close") |
2360 | +- |
2361 | +- mustGet(t, ts.URL+"/") |
2362 | +- mustGet(t, ts.URL+"/", "Connection", "close") |
2363 | +- |
2364 | +- mustGet(t, ts.URL+"/hijack") |
2365 | +- mustGet(t, ts.URL+"/hijack-panic") |
2366 | +- |
2367 | +- // New->Closed |
2368 | +- { |
2369 | +- c, err := net.Dial("tcp", ts.Listener.Addr().String()) |
2370 | +- if err != nil { |
2371 | +- t.Fatal(err) |
2372 | +- } |
2373 | +- c.Close() |
2374 | +- } |
2375 | +- |
2376 | +- // New->Active->Closed |
2377 | +- { |
2378 | +- c, err := net.Dial("tcp", ts.Listener.Addr().String()) |
2379 | +- if err != nil { |
2380 | +- t.Fatal(err) |
2381 | +- } |
2382 | +- if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil { |
2383 | +- t.Fatal(err) |
2384 | +- } |
2385 | +- c.Close() |
2386 | +- } |
2387 | +- |
2388 | +- // New->Idle->Closed |
2389 | +- { |
2390 | +- c, err := net.Dial("tcp", ts.Listener.Addr().String()) |
2391 | +- if err != nil { |
2392 | +- t.Fatal(err) |
2393 | +- } |
2394 | +- if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil { |
2395 | +- t.Fatal(err) |
2396 | +- } |
2397 | +- res, err := ReadResponse(bufio.NewReader(c), nil) |
2398 | +- if err != nil { |
2399 | +- t.Fatal(err) |
2400 | +- } |
2401 | +- if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { |
2402 | +- t.Fatal(err) |
2403 | +- } |
2404 | +- c.Close() |
2405 | +- } |
2406 | +- |
2407 | +- want := map[int][]ConnState{ |
2408 | +- 1: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed}, |
2409 | +- 2: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed}, |
2410 | +- 3: []ConnState{StateNew, StateActive, StateHijacked}, |
2411 | +- 4: []ConnState{StateNew, StateActive, StateHijacked}, |
2412 | +- 5: []ConnState{StateNew, StateClosed}, |
2413 | +- 6: []ConnState{StateNew, StateActive, StateClosed}, |
2414 | +- 7: []ConnState{StateNew, StateActive, StateIdle, StateClosed}, |
2415 | +- } |
2416 | +- logString := func(m map[int][]ConnState) string { |
2417 | +- var b bytes.Buffer |
2418 | +- for id, l := range m { |
2419 | +- fmt.Fprintf(&b, "Conn %d: ", id) |
2420 | +- for _, s := range l { |
2421 | +- fmt.Fprintf(&b, "%s ", s) |
2422 | +- } |
2423 | +- b.WriteString("\n") |
2424 | +- } |
2425 | +- return b.String() |
2426 | +- } |
2427 | +- |
2428 | +- for i := 0; i < 5; i++ { |
2429 | +- time.Sleep(time.Duration(i) * 50 * time.Millisecond) |
2430 | +- mu.Lock() |
2431 | +- match := reflect.DeepEqual(stateLog, want) |
2432 | +- mu.Unlock() |
2433 | +- if match { |
2434 | +- return |
2435 | +- } |
2436 | +- } |
2437 | +- |
2438 | +- mu.Lock() |
2439 | +- t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want)) |
2440 | +- mu.Unlock() |
2441 | +-} |
2442 | +- |
2443 | +-func mustGet(t *testing.T, url string, headers ...string) { |
2444 | +- req, err := NewRequest("GET", url, nil) |
2445 | +- if err != nil { |
2446 | +- t.Fatal(err) |
2447 | +- } |
2448 | +- for len(headers) > 0 { |
2449 | +- req.Header.Add(headers[0], headers[1]) |
2450 | +- headers = headers[2:] |
2451 | +- } |
2452 | +- res, err := DefaultClient.Do(req) |
2453 | +- if err != nil { |
2454 | +- t.Errorf("Error fetching %s: %v", url, err) |
2455 | +- return |
2456 | +- } |
2457 | +- _, err = ioutil.ReadAll(res.Body) |
2458 | +- defer res.Body.Close() |
2459 | +- if err != nil { |
2460 | +- t.Errorf("Error reading %s: %v", url, err) |
2461 | +- } |
2462 | +-} |
2463 | +- |
2464 | +-func TestServerKeepAlivesEnabled(t *testing.T) { |
2465 | +- defer afterTest(t) |
2466 | +- ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) |
2467 | +- ts.Config.SetKeepAlivesEnabled(false) |
2468 | +- ts.Start() |
2469 | +- defer ts.Close() |
2470 | +- res, err := Get(ts.URL) |
2471 | +- if err != nil { |
2472 | +- t.Fatal(err) |
2473 | +- } |
2474 | +- defer res.Body.Close() |
2475 | +- if !res.Close { |
2476 | +- t.Errorf("Body.Close == false; want true") |
2477 | +- } |
2478 | +-} |
2479 | +- |
2480 | +-func TestServerConnStateNew(t *testing.T) { |
2481 | +- sawNew := false // if the test is buggy, we'll race on this variable. |
2482 | +- srv := &Server{ |
2483 | +- ConnState: func(c net.Conn, state ConnState) { |
2484 | +- if state == StateNew { |
2485 | +- sawNew = true // testing that this write isn't racy |
2486 | +- } |
2487 | +- }, |
2488 | +- Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}), // irrelevant |
2489 | +- } |
2490 | +- srv.Serve(&oneConnListener{ |
2491 | +- conn: &rwTestConn{ |
2492 | +- Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"), |
2493 | +- Writer: ioutil.Discard, |
2494 | +- }, |
2495 | +- }) |
2496 | +- if !sawNew { // testing that this read isn't racy |
2497 | +- t.Error("StateNew not seen") |
2498 | +- } |
2499 | +-} |
2500 | +- |
2501 | +-func BenchmarkClientServer(b *testing.B) { |
2502 | +- b.ReportAllocs() |
2503 | +- b.StopTimer() |
2504 | +- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) { |
2505 | +- fmt.Fprintf(rw, "Hello world.\n") |
2506 | +- })) |
2507 | +- defer ts.Close() |
2508 | +- b.StartTimer() |
2509 | +- |
2510 | +- for i := 0; i < b.N; i++ { |
2511 | +- res, err := Get(ts.URL) |
2512 | +- if err != nil { |
2513 | +- b.Fatal("Get:", err) |
2514 | +- } |
2515 | +- all, err := ioutil.ReadAll(res.Body) |
2516 | +- res.Body.Close() |
2517 | +- if err != nil { |
2518 | +- b.Fatal("ReadAll:", err) |
2519 | +- } |
2520 | +- body := string(all) |
2521 | +- if body != "Hello world.\n" { |
2522 | +- b.Fatal("Got body:", body) |
2523 | +- } |
2524 | +- } |
2525 | +- |
2526 | +- b.StopTimer() |
2527 | +-} |
2528 | +- |
2529 | +-// A benchmark for profiling the server without the HTTP client code. |
2530 | +-// The client code runs in a subprocess. |
2531 | +-// |
2532 | +-// For use like: |
2533 | +-// $ go test -c |
2534 | +-// $ ./http.test -test.run=XX -test.bench=BenchmarkServer -test.benchtime=15s -test.cpuprofile=http.prof |
2535 | +-// $ go tool pprof http.test http.prof |
2536 | +-// (pprof) web |
2537 | +-func BenchmarkServer(b *testing.B) { |
2538 | +- b.ReportAllocs() |
2539 | +- // Child process mode; |
2540 | +- if url := os.Getenv("TEST_BENCH_SERVER_URL"); url != "" { |
2541 | +- n, err := strconv.Atoi(os.Getenv("TEST_BENCH_CLIENT_N")) |
2542 | +- if err != nil { |
2543 | +- panic(err) |
2544 | +- } |
2545 | +- for i := 0; i < n; i++ { |
2546 | +- res, err := Get(url) |
2547 | +- if err != nil { |
2548 | +- log.Panicf("Get: %v", err) |
2549 | +- } |
2550 | +- all, err := ioutil.ReadAll(res.Body) |
2551 | +- res.Body.Close() |
2552 | +- if err != nil { |
2553 | +- log.Panicf("ReadAll: %v", err) |
2554 | +- } |
2555 | +- body := string(all) |
2556 | +- if body != "Hello world.\n" { |
2557 | +- log.Panicf("Got body: %q", body) |
2558 | +- } |
2559 | +- } |
2560 | +- os.Exit(0) |
2561 | +- return |
2562 | +- } |
2563 | +- |
2564 | +- var res = []byte("Hello world.\n") |
2565 | +- b.StopTimer() |
2566 | +- ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) { |
2567 | +- rw.Header().Set("Content-Type", "text/html; charset=utf-8") |
2568 | +- rw.Write(res) |
2569 | +- })) |
2570 | +- defer ts.Close() |
2571 | +- b.StartTimer() |
2572 | +- |
2573 | +- cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer") |
2574 | +- cmd.Env = append([]string{ |
2575 | +- fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N), |
2576 | +- fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL), |
2577 | +- }, os.Environ()...) |
2578 | +- out, err := cmd.CombinedOutput() |
2579 | +- if err != nil { |
2580 | +- b.Errorf("Test failure: %v, with output: %s", err, out) |
2581 | +- } |
2582 | +-} |
2583 | +- |
2584 | +-func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) { |
2585 | +- b.ReportAllocs() |
2586 | +- req := reqBytes(`GET / HTTP/1.0 |
2587 | +-Host: golang.org |
2588 | +-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
2589 | +-User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17 |
2590 | +-Accept-Encoding: gzip,deflate,sdch |
2591 | +-Accept-Language: en-US,en;q=0.8 |
2592 | +-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 |
2593 | +-`) |
2594 | +- res := []byte("Hello world!\n") |
2595 | +- |
2596 | +- conn := &testConn{ |
2597 | +- // testConn.Close will not push into the channel |
2598 | +- // if it's full. |
2599 | +- closec: make(chan bool, 1), |
2600 | +- } |
2601 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
2602 | +- rw.Header().Set("Content-Type", "text/html; charset=utf-8") |
2603 | +- rw.Write(res) |
2604 | +- }) |
2605 | +- ln := new(oneConnListener) |
2606 | +- for i := 0; i < b.N; i++ { |
2607 | +- conn.readBuf.Reset() |
2608 | +- conn.writeBuf.Reset() |
2609 | +- conn.readBuf.Write(req) |
2610 | +- ln.conn = conn |
2611 | +- Serve(ln, handler) |
2612 | +- <-conn.closec |
2613 | +- } |
2614 | +-} |
2615 | +- |
2616 | +-// repeatReader reads content count times, then EOFs. |
2617 | +-type repeatReader struct { |
2618 | +- content []byte |
2619 | +- count int |
2620 | +- off int |
2621 | +-} |
2622 | +- |
2623 | +-func (r *repeatReader) Read(p []byte) (n int, err error) { |
2624 | +- if r.count <= 0 { |
2625 | +- return 0, io.EOF |
2626 | +- } |
2627 | +- n = copy(p, r.content[r.off:]) |
2628 | +- r.off += n |
2629 | +- if r.off == len(r.content) { |
2630 | +- r.count-- |
2631 | +- r.off = 0 |
2632 | +- } |
2633 | +- return |
2634 | +-} |
2635 | +- |
2636 | +-func BenchmarkServerFakeConnWithKeepAlive(b *testing.B) { |
2637 | +- b.ReportAllocs() |
2638 | +- |
2639 | +- req := reqBytes(`GET / HTTP/1.1 |
2640 | +-Host: golang.org |
2641 | +-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
2642 | +-User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17 |
2643 | +-Accept-Encoding: gzip,deflate,sdch |
2644 | +-Accept-Language: en-US,en;q=0.8 |
2645 | +-Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 |
2646 | +-`) |
2647 | +- res := []byte("Hello world!\n") |
2648 | +- |
2649 | +- conn := &rwTestConn{ |
2650 | +- Reader: &repeatReader{content: req, count: b.N}, |
2651 | +- Writer: ioutil.Discard, |
2652 | +- closec: make(chan bool, 1), |
2653 | +- } |
2654 | +- handled := 0 |
2655 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
2656 | +- handled++ |
2657 | +- rw.Header().Set("Content-Type", "text/html; charset=utf-8") |
2658 | +- rw.Write(res) |
2659 | +- }) |
2660 | +- ln := &oneConnListener{conn: conn} |
2661 | +- go Serve(ln, handler) |
2662 | +- <-conn.closec |
2663 | +- if b.N != handled { |
2664 | +- b.Errorf("b.N=%d but handled %d", b.N, handled) |
2665 | +- } |
2666 | +-} |
2667 | +- |
2668 | +-// same as above, but representing the most simple possible request |
2669 | +-// and handler. Notably: the handler does not call rw.Header(). |
2670 | +-func BenchmarkServerFakeConnWithKeepAliveLite(b *testing.B) { |
2671 | +- b.ReportAllocs() |
2672 | +- |
2673 | +- req := reqBytes(`GET / HTTP/1.1 |
2674 | +-Host: golang.org |
2675 | +-`) |
2676 | +- res := []byte("Hello world!\n") |
2677 | +- |
2678 | +- conn := &rwTestConn{ |
2679 | +- Reader: &repeatReader{content: req, count: b.N}, |
2680 | +- Writer: ioutil.Discard, |
2681 | +- closec: make(chan bool, 1), |
2682 | +- } |
2683 | +- handled := 0 |
2684 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
2685 | +- handled++ |
2686 | +- rw.Write(res) |
2687 | +- }) |
2688 | +- ln := &oneConnListener{conn: conn} |
2689 | +- go Serve(ln, handler) |
2690 | +- <-conn.closec |
2691 | +- if b.N != handled { |
2692 | +- b.Errorf("b.N=%d but handled %d", b.N, handled) |
2693 | +- } |
2694 | +-} |
2695 | +- |
2696 | +-const someResponse = "<html>some response</html>" |
2697 | +- |
2698 | +-// A Response that's just no bigger than 2KB, the buffer-before-chunking threshold. |
2699 | +-var response = bytes.Repeat([]byte(someResponse), 2<<10/len(someResponse)) |
2700 | +- |
2701 | +-// Both Content-Type and Content-Length set. Should be no buffering. |
2702 | +-func BenchmarkServerHandlerTypeLen(b *testing.B) { |
2703 | +- benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) { |
2704 | +- w.Header().Set("Content-Type", "text/html") |
2705 | +- w.Header().Set("Content-Length", strconv.Itoa(len(response))) |
2706 | +- w.Write(response) |
2707 | +- })) |
2708 | +-} |
2709 | +- |
2710 | +-// A Content-Type is set, but no length. No sniffing, but will count the Content-Length. |
2711 | +-func BenchmarkServerHandlerNoLen(b *testing.B) { |
2712 | +- benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) { |
2713 | +- w.Header().Set("Content-Type", "text/html") |
2714 | +- w.Write(response) |
2715 | +- })) |
2716 | +-} |
2717 | +- |
2718 | +-// A Content-Length is set, but the Content-Type will be sniffed. |
2719 | +-func BenchmarkServerHandlerNoType(b *testing.B) { |
2720 | +- benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) { |
2721 | +- w.Header().Set("Content-Length", strconv.Itoa(len(response))) |
2722 | +- w.Write(response) |
2723 | +- })) |
2724 | +-} |
2725 | +- |
2726 | +-// Neither a Content-Type or Content-Length, so sniffed and counted. |
2727 | +-func BenchmarkServerHandlerNoHeader(b *testing.B) { |
2728 | +- benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) { |
2729 | +- w.Write(response) |
2730 | +- })) |
2731 | +-} |
2732 | +- |
2733 | +-func benchmarkHandler(b *testing.B, h Handler) { |
2734 | +- b.ReportAllocs() |
2735 | +- req := reqBytes(`GET / HTTP/1.1 |
2736 | +-Host: golang.org |
2737 | +-`) |
2738 | +- conn := &rwTestConn{ |
2739 | +- Reader: &repeatReader{content: req, count: b.N}, |
2740 | +- Writer: ioutil.Discard, |
2741 | +- closec: make(chan bool, 1), |
2742 | +- } |
2743 | +- handled := 0 |
2744 | +- handler := HandlerFunc(func(rw ResponseWriter, r *Request) { |
2745 | +- handled++ |
2746 | +- h.ServeHTTP(rw, r) |
2747 | +- }) |
2748 | +- ln := &oneConnListener{conn: conn} |
2749 | +- go Serve(ln, handler) |
2750 | +- <-conn.closec |
2751 | +- if b.N != handled { |
2752 | +- b.Errorf("b.N=%d but handled %d", b.N, handled) |
2753 | +- } |
2754 | +-} |
2755 | +- |
2756 | +-func BenchmarkServerHijack(b *testing.B) { |
2757 | +- b.ReportAllocs() |
2758 | +- req := reqBytes(`GET / HTTP/1.1 |
2759 | +-Host: golang.org |
2760 | +-`) |
2761 | +- h := HandlerFunc(func(w ResponseWriter, r *Request) { |
2762 | +- conn, _, err := w.(Hijacker).Hijack() |
2763 | +- if err != nil { |
2764 | +- panic(err) |
2765 | +- } |
2766 | +- conn.Close() |
2767 | +- }) |
2768 | +- conn := &rwTestConn{ |
2769 | +- Writer: ioutil.Discard, |
2770 | +- closec: make(chan bool, 1), |
2771 | +- } |
2772 | +- ln := &oneConnListener{conn: conn} |
2773 | +- for i := 0; i < b.N; i++ { |
2774 | +- conn.Reader = bytes.NewReader(req) |
2775 | +- ln.conn = conn |
2776 | +- Serve(ln, h) |
2777 | +- <-conn.closec |
2778 | +- } |
2779 | +-} |
2780 | + |
2781 | +=== modified file 'http13client/server.go' |
2782 | +--- http13client/server.go 2014-03-19 20:20:19 +0000 |
2783 | ++++ http13client/server.go 2014-03-19 22:27:37 +0000 |
2784 | +@@ -2,1984 +2,17 @@ |
2785 | + // Use of this source code is governed by a BSD-style |
2786 | + // license that can be found in the LICENSE file. |
2787 | + |
2788 | +-// HTTP server. See RFC 2616. |
2789 | +- |
2790 | + package http |
2791 | + |
2792 | + import ( |
2793 | +- "bufio" |
2794 | +- "crypto/tls" |
2795 | +- "errors" |
2796 | + "fmt" |
2797 | + "io" |
2798 | + "io/ioutil" |
2799 | + "log" |
2800 | + "net" |
2801 | +- "net/url" |
2802 | +- "os" |
2803 | +- "path" |
2804 | +- "runtime" |
2805 | +- "strconv" |
2806 | + "strings" |
2807 | + "sync" |
2808 | +- "sync/atomic" |
2809 | +- "time" |
2810 | +-) |
2811 | +- |
2812 | +-// Errors introduced by the HTTP server. |
2813 | +-var ( |
2814 | +- ErrWriteAfterFlush = errors.New("Conn.Write called after Flush") |
2815 | +- ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body") |
2816 | +- ErrHijacked = errors.New("Conn has been hijacked") |
2817 | +- ErrContentLength = errors.New("Conn.Write wrote more than the declared Content-Length") |
2818 | +-) |
2819 | +- |
2820 | +-// Objects implementing the Handler interface can be |
2821 | +-// registered to serve a particular path or subtree |
2822 | +-// in the HTTP server. |
2823 | +-// |
2824 | +-// ServeHTTP should write reply headers and data to the ResponseWriter |
2825 | +-// and then return. Returning signals that the request is finished |
2826 | +-// and that the HTTP server can move on to the next request on |
2827 | +-// the connection. |
2828 | +-type Handler interface { |
2829 | +- ServeHTTP(ResponseWriter, *Request) |
2830 | +-} |
2831 | +- |
2832 | +-// A ResponseWriter interface is used by an HTTP handler to |
2833 | +-// construct an HTTP response. |
2834 | +-type ResponseWriter interface { |
2835 | +- // Header returns the header map that will be sent by WriteHeader. |
2836 | +- // Changing the header after a call to WriteHeader (or Write) has |
2837 | +- // no effect. |
2838 | +- Header() Header |
2839 | +- |
2840 | +- // Write writes the data to the connection as part of an HTTP reply. |
2841 | +- // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) |
2842 | +- // before writing the data. If the Header does not contain a |
2843 | +- // Content-Type line, Write adds a Content-Type set to the result of passing |
2844 | +- // the initial 512 bytes of written data to DetectContentType. |
2845 | +- Write([]byte) (int, error) |
2846 | +- |
2847 | +- // WriteHeader sends an HTTP response header with status code. |
2848 | +- // If WriteHeader is not called explicitly, the first call to Write |
2849 | +- // will trigger an implicit WriteHeader(http.StatusOK). |
2850 | +- // Thus explicit calls to WriteHeader are mainly used to |
2851 | +- // send error codes. |
2852 | +- WriteHeader(int) |
2853 | +-} |
2854 | +- |
2855 | +-// The Flusher interface is implemented by ResponseWriters that allow |
2856 | +-// an HTTP handler to flush buffered data to the client. |
2857 | +-// |
2858 | +-// Note that even for ResponseWriters that support Flush, |
2859 | +-// if the client is connected through an HTTP proxy, |
2860 | +-// the buffered data may not reach the client until the response |
2861 | +-// completes. |
2862 | +-type Flusher interface { |
2863 | +- // Flush sends any buffered data to the client. |
2864 | +- Flush() |
2865 | +-} |
2866 | +- |
2867 | +-// The Hijacker interface is implemented by ResponseWriters that allow |
2868 | +-// an HTTP handler to take over the connection. |
2869 | +-type Hijacker interface { |
2870 | +- // Hijack lets the caller take over the connection. |
2871 | +- // After a call to Hijack(), the HTTP server library |
2872 | +- // will not do anything else with the connection. |
2873 | +- // It becomes the caller's responsibility to manage |
2874 | +- // and close the connection. |
2875 | +- Hijack() (net.Conn, *bufio.ReadWriter, error) |
2876 | +-} |
2877 | +- |
2878 | +-// The CloseNotifier interface is implemented by ResponseWriters which |
2879 | +-// allow detecting when the underlying connection has gone away. |
2880 | +-// |
2881 | +-// This mechanism can be used to cancel long operations on the server |
2882 | +-// if the client has disconnected before the response is ready. |
2883 | +-type CloseNotifier interface { |
2884 | +- // CloseNotify returns a channel that receives a single value |
2885 | +- // when the client connection has gone away. |
2886 | +- CloseNotify() <-chan bool |
2887 | +-} |
2888 | +- |
2889 | +-// A conn represents the server side of an HTTP connection. |
2890 | +-type conn struct { |
2891 | +- remoteAddr string // network address of remote side |
2892 | +- server *Server // the Server on which the connection arrived |
2893 | +- rwc net.Conn // i/o connection |
2894 | +- sr liveSwitchReader // where the LimitReader reads from; usually the rwc |
2895 | +- lr *io.LimitedReader // io.LimitReader(sr) |
2896 | +- buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc |
2897 | +- tlsState *tls.ConnectionState // or nil when not using TLS |
2898 | +- |
2899 | +- mu sync.Mutex // guards the following |
2900 | +- clientGone bool // if client has disconnected mid-request |
2901 | +- closeNotifyc chan bool // made lazily |
2902 | +- hijackedv bool // connection has been hijacked by handler |
2903 | +-} |
2904 | +- |
2905 | +-func (c *conn) hijacked() bool { |
2906 | +- c.mu.Lock() |
2907 | +- defer c.mu.Unlock() |
2908 | +- return c.hijackedv |
2909 | +-} |
2910 | +- |
2911 | +-func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { |
2912 | +- c.mu.Lock() |
2913 | +- defer c.mu.Unlock() |
2914 | +- if c.hijackedv { |
2915 | +- return nil, nil, ErrHijacked |
2916 | +- } |
2917 | +- if c.closeNotifyc != nil { |
2918 | +- return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier") |
2919 | +- } |
2920 | +- c.hijackedv = true |
2921 | +- rwc = c.rwc |
2922 | +- buf = c.buf |
2923 | +- c.rwc = nil |
2924 | +- c.buf = nil |
2925 | +- c.setState(rwc, StateHijacked) |
2926 | +- return |
2927 | +-} |
2928 | +- |
2929 | +-func (c *conn) closeNotify() <-chan bool { |
2930 | +- c.mu.Lock() |
2931 | +- defer c.mu.Unlock() |
2932 | +- if c.closeNotifyc == nil { |
2933 | +- c.closeNotifyc = make(chan bool, 1) |
2934 | +- if c.hijackedv { |
2935 | +- // to obey the function signature, even though |
2936 | +- // it'll never receive a value. |
2937 | +- return c.closeNotifyc |
2938 | +- } |
2939 | +- pr, pw := io.Pipe() |
2940 | +- |
2941 | +- readSource := c.sr.r |
2942 | +- c.sr.Lock() |
2943 | +- c.sr.r = pr |
2944 | +- c.sr.Unlock() |
2945 | +- go func() { |
2946 | +- _, err := io.Copy(pw, readSource) |
2947 | +- if err == nil { |
2948 | +- err = io.EOF |
2949 | +- } |
2950 | +- pw.CloseWithError(err) |
2951 | +- c.noteClientGone() |
2952 | +- }() |
2953 | +- } |
2954 | +- return c.closeNotifyc |
2955 | +-} |
2956 | +- |
2957 | +-func (c *conn) noteClientGone() { |
2958 | +- c.mu.Lock() |
2959 | +- defer c.mu.Unlock() |
2960 | +- if c.closeNotifyc != nil && !c.clientGone { |
2961 | +- c.closeNotifyc <- true |
2962 | +- } |
2963 | +- c.clientGone = true |
2964 | +-} |
2965 | +- |
2966 | +-// A switchReader can have its Reader changed at runtime. |
2967 | +-// It's not safe for concurrent Reads and switches. |
2968 | +-type switchReader struct { |
2969 | +- io.Reader |
2970 | +-} |
2971 | +- |
2972 | +-// A switchWriter can have its Writer changed at runtime. |
2973 | +-// It's not safe for concurrent Writes and switches. |
2974 | +-type switchWriter struct { |
2975 | +- io.Writer |
2976 | +-} |
2977 | +- |
2978 | +-// A liveSwitchReader is a switchReader that's safe for concurrent |
2979 | +-// reads and switches, if its mutex is held. |
2980 | +-type liveSwitchReader struct { |
2981 | +- sync.Mutex |
2982 | +- r io.Reader |
2983 | +-} |
2984 | +- |
2985 | +-func (sr *liveSwitchReader) Read(p []byte) (n int, err error) { |
2986 | +- sr.Lock() |
2987 | +- r := sr.r |
2988 | +- sr.Unlock() |
2989 | +- return r.Read(p) |
2990 | +-} |
2991 | +- |
2992 | +-// This should be >= 512 bytes for DetectContentType, |
2993 | +-// but otherwise it's somewhat arbitrary. |
2994 | +-const bufferBeforeChunkingSize = 2048 |
2995 | +- |
2996 | +-// chunkWriter writes to a response's conn buffer, and is the writer |
2997 | +-// wrapped by the response.bufw buffered writer. |
2998 | +-// |
2999 | +-// chunkWriter also is responsible for finalizing the Header, including |
3000 | +-// conditionally setting the Content-Type and setting a Content-Length |
3001 | +-// in cases where the handler's final output is smaller than the buffer |
3002 | +-// size. It also conditionally adds chunk headers, when in chunking mode. |
3003 | +-// |
3004 | +-// See the comment above (*response).Write for the entire write flow. |
3005 | +-type chunkWriter struct { |
3006 | +- res *response |
3007 | +- |
3008 | +- // header is either nil or a deep clone of res.handlerHeader |
3009 | +- // at the time of res.WriteHeader, if res.WriteHeader is |
3010 | +- // called and extra buffering is being done to calculate |
3011 | +- // Content-Type and/or Content-Length. |
3012 | +- header Header |
3013 | +- |
3014 | +- // wroteHeader tells whether the header's been written to "the |
3015 | +- // wire" (or rather: w.conn.buf). this is unlike |
3016 | +- // (*response).wroteHeader, which tells only whether it was |
3017 | +- // logically written. |
3018 | +- wroteHeader bool |
3019 | +- |
3020 | +- // set by the writeHeader method: |
3021 | +- chunking bool // using chunked transfer encoding for reply body |
3022 | +-} |
3023 | +- |
3024 | +-var ( |
3025 | +- crlf = []byte("\r\n") |
3026 | +- colonSpace = []byte(": ") |
3027 | +-) |
3028 | +- |
3029 | +-func (cw *chunkWriter) Write(p []byte) (n int, err error) { |
3030 | +- if !cw.wroteHeader { |
3031 | +- cw.writeHeader(p) |
3032 | +- } |
3033 | +- if cw.res.req.Method == "HEAD" { |
3034 | +- // Eat writes. |
3035 | +- return len(p), nil |
3036 | +- } |
3037 | +- if cw.chunking { |
3038 | +- _, err = fmt.Fprintf(cw.res.conn.buf, "%x\r\n", len(p)) |
3039 | +- if err != nil { |
3040 | +- cw.res.conn.rwc.Close() |
3041 | +- return |
3042 | +- } |
3043 | +- } |
3044 | +- n, err = cw.res.conn.buf.Write(p) |
3045 | +- if cw.chunking && err == nil { |
3046 | +- _, err = cw.res.conn.buf.Write(crlf) |
3047 | +- } |
3048 | +- if err != nil { |
3049 | +- cw.res.conn.rwc.Close() |
3050 | +- } |
3051 | +- return |
3052 | +-} |
3053 | +- |
3054 | +-func (cw *chunkWriter) flush() { |
3055 | +- if !cw.wroteHeader { |
3056 | +- cw.writeHeader(nil) |
3057 | +- } |
3058 | +- cw.res.conn.buf.Flush() |
3059 | +-} |
3060 | +- |
3061 | +-func (cw *chunkWriter) close() { |
3062 | +- if !cw.wroteHeader { |
3063 | +- cw.writeHeader(nil) |
3064 | +- } |
3065 | +- if cw.chunking { |
3066 | +- // zero EOF chunk, trailer key/value pairs (currently |
3067 | +- // unsupported in Go's server), followed by a blank |
3068 | +- // line. |
3069 | +- cw.res.conn.buf.WriteString("0\r\n\r\n") |
3070 | +- } |
3071 | +-} |
3072 | +- |
3073 | +-// A response represents the server side of an HTTP response. |
3074 | +-type response struct { |
3075 | +- conn *conn |
3076 | +- req *Request // request for this response |
3077 | +- wroteHeader bool // reply header has been (logically) written |
3078 | +- wroteContinue bool // 100 Continue response was written |
3079 | +- |
3080 | +- w *bufio.Writer // buffers output in chunks to chunkWriter |
3081 | +- cw chunkWriter |
3082 | +- sw *switchWriter // of the bufio.Writer, for return to putBufioWriter |
3083 | +- |
3084 | +- // handlerHeader is the Header that Handlers get access to, |
3085 | +- // which may be retained and mutated even after WriteHeader. |
3086 | +- // handlerHeader is copied into cw.header at WriteHeader |
3087 | +- // time, and privately mutated thereafter. |
3088 | +- handlerHeader Header |
3089 | +- calledHeader bool // handler accessed handlerHeader via Header |
3090 | +- |
3091 | +- written int64 // number of bytes written in body |
3092 | +- contentLength int64 // explicitly-declared Content-Length; or -1 |
3093 | +- status int // status code passed to WriteHeader |
3094 | +- |
3095 | +- // close connection after this reply. set on request and |
3096 | +- // updated after response from handler if there's a |
3097 | +- // "Connection: keep-alive" response header and a |
3098 | +- // Content-Length. |
3099 | +- closeAfterReply bool |
3100 | +- |
3101 | +- // requestBodyLimitHit is set by requestTooLarge when |
3102 | +- // maxBytesReader hits its max size. It is checked in |
3103 | +- // WriteHeader, to make sure we don't consume the |
3104 | +- // remaining request body to try to advance to the next HTTP |
3105 | +- // request. Instead, when this is set, we stop reading |
3106 | +- // subsequent requests on this connection and stop reading |
3107 | +- // input from it. |
3108 | +- requestBodyLimitHit bool |
3109 | +- |
3110 | +- handlerDone bool // set true when the handler exits |
3111 | +- |
3112 | +- // Buffers for Date and Content-Length |
3113 | +- dateBuf [len(TimeFormat)]byte |
3114 | +- clenBuf [10]byte |
3115 | +-} |
3116 | +- |
3117 | +-// requestTooLarge is called by maxBytesReader when too much input has |
3118 | +-// been read from the client. |
3119 | +-func (w *response) requestTooLarge() { |
3120 | +- w.closeAfterReply = true |
3121 | +- w.requestBodyLimitHit = true |
3122 | +- if !w.wroteHeader { |
3123 | +- w.Header().Set("Connection", "close") |
3124 | +- } |
3125 | +-} |
3126 | +- |
3127 | +-// needsSniff reports whether a Content-Type still needs to be sniffed. |
3128 | +-func (w *response) needsSniff() bool { |
3129 | +- _, haveType := w.handlerHeader["Content-Type"] |
3130 | +- return !w.cw.wroteHeader && !haveType && w.written < sniffLen |
3131 | +-} |
3132 | +- |
3133 | +-// writerOnly hides an io.Writer value's optional ReadFrom method |
3134 | +-// from io.Copy. |
3135 | +-type writerOnly struct { |
3136 | +- io.Writer |
3137 | +-} |
3138 | +- |
3139 | +-func srcIsRegularFile(src io.Reader) (isRegular bool, err error) { |
3140 | +- switch v := src.(type) { |
3141 | +- case *os.File: |
3142 | +- fi, err := v.Stat() |
3143 | +- if err != nil { |
3144 | +- return false, err |
3145 | +- } |
3146 | +- return fi.Mode().IsRegular(), nil |
3147 | +- case *io.LimitedReader: |
3148 | +- return srcIsRegularFile(v.R) |
3149 | +- default: |
3150 | +- return |
3151 | +- } |
3152 | +-} |
3153 | +- |
3154 | +-// ReadFrom is here to optimize copying from an *os.File regular file |
3155 | +-// to a *net.TCPConn with sendfile. |
3156 | +-func (w *response) ReadFrom(src io.Reader) (n int64, err error) { |
3157 | +- // Our underlying w.conn.rwc is usually a *TCPConn (with its |
3158 | +- // own ReadFrom method). If not, or if our src isn't a regular |
3159 | +- // file, just fall back to the normal copy method. |
3160 | +- rf, ok := w.conn.rwc.(io.ReaderFrom) |
3161 | +- regFile, err := srcIsRegularFile(src) |
3162 | +- if err != nil { |
3163 | +- return 0, err |
3164 | +- } |
3165 | +- if !ok || !regFile { |
3166 | +- return io.Copy(writerOnly{w}, src) |
3167 | +- } |
3168 | +- |
3169 | +- // sendfile path: |
3170 | +- |
3171 | +- if !w.wroteHeader { |
3172 | +- w.WriteHeader(StatusOK) |
3173 | +- } |
3174 | +- |
3175 | +- if w.needsSniff() { |
3176 | +- n0, err := io.Copy(writerOnly{w}, io.LimitReader(src, sniffLen)) |
3177 | +- n += n0 |
3178 | +- if err != nil { |
3179 | +- return n, err |
3180 | +- } |
3181 | +- } |
3182 | +- |
3183 | +- w.w.Flush() // get rid of any previous writes |
3184 | +- w.cw.flush() // make sure Header is written; flush data to rwc |
3185 | +- |
3186 | +- // Now that cw has been flushed, its chunking field is guaranteed initialized. |
3187 | +- if !w.cw.chunking && w.bodyAllowed() { |
3188 | +- n0, err := rf.ReadFrom(src) |
3189 | +- n += n0 |
3190 | +- w.written += n0 |
3191 | +- return n, err |
3192 | +- } |
3193 | +- |
3194 | +- n0, err := io.Copy(writerOnly{w}, src) |
3195 | +- n += n0 |
3196 | +- return n, err |
3197 | +-} |
3198 | +- |
3199 | +-// noLimit is an effective infinite upper bound for io.LimitedReader |
3200 | +-const noLimit int64 = (1 << 63) - 1 |
3201 | +- |
3202 | +-// debugServerConnections controls whether all server connections are wrapped |
3203 | +-// with a verbose logging wrapper. |
3204 | +-const debugServerConnections = false |
3205 | +- |
3206 | +-// Create new connection from rwc. |
3207 | +-func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) { |
3208 | +- c = new(conn) |
3209 | +- c.remoteAddr = rwc.RemoteAddr().String() |
3210 | +- c.server = srv |
3211 | +- c.rwc = rwc |
3212 | +- if debugServerConnections { |
3213 | +- c.rwc = newLoggingConn("server", c.rwc) |
3214 | +- } |
3215 | +- c.sr = liveSwitchReader{r: c.rwc} |
3216 | +- c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader) |
3217 | +- br := newBufioReader(c.lr) |
3218 | +- bw := newBufioWriterSize(c.rwc, 4<<10) |
3219 | +- c.buf = bufio.NewReadWriter(br, bw) |
3220 | +- return c, nil |
3221 | +-} |
3222 | +- |
3223 | +-// TODO: use a sync.Cache instead |
3224 | +-var ( |
3225 | +- bufioReaderCache = make(chan *bufio.Reader, 4) |
3226 | +- bufioWriterCache2k = make(chan *bufio.Writer, 4) |
3227 | +- bufioWriterCache4k = make(chan *bufio.Writer, 4) |
3228 | +-) |
3229 | +- |
3230 | +-func bufioWriterCache(size int) chan *bufio.Writer { |
3231 | +- switch size { |
3232 | +- case 2 << 10: |
3233 | +- return bufioWriterCache2k |
3234 | +- case 4 << 10: |
3235 | +- return bufioWriterCache4k |
3236 | +- } |
3237 | +- return nil |
3238 | +-} |
3239 | +- |
3240 | +-func newBufioReader(r io.Reader) *bufio.Reader { |
3241 | +- select { |
3242 | +- case p := <-bufioReaderCache: |
3243 | +- p.Reset(r) |
3244 | +- return p |
3245 | +- default: |
3246 | +- return bufio.NewReader(r) |
3247 | +- } |
3248 | +-} |
3249 | +- |
3250 | +-func putBufioReader(br *bufio.Reader) { |
3251 | +- br.Reset(nil) |
3252 | +- select { |
3253 | +- case bufioReaderCache <- br: |
3254 | +- default: |
3255 | +- } |
3256 | +-} |
3257 | +- |
3258 | +-func newBufioWriterSize(w io.Writer, size int) *bufio.Writer { |
3259 | +- select { |
3260 | +- case p := <-bufioWriterCache(size): |
3261 | +- p.Reset(w) |
3262 | +- return p |
3263 | +- default: |
3264 | +- return bufio.NewWriterSize(w, size) |
3265 | +- } |
3266 | +-} |
3267 | +- |
3268 | +-func putBufioWriter(bw *bufio.Writer) { |
3269 | +- bw.Reset(nil) |
3270 | +- select { |
3271 | +- case bufioWriterCache(bw.Available()) <- bw: |
3272 | +- default: |
3273 | +- } |
3274 | +-} |
3275 | +- |
3276 | +-// DefaultMaxHeaderBytes is the maximum permitted size of the headers |
3277 | +-// in an HTTP request. |
3278 | +-// This can be overridden by setting Server.MaxHeaderBytes. |
3279 | +-const DefaultMaxHeaderBytes = 1 << 20 // 1 MB |
3280 | +- |
3281 | +-func (srv *Server) maxHeaderBytes() int { |
3282 | +- if srv.MaxHeaderBytes > 0 { |
3283 | +- return srv.MaxHeaderBytes |
3284 | +- } |
3285 | +- return DefaultMaxHeaderBytes |
3286 | +-} |
3287 | +- |
3288 | +-func (srv *Server) initialLimitedReaderSize() int64 { |
3289 | +- return int64(srv.maxHeaderBytes()) + 4096 // bufio slop |
3290 | +-} |
3291 | +- |
3292 | +-// wrapper around io.ReaderCloser which on first read, sends an |
3293 | +-// HTTP/1.1 100 Continue header |
3294 | +-type expectContinueReader struct { |
3295 | +- resp *response |
3296 | +- readCloser io.ReadCloser |
3297 | +- closed bool |
3298 | +-} |
3299 | +- |
3300 | +-func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { |
3301 | +- if ecr.closed { |
3302 | +- return 0, ErrBodyReadAfterClose |
3303 | +- } |
3304 | +- if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() { |
3305 | +- ecr.resp.wroteContinue = true |
3306 | +- ecr.resp.conn.buf.WriteString("HTTP/1.1 100 Continue\r\n\r\n") |
3307 | +- ecr.resp.conn.buf.Flush() |
3308 | +- } |
3309 | +- return ecr.readCloser.Read(p) |
3310 | +-} |
3311 | +- |
3312 | +-func (ecr *expectContinueReader) Close() error { |
3313 | +- ecr.closed = true |
3314 | +- return ecr.readCloser.Close() |
3315 | +-} |
3316 | +- |
3317 | +-// TimeFormat is the time format to use with |
3318 | +-// time.Parse and time.Time.Format when parsing |
3319 | +-// or generating times in HTTP headers. |
3320 | +-// It is like time.RFC1123 but hard codes GMT as the time zone. |
3321 | +-const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" |
3322 | +- |
3323 | +-// appendTime is a non-allocating version of []byte(t.UTC().Format(TimeFormat)) |
3324 | +-func appendTime(b []byte, t time.Time) []byte { |
3325 | +- const days = "SunMonTueWedThuFriSat" |
3326 | +- const months = "JanFebMarAprMayJunJulAugSepOctNovDec" |
3327 | +- |
3328 | +- t = t.UTC() |
3329 | +- yy, mm, dd := t.Date() |
3330 | +- hh, mn, ss := t.Clock() |
3331 | +- day := days[3*t.Weekday():] |
3332 | +- mon := months[3*(mm-1):] |
3333 | +- |
3334 | +- return append(b, |
3335 | +- day[0], day[1], day[2], ',', ' ', |
3336 | +- byte('0'+dd/10), byte('0'+dd%10), ' ', |
3337 | +- mon[0], mon[1], mon[2], ' ', |
3338 | +- byte('0'+yy/1000), byte('0'+(yy/100)%10), byte('0'+(yy/10)%10), byte('0'+yy%10), ' ', |
3339 | +- byte('0'+hh/10), byte('0'+hh%10), ':', |
3340 | +- byte('0'+mn/10), byte('0'+mn%10), ':', |
3341 | +- byte('0'+ss/10), byte('0'+ss%10), ' ', |
3342 | +- 'G', 'M', 'T') |
3343 | +-} |
3344 | +- |
3345 | +-var errTooLarge = errors.New("http: request too large") |
3346 | +- |
3347 | +-// Read next request from connection. |
3348 | +-func (c *conn) readRequest() (w *response, err error) { |
3349 | +- if c.hijacked() { |
3350 | +- return nil, ErrHijacked |
3351 | +- } |
3352 | +- |
3353 | +- if d := c.server.ReadTimeout; d != 0 { |
3354 | +- c.rwc.SetReadDeadline(time.Now().Add(d)) |
3355 | +- } |
3356 | +- if d := c.server.WriteTimeout; d != 0 { |
3357 | +- defer func() { |
3358 | +- c.rwc.SetWriteDeadline(time.Now().Add(d)) |
3359 | +- }() |
3360 | +- } |
3361 | +- |
3362 | +- c.lr.N = c.server.initialLimitedReaderSize() |
3363 | +- var req *Request |
3364 | +- if req, err = ReadRequest(c.buf.Reader); err != nil { |
3365 | +- if c.lr.N == 0 { |
3366 | +- return nil, errTooLarge |
3367 | +- } |
3368 | +- return nil, err |
3369 | +- } |
3370 | +- c.lr.N = noLimit |
3371 | +- |
3372 | +- req.RemoteAddr = c.remoteAddr |
3373 | +- req.TLS = c.tlsState |
3374 | +- |
3375 | +- w = &response{ |
3376 | +- conn: c, |
3377 | +- req: req, |
3378 | +- handlerHeader: make(Header), |
3379 | +- contentLength: -1, |
3380 | +- } |
3381 | +- w.cw.res = w |
3382 | +- w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize) |
3383 | +- return w, nil |
3384 | +-} |
3385 | +- |
3386 | +-func (w *response) Header() Header { |
3387 | +- if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader { |
3388 | +- // Accessing the header between logically writing it |
3389 | +- // and physically writing it means we need to allocate |
3390 | +- // a clone to snapshot the logically written state. |
3391 | +- w.cw.header = w.handlerHeader.clone() |
3392 | +- } |
3393 | +- w.calledHeader = true |
3394 | +- return w.handlerHeader |
3395 | +-} |
3396 | +- |
3397 | +-// maxPostHandlerReadBytes is the max number of Request.Body bytes not |
3398 | +-// consumed by a handler that the server will read from the client |
3399 | +-// in order to keep a connection alive. If there are more bytes than |
3400 | +-// this then the server to be paranoid instead sends a "Connection: |
3401 | +-// close" response. |
3402 | +-// |
3403 | +-// This number is approximately what a typical machine's TCP buffer |
3404 | +-// size is anyway. (if we have the bytes on the machine, we might as |
3405 | +-// well read them) |
3406 | +-const maxPostHandlerReadBytes = 256 << 10 |
3407 | +- |
3408 | +-func (w *response) WriteHeader(code int) { |
3409 | +- if w.conn.hijacked() { |
3410 | +- w.conn.server.logf("http: response.WriteHeader on hijacked connection") |
3411 | +- return |
3412 | +- } |
3413 | +- if w.wroteHeader { |
3414 | +- w.conn.server.logf("http: multiple response.WriteHeader calls") |
3415 | +- return |
3416 | +- } |
3417 | +- w.wroteHeader = true |
3418 | +- w.status = code |
3419 | +- |
3420 | +- if w.calledHeader && w.cw.header == nil { |
3421 | +- w.cw.header = w.handlerHeader.clone() |
3422 | +- } |
3423 | +- |
3424 | +- if cl := w.handlerHeader.get("Content-Length"); cl != "" { |
3425 | +- v, err := strconv.ParseInt(cl, 10, 64) |
3426 | +- if err == nil && v >= 0 { |
3427 | +- w.contentLength = v |
3428 | +- } else { |
3429 | +- w.conn.server.logf("http: invalid Content-Length of %q", cl) |
3430 | +- w.handlerHeader.Del("Content-Length") |
3431 | +- } |
3432 | +- } |
3433 | +-} |
3434 | +- |
3435 | +-// extraHeader is the set of headers sometimes added by chunkWriter.writeHeader. |
3436 | +-// This type is used to avoid extra allocations from cloning and/or populating |
3437 | +-// the response Header map and all its 1-element slices. |
3438 | +-type extraHeader struct { |
3439 | +- contentType string |
3440 | +- connection string |
3441 | +- transferEncoding string |
3442 | +- date []byte // written if not nil |
3443 | +- contentLength []byte // written if not nil |
3444 | +-} |
3445 | +- |
3446 | +-// Sorted the same as extraHeader.Write's loop. |
3447 | +-var extraHeaderKeys = [][]byte{ |
3448 | +- []byte("Content-Type"), |
3449 | +- []byte("Connection"), |
3450 | +- []byte("Transfer-Encoding"), |
3451 | +-} |
3452 | +- |
3453 | +-var ( |
3454 | +- headerContentLength = []byte("Content-Length: ") |
3455 | +- headerDate = []byte("Date: ") |
3456 | +-) |
3457 | +- |
3458 | +-// Write writes the headers described in h to w. |
3459 | +-// |
3460 | +-// This method has a value receiver, despite the somewhat large size |
3461 | +-// of h, because it prevents an allocation. The escape analysis isn't |
3462 | +-// smart enough to realize this function doesn't mutate h. |
3463 | +-func (h extraHeader) Write(w *bufio.Writer) { |
3464 | +- if h.date != nil { |
3465 | +- w.Write(headerDate) |
3466 | +- w.Write(h.date) |
3467 | +- w.Write(crlf) |
3468 | +- } |
3469 | +- if h.contentLength != nil { |
3470 | +- w.Write(headerContentLength) |
3471 | +- w.Write(h.contentLength) |
3472 | +- w.Write(crlf) |
3473 | +- } |
3474 | +- for i, v := range []string{h.contentType, h.connection, h.transferEncoding} { |
3475 | +- if v != "" { |
3476 | +- w.Write(extraHeaderKeys[i]) |
3477 | +- w.Write(colonSpace) |
3478 | +- w.WriteString(v) |
3479 | +- w.Write(crlf) |
3480 | +- } |
3481 | +- } |
3482 | +-} |
3483 | +- |
3484 | +-// writeHeader finalizes the header sent to the client and writes it |
3485 | +-// to cw.res.conn.buf. |
3486 | +-// |
3487 | +-// p is not written by writeHeader, but is the first chunk of the body |
3488 | +-// that will be written. It is sniffed for a Content-Type if none is |
3489 | +-// set explicitly. It's also used to set the Content-Length, if the |
3490 | +-// total body size was small and the handler has already finished |
3491 | +-// running. |
3492 | +-func (cw *chunkWriter) writeHeader(p []byte) { |
3493 | +- if cw.wroteHeader { |
3494 | +- return |
3495 | +- } |
3496 | +- cw.wroteHeader = true |
3497 | +- |
3498 | +- w := cw.res |
3499 | +- keepAlivesEnabled := w.conn.server.doKeepAlives() |
3500 | +- isHEAD := w.req.Method == "HEAD" |
3501 | +- |
3502 | +- // header is written out to w.conn.buf below. Depending on the |
3503 | +- // state of the handler, we either own the map or not. If we |
3504 | +- // don't own it, the exclude map is created lazily for |
3505 | +- // WriteSubset to remove headers. The setHeader struct holds |
3506 | +- // headers we need to add. |
3507 | +- header := cw.header |
3508 | +- owned := header != nil |
3509 | +- if !owned { |
3510 | +- header = w.handlerHeader |
3511 | +- } |
3512 | +- var excludeHeader map[string]bool |
3513 | +- delHeader := func(key string) { |
3514 | +- if owned { |
3515 | +- header.Del(key) |
3516 | +- return |
3517 | +- } |
3518 | +- if _, ok := header[key]; !ok { |
3519 | +- return |
3520 | +- } |
3521 | +- if excludeHeader == nil { |
3522 | +- excludeHeader = make(map[string]bool) |
3523 | +- } |
3524 | +- excludeHeader[key] = true |
3525 | +- } |
3526 | +- var setHeader extraHeader |
3527 | +- |
3528 | +- // If the handler is done but never sent a Content-Length |
3529 | +- // response header and this is our first (and last) write, set |
3530 | +- // it, even to zero. This helps HTTP/1.0 clients keep their |
3531 | +- // "keep-alive" connections alive. |
3532 | +- // Exceptions: 304/204/1xx responses never get Content-Length, and if |
3533 | +- // it was a HEAD request, we don't know the difference between |
3534 | +- // 0 actual bytes and 0 bytes because the handler noticed it |
3535 | +- // was a HEAD request and chose not to write anything. So for |
3536 | +- // HEAD, the handler should either write the Content-Length or |
3537 | +- // write non-zero bytes. If it's actually 0 bytes and the |
3538 | +- // handler never looked at the Request.Method, we just don't |
3539 | +- // send a Content-Length header. |
3540 | +- if w.handlerDone && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) { |
3541 | +- w.contentLength = int64(len(p)) |
3542 | +- setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10) |
3543 | +- } |
3544 | +- |
3545 | +- // If this was an HTTP/1.0 request with keep-alive and we sent a |
3546 | +- // Content-Length back, we can make this a keep-alive response ... |
3547 | +- if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled { |
3548 | +- sentLength := header.get("Content-Length") != "" |
3549 | +- if sentLength && header.get("Connection") == "keep-alive" { |
3550 | +- w.closeAfterReply = false |
3551 | +- } |
3552 | +- } |
3553 | +- |
3554 | +- // Check for a explicit (and valid) Content-Length header. |
3555 | +- hasCL := w.contentLength != -1 |
3556 | +- |
3557 | +- if w.req.wantsHttp10KeepAlive() && (isHEAD || hasCL) { |
3558 | +- _, connectionHeaderSet := header["Connection"] |
3559 | +- if !connectionHeaderSet { |
3560 | +- setHeader.connection = "keep-alive" |
3561 | +- } |
3562 | +- } else if !w.req.ProtoAtLeast(1, 1) || w.req.wantsClose() { |
3563 | +- w.closeAfterReply = true |
3564 | +- } |
3565 | +- |
3566 | +- if header.get("Connection") == "close" || !keepAlivesEnabled { |
3567 | +- w.closeAfterReply = true |
3568 | +- } |
3569 | +- |
3570 | +- // Per RFC 2616, we should consume the request body before |
3571 | +- // replying, if the handler hasn't already done so. But we |
3572 | +- // don't want to do an unbounded amount of reading here for |
3573 | +- // DoS reasons, so we only try up to a threshold. |
3574 | +- if w.req.ContentLength != 0 && !w.closeAfterReply { |
3575 | +- ecr, isExpecter := w.req.Body.(*expectContinueReader) |
3576 | +- if !isExpecter || ecr.resp.wroteContinue { |
3577 | +- n, _ := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1) |
3578 | +- if n >= maxPostHandlerReadBytes { |
3579 | +- w.requestTooLarge() |
3580 | +- delHeader("Connection") |
3581 | +- setHeader.connection = "close" |
3582 | +- } else { |
3583 | +- w.req.Body.Close() |
3584 | +- } |
3585 | +- } |
3586 | +- } |
3587 | +- |
3588 | +- code := w.status |
3589 | +- if !bodyAllowedForStatus(code) { |
3590 | +- // Must not have body. |
3591 | +- // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers" |
3592 | +- for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} { |
3593 | +- delHeader(k) |
3594 | +- } |
3595 | +- } else { |
3596 | +- // If no content type, apply sniffing algorithm to body. |
3597 | +- _, haveType := header["Content-Type"] |
3598 | +- if !haveType { |
3599 | +- setHeader.contentType = DetectContentType(p) |
3600 | +- } |
3601 | +- } |
3602 | +- |
3603 | +- if _, ok := header["Date"]; !ok { |
3604 | +- setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now()) |
3605 | +- } |
3606 | +- |
3607 | +- te := header.get("Transfer-Encoding") |
3608 | +- hasTE := te != "" |
3609 | +- if hasCL && hasTE && te != "identity" { |
3610 | +- // TODO: return an error if WriteHeader gets a return parameter |
3611 | +- // For now just ignore the Content-Length. |
3612 | +- w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", |
3613 | +- te, w.contentLength) |
3614 | +- delHeader("Content-Length") |
3615 | +- hasCL = false |
3616 | +- } |
3617 | +- |
3618 | +- if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) { |
3619 | +- // do nothing |
3620 | +- } else if code == StatusNoContent { |
3621 | +- delHeader("Transfer-Encoding") |
3622 | +- } else if hasCL { |
3623 | +- delHeader("Transfer-Encoding") |
3624 | +- } else if w.req.ProtoAtLeast(1, 1) { |
3625 | +- // HTTP/1.1 or greater: use chunked transfer encoding |
3626 | +- // to avoid closing the connection at EOF. |
3627 | +- // TODO: this blows away any custom or stacked Transfer-Encoding they |
3628 | +- // might have set. Deal with that as need arises once we have a valid |
3629 | +- // use case. |
3630 | +- cw.chunking = true |
3631 | +- setHeader.transferEncoding = "chunked" |
3632 | +- } else { |
3633 | +- // HTTP version < 1.1: cannot do chunked transfer |
3634 | +- // encoding and we don't know the Content-Length so |
3635 | +- // signal EOF by closing connection. |
3636 | +- w.closeAfterReply = true |
3637 | +- delHeader("Transfer-Encoding") // in case already set |
3638 | +- } |
3639 | +- |
3640 | +- // Cannot use Content-Length with non-identity Transfer-Encoding. |
3641 | +- if cw.chunking { |
3642 | +- delHeader("Content-Length") |
3643 | +- } |
3644 | +- if !w.req.ProtoAtLeast(1, 0) { |
3645 | +- return |
3646 | +- } |
3647 | +- |
3648 | +- if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) { |
3649 | +- delHeader("Connection") |
3650 | +- if w.req.ProtoAtLeast(1, 1) { |
3651 | +- setHeader.connection = "close" |
3652 | +- } |
3653 | +- } |
3654 | +- |
3655 | +- w.conn.buf.WriteString(statusLine(w.req, code)) |
3656 | +- cw.header.WriteSubset(w.conn.buf, excludeHeader) |
3657 | +- setHeader.Write(w.conn.buf.Writer) |
3658 | +- w.conn.buf.Write(crlf) |
3659 | +-} |
3660 | +- |
3661 | +-// statusLines is a cache of Status-Line strings, keyed by code (for |
3662 | +-// HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a |
3663 | +-// map keyed by struct of two fields. This map's max size is bounded |
3664 | +-// by 2*len(statusText), two protocol types for each known official |
3665 | +-// status code in the statusText map. |
3666 | +-var ( |
3667 | +- statusMu sync.RWMutex |
3668 | +- statusLines = make(map[int]string) |
3669 | +-) |
3670 | +- |
3671 | +-// statusLine returns a response Status-Line (RFC 2616 Section 6.1) |
3672 | +-// for the given request and response status code. |
3673 | +-func statusLine(req *Request, code int) string { |
3674 | +- // Fast path: |
3675 | +- key := code |
3676 | +- proto11 := req.ProtoAtLeast(1, 1) |
3677 | +- if !proto11 { |
3678 | +- key = -key |
3679 | +- } |
3680 | +- statusMu.RLock() |
3681 | +- line, ok := statusLines[key] |
3682 | +- statusMu.RUnlock() |
3683 | +- if ok { |
3684 | +- return line |
3685 | +- } |
3686 | +- |
3687 | +- // Slow path: |
3688 | +- proto := "HTTP/1.0" |
3689 | +- if proto11 { |
3690 | +- proto = "HTTP/1.1" |
3691 | +- } |
3692 | +- codestring := strconv.Itoa(code) |
3693 | +- text, ok := statusText[code] |
3694 | +- if !ok { |
3695 | +- text = "status code " + codestring |
3696 | +- } |
3697 | +- line = proto + " " + codestring + " " + text + "\r\n" |
3698 | +- if ok { |
3699 | +- statusMu.Lock() |
3700 | +- defer statusMu.Unlock() |
3701 | +- statusLines[key] = line |
3702 | +- } |
3703 | +- return line |
3704 | +-} |
3705 | +- |
3706 | +-// bodyAllowed returns true if a Write is allowed for this response type. |
3707 | +-// It's illegal to call this before the header has been flushed. |
3708 | +-func (w *response) bodyAllowed() bool { |
3709 | +- if !w.wroteHeader { |
3710 | +- panic("") |
3711 | +- } |
3712 | +- return bodyAllowedForStatus(w.status) |
3713 | +-} |
3714 | +- |
3715 | +-// The Life Of A Write is like this: |
3716 | +-// |
3717 | +-// Handler starts. No header has been sent. The handler can either |
3718 | +-// write a header, or just start writing. Writing before sending a header |
3719 | +-// sends an implicitly empty 200 OK header. |
3720 | +-// |
3721 | +-// If the handler didn't declare a Content-Length up front, we either |
3722 | +-// go into chunking mode or, if the handler finishes running before |
3723 | +-// the chunking buffer size, we compute a Content-Length and send that |
3724 | +-// in the header instead. |
3725 | +-// |
3726 | +-// Likewise, if the handler didn't set a Content-Type, we sniff that |
3727 | +-// from the initial chunk of output. |
3728 | +-// |
3729 | +-// The Writers are wired together like: |
3730 | +-// |
3731 | +-// 1. *response (the ResponseWriter) -> |
3732 | +-// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes |
3733 | +-// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type) |
3734 | +-// and which writes the chunk headers, if needed. |
3735 | +-// 4. conn.buf, a bufio.Writer of default (4kB) bytes |
3736 | +-// 5. the rwc, the net.Conn. |
3737 | +-// |
3738 | +-// TODO(bradfitz): short-circuit some of the buffering when the |
3739 | +-// initial header contains both a Content-Type and Content-Length. |
3740 | +-// Also short-circuit in (1) when the header's been sent and not in |
3741 | +-// chunking mode, writing directly to (4) instead, if (2) has no |
3742 | +-// buffered data. More generally, we could short-circuit from (1) to |
3743 | +-// (3) even in chunking mode if the write size from (1) is over some |
3744 | +-// threshold and nothing is in (2). The answer might be mostly making |
3745 | +-// bufferBeforeChunkingSize smaller and having bufio's fast-paths deal |
3746 | +-// with this instead. |
3747 | +-func (w *response) Write(data []byte) (n int, err error) { |
3748 | +- return w.write(len(data), data, "") |
3749 | +-} |
3750 | +- |
3751 | +-func (w *response) WriteString(data string) (n int, err error) { |
3752 | +- return w.write(len(data), nil, data) |
3753 | +-} |
3754 | +- |
3755 | +-// either dataB or dataS is non-zero. |
3756 | +-func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) { |
3757 | +- if w.conn.hijacked() { |
3758 | +- w.conn.server.logf("http: response.Write on hijacked connection") |
3759 | +- return 0, ErrHijacked |
3760 | +- } |
3761 | +- if !w.wroteHeader { |
3762 | +- w.WriteHeader(StatusOK) |
3763 | +- } |
3764 | +- if lenData == 0 { |
3765 | +- return 0, nil |
3766 | +- } |
3767 | +- if !w.bodyAllowed() { |
3768 | +- return 0, ErrBodyNotAllowed |
3769 | +- } |
3770 | +- |
3771 | +- w.written += int64(lenData) // ignoring errors, for errorKludge |
3772 | +- if w.contentLength != -1 && w.written > w.contentLength { |
3773 | +- return 0, ErrContentLength |
3774 | +- } |
3775 | +- if dataB != nil { |
3776 | +- return w.w.Write(dataB) |
3777 | +- } else { |
3778 | +- return w.w.WriteString(dataS) |
3779 | +- } |
3780 | +-} |
3781 | +- |
3782 | +-func (w *response) finishRequest() { |
3783 | +- w.handlerDone = true |
3784 | +- |
3785 | +- if !w.wroteHeader { |
3786 | +- w.WriteHeader(StatusOK) |
3787 | +- } |
3788 | +- |
3789 | +- w.w.Flush() |
3790 | +- putBufioWriter(w.w) |
3791 | +- w.cw.close() |
3792 | +- w.conn.buf.Flush() |
3793 | +- |
3794 | +- // Close the body (regardless of w.closeAfterReply) so we can |
3795 | +- // re-use its bufio.Reader later safely. |
3796 | +- w.req.Body.Close() |
3797 | +- |
3798 | +- if w.req.MultipartForm != nil { |
3799 | +- w.req.MultipartForm.RemoveAll() |
3800 | +- } |
3801 | +- |
3802 | +- if w.req.Method != "HEAD" && w.contentLength != -1 && w.bodyAllowed() && w.contentLength != w.written { |
3803 | +- // Did not write enough. Avoid getting out of sync. |
3804 | +- w.closeAfterReply = true |
3805 | +- } |
3806 | +-} |
3807 | +- |
3808 | +-func (w *response) Flush() { |
3809 | +- if !w.wroteHeader { |
3810 | +- w.WriteHeader(StatusOK) |
3811 | +- } |
3812 | +- w.w.Flush() |
3813 | +- w.cw.flush() |
3814 | +-} |
3815 | +- |
3816 | +-func (c *conn) finalFlush() { |
3817 | +- if c.buf != nil { |
3818 | +- c.buf.Flush() |
3819 | +- |
3820 | +- // Steal the bufio.Reader (~4KB worth of memory) and its associated |
3821 | +- // reader for a future connection. |
3822 | +- putBufioReader(c.buf.Reader) |
3823 | +- |
3824 | +- // Steal the bufio.Writer (~4KB worth of memory) and its associated |
3825 | +- // writer for a future connection. |
3826 | +- putBufioWriter(c.buf.Writer) |
3827 | +- |
3828 | +- c.buf = nil |
3829 | +- } |
3830 | +-} |
3831 | +- |
3832 | +-// Close the connection. |
3833 | +-func (c *conn) close() { |
3834 | +- c.finalFlush() |
3835 | +- if c.rwc != nil { |
3836 | +- c.rwc.Close() |
3837 | +- c.rwc = nil |
3838 | +- } |
3839 | +-} |
3840 | +- |
3841 | +-// rstAvoidanceDelay is the amount of time we sleep after closing the |
3842 | +-// write side of a TCP connection before closing the entire socket. |
3843 | +-// By sleeping, we increase the chances that the client sees our FIN |
3844 | +-// and processes its final data before they process the subsequent RST |
3845 | +-// from closing a connection with known unread data. |
3846 | +-// This RST seems to occur mostly on BSD systems. (And Windows?) |
3847 | +-// This timeout is somewhat arbitrary (~latency around the planet). |
3848 | +-const rstAvoidanceDelay = 500 * time.Millisecond |
3849 | +- |
3850 | +-// closeWrite flushes any outstanding data and sends a FIN packet (if |
3851 | +-// client is connected via TCP), signalling that we're done. We then |
3852 | +-// pause for a bit, hoping the client processes it before `any |
3853 | +-// subsequent RST. |
3854 | +-// |
3855 | +-// See http://golang.org/issue/3595 |
3856 | +-func (c *conn) closeWriteAndWait() { |
3857 | +- c.finalFlush() |
3858 | +- if tcp, ok := c.rwc.(*net.TCPConn); ok { |
3859 | +- tcp.CloseWrite() |
3860 | +- } |
3861 | +- time.Sleep(rstAvoidanceDelay) |
3862 | +-} |
3863 | +- |
3864 | +-// validNPN reports whether the proto is not a blacklisted Next |
3865 | +-// Protocol Negotiation protocol. Empty and built-in protocol types |
3866 | +-// are blacklisted and can't be overridden with alternate |
3867 | +-// implementations. |
3868 | +-func validNPN(proto string) bool { |
3869 | +- switch proto { |
3870 | +- case "", "http/1.1", "http/1.0": |
3871 | +- return false |
3872 | +- } |
3873 | +- return true |
3874 | +-} |
3875 | +- |
3876 | +-func (c *conn) setState(nc net.Conn, state ConnState) { |
3877 | +- if hook := c.server.ConnState; hook != nil { |
3878 | +- hook(nc, state) |
3879 | +- } |
3880 | +-} |
3881 | +- |
3882 | +-// Serve a new connection. |
3883 | +-func (c *conn) serve() { |
3884 | +- origConn := c.rwc // copy it before it's set nil on Close or Hijack |
3885 | +- defer func() { |
3886 | +- if err := recover(); err != nil { |
3887 | +- const size = 64 << 10 |
3888 | +- buf := make([]byte, size) |
3889 | +- buf = buf[:runtime.Stack(buf, false)] |
3890 | +- c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) |
3891 | +- } |
3892 | +- if !c.hijacked() { |
3893 | +- c.close() |
3894 | +- c.setState(origConn, StateClosed) |
3895 | +- } |
3896 | +- }() |
3897 | +- |
3898 | +- if tlsConn, ok := c.rwc.(*tls.Conn); ok { |
3899 | +- if d := c.server.ReadTimeout; d != 0 { |
3900 | +- c.rwc.SetReadDeadline(time.Now().Add(d)) |
3901 | +- } |
3902 | +- if d := c.server.WriteTimeout; d != 0 { |
3903 | +- c.rwc.SetWriteDeadline(time.Now().Add(d)) |
3904 | +- } |
3905 | +- if err := tlsConn.Handshake(); err != nil { |
3906 | +- c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) |
3907 | +- return |
3908 | +- } |
3909 | +- c.tlsState = new(tls.ConnectionState) |
3910 | +- *c.tlsState = tlsConn.ConnectionState() |
3911 | +- if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) { |
3912 | +- if fn := c.server.TLSNextProto[proto]; fn != nil { |
3913 | +- h := initNPNRequest{tlsConn, serverHandler{c.server}} |
3914 | +- fn(c.server, tlsConn, h) |
3915 | +- } |
3916 | +- return |
3917 | +- } |
3918 | +- } |
3919 | +- |
3920 | +- for { |
3921 | +- w, err := c.readRequest() |
3922 | +- if c.lr.N != c.server.initialLimitedReaderSize() { |
3923 | +- // If we read any bytes off the wire, we're active. |
3924 | +- c.setState(c.rwc, StateActive) |
3925 | +- } |
3926 | +- if err != nil { |
3927 | +- if err == errTooLarge { |
3928 | +- // Their HTTP client may or may not be |
3929 | +- // able to read this if we're |
3930 | +- // responding to them and hanging up |
3931 | +- // while they're still writing their |
3932 | +- // request. Undefined behavior. |
3933 | +- io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n") |
3934 | +- c.closeWriteAndWait() |
3935 | +- break |
3936 | +- } else if err == io.EOF { |
3937 | +- break // Don't reply |
3938 | +- } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() { |
3939 | +- break // Don't reply |
3940 | +- } |
3941 | +- io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n") |
3942 | +- break |
3943 | +- } |
3944 | +- |
3945 | +- // Expect 100 Continue support |
3946 | +- req := w.req |
3947 | +- if req.expectsContinue() { |
3948 | +- if req.ProtoAtLeast(1, 1) { |
3949 | +- // Wrap the Body reader with one that replies on the connection |
3950 | +- req.Body = &expectContinueReader{readCloser: req.Body, resp: w} |
3951 | +- } |
3952 | +- if req.ContentLength == 0 { |
3953 | +- w.Header().Set("Connection", "close") |
3954 | +- w.WriteHeader(StatusBadRequest) |
3955 | +- w.finishRequest() |
3956 | +- break |
3957 | +- } |
3958 | +- req.Header.Del("Expect") |
3959 | +- } else if req.Header.get("Expect") != "" { |
3960 | +- w.sendExpectationFailed() |
3961 | +- break |
3962 | +- } |
3963 | +- |
3964 | +- // HTTP cannot have multiple simultaneous active requests.[*] |
3965 | +- // Until the server replies to this request, it can't read another, |
3966 | +- // so we might as well run the handler in this goroutine. |
3967 | +- // [*] Not strictly true: HTTP pipelining. We could let them all process |
3968 | +- // in parallel even if their responses need to be serialized. |
3969 | +- serverHandler{c.server}.ServeHTTP(w, w.req) |
3970 | +- if c.hijacked() { |
3971 | +- return |
3972 | +- } |
3973 | +- w.finishRequest() |
3974 | +- if w.closeAfterReply { |
3975 | +- if w.requestBodyLimitHit { |
3976 | +- c.closeWriteAndWait() |
3977 | +- } |
3978 | +- break |
3979 | +- } |
3980 | +- c.setState(c.rwc, StateIdle) |
3981 | +- } |
3982 | +-} |
3983 | +- |
3984 | +-func (w *response) sendExpectationFailed() { |
3985 | +- // TODO(bradfitz): let ServeHTTP handlers handle |
3986 | +- // requests with non-standard expectation[s]? Seems |
3987 | +- // theoretical at best, and doesn't fit into the |
3988 | +- // current ServeHTTP model anyway. We'd need to |
3989 | +- // make the ResponseWriter an optional |
3990 | +- // "ExpectReplier" interface or something. |
3991 | +- // |
3992 | +- // For now we'll just obey RFC 2616 14.20 which says |
3993 | +- // "If a server receives a request containing an |
3994 | +- // Expect field that includes an expectation- |
3995 | +- // extension that it does not support, it MUST |
3996 | +- // respond with a 417 (Expectation Failed) status." |
3997 | +- w.Header().Set("Connection", "close") |
3998 | +- w.WriteHeader(StatusExpectationFailed) |
3999 | +- w.finishRequest() |
4000 | +-} |
4001 | +- |
4002 | +-// Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter |
4003 | +-// and a Hijacker. |
4004 | +-func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { |
4005 | +- if w.wroteHeader { |
4006 | +- w.cw.flush() |
4007 | +- } |
4008 | +- // Release the bufioWriter that writes to the chunk writer, it is not |
4009 | +- // used after a connection has been hijacked. |
4010 | +- rwc, buf, err = w.conn.hijack() |
4011 | +- if err == nil { |
4012 | +- putBufioWriter(w.w) |
4013 | +- w.w = nil |
4014 | +- } |
4015 | +- return rwc, buf, err |
4016 | +-} |
4017 | +- |
4018 | +-func (w *response) CloseNotify() <-chan bool { |
4019 | +- return w.conn.closeNotify() |
4020 | +-} |
4021 | +- |
4022 | +-// The HandlerFunc type is an adapter to allow the use of |
4023 | +-// ordinary functions as HTTP handlers. If f is a function |
4024 | +-// with the appropriate signature, HandlerFunc(f) is a |
4025 | +-// Handler object that calls f. |
4026 | +-type HandlerFunc func(ResponseWriter, *Request) |
4027 | +- |
4028 | +-// ServeHTTP calls f(w, r). |
4029 | +-func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { |
4030 | +- f(w, r) |
4031 | +-} |
4032 | +- |
4033 | +-// Helper handlers |
4034 | +- |
4035 | +-// Error replies to the request with the specified error message and HTTP code. |
4036 | +-// The error message should be plain text. |
4037 | +-func Error(w ResponseWriter, error string, code int) { |
4038 | +- w.Header().Set("Content-Type", "text/plain; charset=utf-8") |
4039 | +- w.WriteHeader(code) |
4040 | +- fmt.Fprintln(w, error) |
4041 | +-} |
4042 | +- |
4043 | +-// NotFound replies to the request with an HTTP 404 not found error. |
4044 | +-func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) } |
4045 | +- |
4046 | +-// NotFoundHandler returns a simple request handler |
4047 | +-// that replies to each request with a ``404 page not found'' reply. |
4048 | +-func NotFoundHandler() Handler { return HandlerFunc(NotFound) } |
4049 | +- |
4050 | +-// StripPrefix returns a handler that serves HTTP requests |
4051 | +-// by removing the given prefix from the request URL's Path |
4052 | +-// and invoking the handler h. StripPrefix handles a |
4053 | +-// request for a path that doesn't begin with prefix by |
4054 | +-// replying with an HTTP 404 not found error. |
4055 | +-func StripPrefix(prefix string, h Handler) Handler { |
4056 | +- if prefix == "" { |
4057 | +- return h |
4058 | +- } |
4059 | +- return HandlerFunc(func(w ResponseWriter, r *Request) { |
4060 | +- if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) { |
4061 | +- r.URL.Path = p |
4062 | +- h.ServeHTTP(w, r) |
4063 | +- } else { |
4064 | +- NotFound(w, r) |
4065 | +- } |
4066 | +- }) |
4067 | +-} |
4068 | +- |
4069 | +-// Redirect replies to the request with a redirect to url, |
4070 | +-// which may be a path relative to the request path. |
4071 | +-func Redirect(w ResponseWriter, r *Request, urlStr string, code int) { |
4072 | +- if u, err := url.Parse(urlStr); err == nil { |
4073 | +- // If url was relative, make absolute by |
4074 | +- // combining with request path. |
4075 | +- // The browser would probably do this for us, |
4076 | +- // but doing it ourselves is more reliable. |
4077 | +- |
4078 | +- // NOTE(rsc): RFC 2616 says that the Location |
4079 | +- // line must be an absolute URI, like |
4080 | +- // "http://www.google.com/redirect/", |
4081 | +- // not a path like "/redirect/". |
4082 | +- // Unfortunately, we don't know what to |
4083 | +- // put in the host name section to get the |
4084 | +- // client to connect to us again, so we can't |
4085 | +- // know the right absolute URI to send back. |
4086 | +- // Because of this problem, no one pays attention |
4087 | +- // to the RFC; they all send back just a new path. |
4088 | +- // So do we. |
4089 | +- oldpath := r.URL.Path |
4090 | +- if oldpath == "" { // should not happen, but avoid a crash if it does |
4091 | +- oldpath = "/" |
4092 | +- } |
4093 | +- if u.Scheme == "" { |
4094 | +- // no leading http://server |
4095 | +- if urlStr == "" || urlStr[0] != '/' { |
4096 | +- // make relative path absolute |
4097 | +- olddir, _ := path.Split(oldpath) |
4098 | +- urlStr = olddir + urlStr |
4099 | +- } |
4100 | +- |
4101 | +- var query string |
4102 | +- if i := strings.Index(urlStr, "?"); i != -1 { |
4103 | +- urlStr, query = urlStr[:i], urlStr[i:] |
4104 | +- } |
4105 | +- |
4106 | +- // clean up but preserve trailing slash |
4107 | +- trailing := strings.HasSuffix(urlStr, "/") |
4108 | +- urlStr = path.Clean(urlStr) |
4109 | +- if trailing && !strings.HasSuffix(urlStr, "/") { |
4110 | +- urlStr += "/" |
4111 | +- } |
4112 | +- urlStr += query |
4113 | +- } |
4114 | +- } |
4115 | +- |
4116 | +- w.Header().Set("Location", urlStr) |
4117 | +- w.WriteHeader(code) |
4118 | +- |
4119 | +- // RFC2616 recommends that a short note "SHOULD" be included in the |
4120 | +- // response because older user agents may not understand 301/307. |
4121 | +- // Shouldn't send the response for POST or HEAD; that leaves GET. |
4122 | +- if r.Method == "GET" { |
4123 | +- note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[code] + "</a>.\n" |
4124 | +- fmt.Fprintln(w, note) |
4125 | +- } |
4126 | +-} |
4127 | +- |
4128 | +-var htmlReplacer = strings.NewReplacer( |
4129 | +- "&", "&", |
4130 | +- "<", "<", |
4131 | +- ">", ">", |
4132 | +- // """ is shorter than """. |
4133 | +- `"`, """, |
4134 | +- // "'" is shorter than "'" and apos was not in HTML until HTML5. |
4135 | +- "'", "'", |
4136 | +-) |
4137 | +- |
4138 | +-func htmlEscape(s string) string { |
4139 | +- return htmlReplacer.Replace(s) |
4140 | +-} |
4141 | +- |
4142 | +-// Redirect to a fixed URL |
4143 | +-type redirectHandler struct { |
4144 | +- url string |
4145 | +- code int |
4146 | +-} |
4147 | +- |
4148 | +-func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { |
4149 | +- Redirect(w, r, rh.url, rh.code) |
4150 | +-} |
4151 | +- |
4152 | +-// RedirectHandler returns a request handler that redirects |
4153 | +-// each request it receives to the given url using the given |
4154 | +-// status code. |
4155 | +-func RedirectHandler(url string, code int) Handler { |
4156 | +- return &redirectHandler{url, code} |
4157 | +-} |
4158 | +- |
4159 | +-// ServeMux is an HTTP request multiplexer. |
4160 | +-// It matches the URL of each incoming request against a list of registered |
4161 | +-// patterns and calls the handler for the pattern that |
4162 | +-// most closely matches the URL. |
4163 | +-// |
4164 | +-// Patterns name fixed, rooted paths, like "/favicon.ico", |
4165 | +-// or rooted subtrees, like "/images/" (note the trailing slash). |
4166 | +-// Longer patterns take precedence over shorter ones, so that |
4167 | +-// if there are handlers registered for both "/images/" |
4168 | +-// and "/images/thumbnails/", the latter handler will be |
4169 | +-// called for paths beginning "/images/thumbnails/" and the |
4170 | +-// former will receive requests for any other paths in the |
4171 | +-// "/images/" subtree. |
4172 | +-// |
4173 | +-// Note that since a pattern ending in a slash names a rooted subtree, |
4174 | +-// the pattern "/" matches all paths not matched by other registered |
4175 | +-// patterns, not just the URL with Path == "/". |
4176 | +-// |
4177 | +-// Patterns may optionally begin with a host name, restricting matches to |
4178 | +-// URLs on that host only. Host-specific patterns take precedence over |
4179 | +-// general patterns, so that a handler might register for the two patterns |
4180 | +-// "/codesearch" and "codesearch.google.com/" without also taking over |
4181 | +-// requests for "http://www.google.com/". |
4182 | +-// |
4183 | +-// ServeMux also takes care of sanitizing the URL request path, |
4184 | +-// redirecting any request containing . or .. elements to an |
4185 | +-// equivalent .- and ..-free URL. |
4186 | +-type ServeMux struct { |
4187 | +- mu sync.RWMutex |
4188 | +- m map[string]muxEntry |
4189 | +- hosts bool // whether any patterns contain hostnames |
4190 | +-} |
4191 | +- |
4192 | +-type muxEntry struct { |
4193 | +- explicit bool |
4194 | +- h Handler |
4195 | +- pattern string |
4196 | +-} |
4197 | +- |
4198 | +-// NewServeMux allocates and returns a new ServeMux. |
4199 | +-func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} } |
4200 | +- |
4201 | +-// DefaultServeMux is the default ServeMux used by Serve. |
4202 | +-var DefaultServeMux = NewServeMux() |
4203 | +- |
4204 | +-// Does path match pattern? |
4205 | +-func pathMatch(pattern, path string) bool { |
4206 | +- if len(pattern) == 0 { |
4207 | +- // should not happen |
4208 | +- return false |
4209 | +- } |
4210 | +- n := len(pattern) |
4211 | +- if pattern[n-1] != '/' { |
4212 | +- return pattern == path |
4213 | +- } |
4214 | +- return len(path) >= n && path[0:n] == pattern |
4215 | +-} |
4216 | +- |
4217 | +-// Return the canonical path for p, eliminating . and .. elements. |
4218 | +-func cleanPath(p string) string { |
4219 | +- if p == "" { |
4220 | +- return "/" |
4221 | +- } |
4222 | +- if p[0] != '/' { |
4223 | +- p = "/" + p |
4224 | +- } |
4225 | +- np := path.Clean(p) |
4226 | +- // path.Clean removes trailing slash except for root; |
4227 | +- // put the trailing slash back if necessary. |
4228 | +- if p[len(p)-1] == '/' && np != "/" { |
4229 | +- np += "/" |
4230 | +- } |
4231 | +- return np |
4232 | +-} |
4233 | +- |
4234 | +-// Find a handler on a handler map given a path string |
4235 | +-// Most-specific (longest) pattern wins |
4236 | +-func (mux *ServeMux) match(path string) (h Handler, pattern string) { |
4237 | +- var n = 0 |
4238 | +- for k, v := range mux.m { |
4239 | +- if !pathMatch(k, path) { |
4240 | +- continue |
4241 | +- } |
4242 | +- if h == nil || len(k) > n { |
4243 | +- n = len(k) |
4244 | +- h = v.h |
4245 | +- pattern = v.pattern |
4246 | +- } |
4247 | +- } |
4248 | +- return |
4249 | +-} |
4250 | +- |
4251 | +-// Handler returns the handler to use for the given request, |
4252 | +-// consulting r.Method, r.Host, and r.URL.Path. It always returns |
4253 | +-// a non-nil handler. If the path is not in its canonical form, the |
4254 | +-// handler will be an internally-generated handler that redirects |
4255 | +-// to the canonical path. |
4256 | +-// |
4257 | +-// Handler also returns the registered pattern that matches the |
4258 | +-// request or, in the case of internally-generated redirects, |
4259 | +-// the pattern that will match after following the redirect. |
4260 | +-// |
4261 | +-// If there is no registered handler that applies to the request, |
4262 | +-// Handler returns a ``page not found'' handler and an empty pattern. |
4263 | +-func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { |
4264 | +- if r.Method != "CONNECT" { |
4265 | +- if p := cleanPath(r.URL.Path); p != r.URL.Path { |
4266 | +- _, pattern = mux.handler(r.Host, p) |
4267 | +- url := *r.URL |
4268 | +- url.Path = p |
4269 | +- return RedirectHandler(url.String(), StatusMovedPermanently), pattern |
4270 | +- } |
4271 | +- } |
4272 | +- |
4273 | +- return mux.handler(r.Host, r.URL.Path) |
4274 | +-} |
4275 | +- |
4276 | +-// handler is the main implementation of Handler. |
4277 | +-// The path is known to be in canonical form, except for CONNECT methods. |
4278 | +-func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { |
4279 | +- mux.mu.RLock() |
4280 | +- defer mux.mu.RUnlock() |
4281 | +- |
4282 | +- // Host-specific pattern takes precedence over generic ones |
4283 | +- if mux.hosts { |
4284 | +- h, pattern = mux.match(host + path) |
4285 | +- } |
4286 | +- if h == nil { |
4287 | +- h, pattern = mux.match(path) |
4288 | +- } |
4289 | +- if h == nil { |
4290 | +- h, pattern = NotFoundHandler(), "" |
4291 | +- } |
4292 | +- return |
4293 | +-} |
4294 | +- |
4295 | +-// ServeHTTP dispatches the request to the handler whose |
4296 | +-// pattern most closely matches the request URL. |
4297 | +-func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { |
4298 | +- if r.RequestURI == "*" { |
4299 | +- if r.ProtoAtLeast(1, 1) { |
4300 | +- w.Header().Set("Connection", "close") |
4301 | +- } |
4302 | +- w.WriteHeader(StatusBadRequest) |
4303 | +- return |
4304 | +- } |
4305 | +- h, _ := mux.Handler(r) |
4306 | +- h.ServeHTTP(w, r) |
4307 | +-} |
4308 | +- |
4309 | +-// Handle registers the handler for the given pattern. |
4310 | +-// If a handler already exists for pattern, Handle panics. |
4311 | +-func (mux *ServeMux) Handle(pattern string, handler Handler) { |
4312 | +- mux.mu.Lock() |
4313 | +- defer mux.mu.Unlock() |
4314 | +- |
4315 | +- if pattern == "" { |
4316 | +- panic("http: invalid pattern " + pattern) |
4317 | +- } |
4318 | +- if handler == nil { |
4319 | +- panic("http: nil handler") |
4320 | +- } |
4321 | +- if mux.m[pattern].explicit { |
4322 | +- panic("http: multiple registrations for " + pattern) |
4323 | +- } |
4324 | +- |
4325 | +- mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern} |
4326 | +- |
4327 | +- if pattern[0] != '/' { |
4328 | +- mux.hosts = true |
4329 | +- } |
4330 | +- |
4331 | +- // Helpful behavior: |
4332 | +- // If pattern is /tree/, insert an implicit permanent redirect for /tree. |
4333 | +- // It can be overridden by an explicit registration. |
4334 | +- n := len(pattern) |
4335 | +- if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { |
4336 | +- // If pattern contains a host name, strip it and use remaining |
4337 | +- // path for redirect. |
4338 | +- path := pattern |
4339 | +- if pattern[0] != '/' { |
4340 | +- // In pattern, at least the last character is a '/', so |
4341 | +- // strings.Index can't be -1. |
4342 | +- path = pattern[strings.Index(pattern, "/"):] |
4343 | +- } |
4344 | +- mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern} |
4345 | +- } |
4346 | +-} |
4347 | +- |
4348 | +-// HandleFunc registers the handler function for the given pattern. |
4349 | +-func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { |
4350 | +- mux.Handle(pattern, HandlerFunc(handler)) |
4351 | +-} |
4352 | +- |
4353 | +-// Handle registers the handler for the given pattern |
4354 | +-// in the DefaultServeMux. |
4355 | +-// The documentation for ServeMux explains how patterns are matched. |
4356 | +-func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } |
4357 | +- |
4358 | +-// HandleFunc registers the handler function for the given pattern |
4359 | +-// in the DefaultServeMux. |
4360 | +-// The documentation for ServeMux explains how patterns are matched. |
4361 | +-func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { |
4362 | +- DefaultServeMux.HandleFunc(pattern, handler) |
4363 | +-} |
4364 | +- |
4365 | +-// Serve accepts incoming HTTP connections on the listener l, |
4366 | +-// creating a new service goroutine for each. The service goroutines |
4367 | +-// read requests and then call handler to reply to them. |
4368 | +-// Handler is typically nil, in which case the DefaultServeMux is used. |
4369 | +-func Serve(l net.Listener, handler Handler) error { |
4370 | +- srv := &Server{Handler: handler} |
4371 | +- return srv.Serve(l) |
4372 | +-} |
4373 | +- |
4374 | +-// A Server defines parameters for running an HTTP server. |
4375 | +-// The zero value for Server is a valid configuration. |
4376 | +-type Server struct { |
4377 | +- Addr string // TCP address to listen on, ":http" if empty |
4378 | +- Handler Handler // handler to invoke, http.DefaultServeMux if nil |
4379 | +- ReadTimeout time.Duration // maximum duration before timing out read of the request |
4380 | +- WriteTimeout time.Duration // maximum duration before timing out write of the response |
4381 | +- MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0 |
4382 | +- TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS |
4383 | +- |
4384 | +- // TLSNextProto optionally specifies a function to take over |
4385 | +- // ownership of the provided TLS connection when an NPN |
4386 | +- // protocol upgrade has occurred. The map key is the protocol |
4387 | +- // name negotiated. The Handler argument should be used to |
4388 | +- // handle HTTP requests and will initialize the Request's TLS |
4389 | +- // and RemoteAddr if not already set. The connection is |
4390 | +- // automatically closed when the function returns. |
4391 | +- TLSNextProto map[string]func(*Server, *tls.Conn, Handler) |
4392 | +- |
4393 | +- // ConnState specifies an optional callback function that is |
4394 | +- // called when a client connection changes state. See the |
4395 | +- // ConnState type and associated constants for details. |
4396 | +- ConnState func(net.Conn, ConnState) |
4397 | +- |
4398 | +- // ErrorLog specifies an optional logger for errors accepting |
4399 | +- // connections and unexpected behavior from handlers. |
4400 | +- // If nil, logging goes to os.Stderr via the log package's |
4401 | +- // standard logger. |
4402 | +- ErrorLog *log.Logger |
4403 | +- |
4404 | +- disableKeepAlives int32 // accessed atomically. |
4405 | +-} |
4406 | +- |
4407 | +-// A ConnState represents the state of a client connection to a server. |
4408 | +-// It's used by the optional Server.ConnState hook. |
4409 | +-type ConnState int |
4410 | +- |
4411 | +-const ( |
4412 | +- // StateNew represents a new connection that is expected to |
4413 | +- // send a request immediately. Connections begin at this |
4414 | +- // state and then transition to either StateActive or |
4415 | +- // StateClosed. |
4416 | +- StateNew ConnState = iota |
4417 | +- |
4418 | +- // StateActive represents a connection that has read 1 or more |
4419 | +- // bytes of a request. The Server.ConnState hook for |
4420 | +- // StateActive fires before the request has entered a handler |
4421 | +- // and doesn't fire again until the request has been |
4422 | +- // handled. After the request is handled, the state |
4423 | +- // transitions to StateClosed, StateHijacked, or StateIdle. |
4424 | +- StateActive |
4425 | +- |
4426 | +- // StateIdle represents a connection that has finished |
4427 | +- // handling a request and is in the keep-alive state, waiting |
4428 | +- // for a new request. Connections transition from StateIdle |
4429 | +- // to either StateActive or StateClosed. |
4430 | +- StateIdle |
4431 | +- |
4432 | +- // StateHijacked represents a hijacked connection. |
4433 | +- // This is a terminal state. It does not transition to StateClosed. |
4434 | +- StateHijacked |
4435 | +- |
4436 | +- // StateClosed represents a closed connection. |
4437 | +- // This is a terminal state. Hijacked connections do not |
4438 | +- // transition to StateClosed. |
4439 | +- StateClosed |
4440 | +-) |
4441 | +- |
4442 | +-var stateName = map[ConnState]string{ |
4443 | +- StateNew: "new", |
4444 | +- StateActive: "active", |
4445 | +- StateIdle: "idle", |
4446 | +- StateHijacked: "hijacked", |
4447 | +- StateClosed: "closed", |
4448 | +-} |
4449 | +- |
4450 | +-func (c ConnState) String() string { |
4451 | +- return stateName[c] |
4452 | +-} |
4453 | +- |
4454 | +-// serverHandler delegates to either the server's Handler or |
4455 | +-// DefaultServeMux and also handles "OPTIONS *" requests. |
4456 | +-type serverHandler struct { |
4457 | +- srv *Server |
4458 | +-} |
4459 | +- |
4460 | +-func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { |
4461 | +- handler := sh.srv.Handler |
4462 | +- if handler == nil { |
4463 | +- handler = DefaultServeMux |
4464 | +- } |
4465 | +- if req.RequestURI == "*" && req.Method == "OPTIONS" { |
4466 | +- handler = globalOptionsHandler{} |
4467 | +- } |
4468 | +- handler.ServeHTTP(rw, req) |
4469 | +-} |
4470 | +- |
4471 | +-// ListenAndServe listens on the TCP network address srv.Addr and then |
4472 | +-// calls Serve to handle requests on incoming connections. If |
4473 | +-// srv.Addr is blank, ":http" is used. |
4474 | +-func (srv *Server) ListenAndServe() error { |
4475 | +- addr := srv.Addr |
4476 | +- if addr == "" { |
4477 | +- addr = ":http" |
4478 | +- } |
4479 | +- ln, err := net.Listen("tcp", addr) |
4480 | +- if err != nil { |
4481 | +- return err |
4482 | +- } |
4483 | +- return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) |
4484 | +-} |
4485 | +- |
4486 | +-// Serve accepts incoming connections on the Listener l, creating a |
4487 | +-// new service goroutine for each. The service goroutines read requests and |
4488 | +-// then call srv.Handler to reply to them. |
4489 | +-func (srv *Server) Serve(l net.Listener) error { |
4490 | +- defer l.Close() |
4491 | +- var tempDelay time.Duration // how long to sleep on accept failure |
4492 | +- for { |
4493 | +- rw, e := l.Accept() |
4494 | +- if e != nil { |
4495 | +- if ne, ok := e.(net.Error); ok && ne.Temporary() { |
4496 | +- if tempDelay == 0 { |
4497 | +- tempDelay = 5 * time.Millisecond |
4498 | +- } else { |
4499 | +- tempDelay *= 2 |
4500 | +- } |
4501 | +- if max := 1 * time.Second; tempDelay > max { |
4502 | +- tempDelay = max |
4503 | +- } |
4504 | +- srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) |
4505 | +- time.Sleep(tempDelay) |
4506 | +- continue |
4507 | +- } |
4508 | +- return e |
4509 | +- } |
4510 | +- tempDelay = 0 |
4511 | +- c, err := srv.newConn(rw) |
4512 | +- if err != nil { |
4513 | +- continue |
4514 | +- } |
4515 | +- c.setState(c.rwc, StateNew) // before Serve can return |
4516 | +- go c.serve() |
4517 | +- } |
4518 | +-} |
4519 | +- |
4520 | +-func (s *Server) doKeepAlives() bool { |
4521 | +- return atomic.LoadInt32(&s.disableKeepAlives) == 0 |
4522 | +-} |
4523 | +- |
4524 | +-// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. |
4525 | +-// By default, keep-alives are always enabled. Only very |
4526 | +-// resource-constrained environments or servers in the process of |
4527 | +-// shutting down should disable them. |
4528 | +-func (s *Server) SetKeepAlivesEnabled(v bool) { |
4529 | +- if v { |
4530 | +- atomic.StoreInt32(&s.disableKeepAlives, 0) |
4531 | +- } else { |
4532 | +- atomic.StoreInt32(&s.disableKeepAlives, 1) |
4533 | +- } |
4534 | +-} |
4535 | +- |
4536 | +-func (s *Server) logf(format string, args ...interface{}) { |
4537 | +- if s.ErrorLog != nil { |
4538 | +- s.ErrorLog.Printf(format, args...) |
4539 | +- } else { |
4540 | +- log.Printf(format, args...) |
4541 | +- } |
4542 | +-} |
4543 | +- |
4544 | +-// ListenAndServe listens on the TCP network address addr |
4545 | +-// and then calls Serve with handler to handle requests |
4546 | +-// on incoming connections. Handler is typically nil, |
4547 | +-// in which case the DefaultServeMux is used. |
4548 | +-// |
4549 | +-// A trivial example server is: |
4550 | +-// |
4551 | +-// package main |
4552 | +-// |
4553 | +-// import ( |
4554 | +-// "io" |
4555 | +-// "launchpad.net/ubuntu-push/http13client" |
4556 | +-// "log" |
4557 | +-// ) |
4558 | +-// |
4559 | +-// // hello world, the web server |
4560 | +-// func HelloServer(w http.ResponseWriter, req *http.Request) { |
4561 | +-// io.WriteString(w, "hello, world!\n") |
4562 | +-// } |
4563 | +-// |
4564 | +-// func main() { |
4565 | +-// http.HandleFunc("/hello", HelloServer) |
4566 | +-// err := http.ListenAndServe(":12345", nil) |
4567 | +-// if err != nil { |
4568 | +-// log.Fatal("ListenAndServe: ", err) |
4569 | +-// } |
4570 | +-// } |
4571 | +-func ListenAndServe(addr string, handler Handler) error { |
4572 | +- server := &Server{Addr: addr, Handler: handler} |
4573 | +- return server.ListenAndServe() |
4574 | +-} |
4575 | +- |
4576 | +-// ListenAndServeTLS acts identically to ListenAndServe, except that it |
4577 | +-// expects HTTPS connections. Additionally, files containing a certificate and |
4578 | +-// matching private key for the server must be provided. If the certificate |
4579 | +-// is signed by a certificate authority, the certFile should be the concatenation |
4580 | +-// of the server's certificate followed by the CA's certificate. |
4581 | +-// |
4582 | +-// A trivial example server is: |
4583 | +-// |
4584 | +-// import ( |
4585 | +-// "log" |
4586 | +-// "launchpad.net/ubuntu-push/http13client" |
4587 | +-// ) |
4588 | +-// |
4589 | +-// func handler(w http.ResponseWriter, req *http.Request) { |
4590 | +-// w.Header().Set("Content-Type", "text/plain") |
4591 | +-// w.Write([]byte("This is an example server.\n")) |
4592 | +-// } |
4593 | +-// |
4594 | +-// func main() { |
4595 | +-// http.HandleFunc("/", handler) |
4596 | +-// log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/") |
4597 | +-// err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil) |
4598 | +-// if err != nil { |
4599 | +-// log.Fatal(err) |
4600 | +-// } |
4601 | +-// } |
4602 | +-// |
4603 | +-// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem. |
4604 | +-func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error { |
4605 | +- server := &Server{Addr: addr, Handler: handler} |
4606 | +- return server.ListenAndServeTLS(certFile, keyFile) |
4607 | +-} |
4608 | +- |
4609 | +-// ListenAndServeTLS listens on the TCP network address srv.Addr and |
4610 | +-// then calls Serve to handle requests on incoming TLS connections. |
4611 | +-// |
4612 | +-// Filenames containing a certificate and matching private key for |
4613 | +-// the server must be provided. If the certificate is signed by a |
4614 | +-// certificate authority, the certFile should be the concatenation |
4615 | +-// of the server's certificate followed by the CA's certificate. |
4616 | +-// |
4617 | +-// If srv.Addr is blank, ":https" is used. |
4618 | +-func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { |
4619 | +- addr := srv.Addr |
4620 | +- if addr == "" { |
4621 | +- addr = ":https" |
4622 | +- } |
4623 | +- config := &tls.Config{} |
4624 | +- if srv.TLSConfig != nil { |
4625 | +- *config = *srv.TLSConfig |
4626 | +- } |
4627 | +- if config.NextProtos == nil { |
4628 | +- config.NextProtos = []string{"http/1.1"} |
4629 | +- } |
4630 | +- |
4631 | +- var err error |
4632 | +- config.Certificates = make([]tls.Certificate, 1) |
4633 | +- config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) |
4634 | +- if err != nil { |
4635 | +- return err |
4636 | +- } |
4637 | +- |
4638 | +- ln, err := net.Listen("tcp", addr) |
4639 | +- if err != nil { |
4640 | +- return err |
4641 | +- } |
4642 | +- |
4643 | +- tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config) |
4644 | +- return srv.Serve(tlsListener) |
4645 | +-} |
4646 | +- |
4647 | +-// TimeoutHandler returns a Handler that runs h with the given time limit. |
4648 | +-// |
4649 | +-// The new Handler calls h.ServeHTTP to handle each request, but if a |
4650 | +-// call runs for longer than its time limit, the handler responds with |
4651 | +-// a 503 Service Unavailable error and the given message in its body. |
4652 | +-// (If msg is empty, a suitable default message will be sent.) |
4653 | +-// After such a timeout, writes by h to its ResponseWriter will return |
4654 | +-// ErrHandlerTimeout. |
4655 | +-func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler { |
4656 | +- f := func() <-chan time.Time { |
4657 | +- return time.After(dt) |
4658 | +- } |
4659 | +- return &timeoutHandler{h, f, msg} |
4660 | +-} |
4661 | +- |
4662 | +-// ErrHandlerTimeout is returned on ResponseWriter Write calls |
4663 | +-// in handlers which have timed out. |
4664 | +-var ErrHandlerTimeout = errors.New("http: Handler timeout") |
4665 | +- |
4666 | +-type timeoutHandler struct { |
4667 | +- handler Handler |
4668 | +- timeout func() <-chan time.Time // returns channel producing a timeout |
4669 | +- body string |
4670 | +-} |
4671 | +- |
4672 | +-func (h *timeoutHandler) errorBody() string { |
4673 | +- if h.body != "" { |
4674 | +- return h.body |
4675 | +- } |
4676 | +- return "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>" |
4677 | +-} |
4678 | +- |
4679 | +-func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { |
4680 | +- done := make(chan bool, 1) |
4681 | +- tw := &timeoutWriter{w: w} |
4682 | +- go func() { |
4683 | +- h.handler.ServeHTTP(tw, r) |
4684 | +- done <- true |
4685 | +- }() |
4686 | +- select { |
4687 | +- case <-done: |
4688 | +- return |
4689 | +- case <-h.timeout(): |
4690 | +- tw.mu.Lock() |
4691 | +- defer tw.mu.Unlock() |
4692 | +- if !tw.wroteHeader { |
4693 | +- tw.w.WriteHeader(StatusServiceUnavailable) |
4694 | +- tw.w.Write([]byte(h.errorBody())) |
4695 | +- } |
4696 | +- tw.timedOut = true |
4697 | +- } |
4698 | +-} |
4699 | +- |
4700 | +-type timeoutWriter struct { |
4701 | +- w ResponseWriter |
4702 | +- |
4703 | +- mu sync.Mutex |
4704 | +- timedOut bool |
4705 | +- wroteHeader bool |
4706 | +-} |
4707 | +- |
4708 | +-func (tw *timeoutWriter) Header() Header { |
4709 | +- return tw.w.Header() |
4710 | +-} |
4711 | +- |
4712 | +-func (tw *timeoutWriter) Write(p []byte) (int, error) { |
4713 | +- tw.mu.Lock() |
4714 | +- timedOut := tw.timedOut |
4715 | +- tw.mu.Unlock() |
4716 | +- if timedOut { |
4717 | +- return 0, ErrHandlerTimeout |
4718 | +- } |
4719 | +- return tw.w.Write(p) |
4720 | +-} |
4721 | +- |
4722 | +-func (tw *timeoutWriter) WriteHeader(code int) { |
4723 | +- tw.mu.Lock() |
4724 | +- if tw.timedOut || tw.wroteHeader { |
4725 | +- tw.mu.Unlock() |
4726 | +- return |
4727 | +- } |
4728 | +- tw.wroteHeader = true |
4729 | +- tw.mu.Unlock() |
4730 | +- tw.w.WriteHeader(code) |
4731 | +-} |
4732 | +- |
4733 | +-// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted |
4734 | +-// connections. It's used by ListenAndServe and ListenAndServeTLS so |
4735 | +-// dead TCP connections (e.g. closing laptop mid-download) eventually |
4736 | +-// go away. |
4737 | +-type tcpKeepAliveListener struct { |
4738 | +- *net.TCPListener |
4739 | +-} |
4740 | +- |
4741 | +-func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { |
4742 | +- tc, err := ln.AcceptTCP() |
4743 | +- if err != nil { |
4744 | +- return |
4745 | +- } |
4746 | +- tc.SetKeepAlive(true) |
4747 | +- tc.SetKeepAlivePeriod(3 * time.Minute) |
4748 | +- return tc, nil |
4749 | +-} |
4750 | +- |
4751 | +-// globalOptionsHandler responds to "OPTIONS *" requests. |
4752 | +-type globalOptionsHandler struct{} |
4753 | +- |
4754 | +-func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) { |
4755 | +- w.Header().Set("Content-Length", "0") |
4756 | +- if r.ContentLength != 0 { |
4757 | +- // Read up to 4KB of OPTIONS body (as mentioned in the |
4758 | +- // spec as being reserved for future use), but anything |
4759 | +- // over that is considered a waste of server resources |
4760 | +- // (or an attack) and we abort and close the connection, |
4761 | +- // courtesy of MaxBytesReader's EOF behavior. |
4762 | +- mb := MaxBytesReader(w, r.Body, 4<<10) |
4763 | +- io.Copy(ioutil.Discard, mb) |
4764 | +- } |
4765 | +-} |
4766 | ++) |
4767 | + |
4768 | + // eofReader is a non-nil io.ReadCloser that always returns EOF. |
4769 | + // It embeds a *strings.Reader so it still has a WriteTo method |
4770 | +@@ -1992,28 +25,6 @@ |
4771 | + ioutil.NopCloser(nil), |
4772 | + } |
4773 | + |
4774 | +-// initNPNRequest is an HTTP handler that initializes certain |
4775 | +-// uninitialized fields in its *Request. Such partially-initialized |
4776 | +-// Requests come from NPN protocol handlers. |
4777 | +-type initNPNRequest struct { |
4778 | +- c *tls.Conn |
4779 | +- h serverHandler |
4780 | +-} |
4781 | +- |
4782 | +-func (h initNPNRequest) ServeHTTP(rw ResponseWriter, req *Request) { |
4783 | +- if req.TLS == nil { |
4784 | +- req.TLS = &tls.ConnectionState{} |
4785 | +- *req.TLS = h.c.ConnectionState() |
4786 | +- } |
4787 | +- if req.Body == nil { |
4788 | +- req.Body = eofReader |
4789 | +- } |
4790 | +- if req.RemoteAddr == "" { |
4791 | +- req.RemoteAddr = h.c.RemoteAddr().String() |
4792 | +- } |
4793 | +- h.h.ServeHTTP(rw, req) |
4794 | +-} |
4795 | +- |
4796 | + // loggingConn is used for debugging. |
4797 | + type loggingConn struct { |
4798 | + name string |
4799 | + |
4800 | |
4801 | === added file 'http13client/_patches/fix_code.patch' |
4802 | --- http13client/_patches/fix_code.patch 1970-01-01 00:00:00 +0000 |
4803 | +++ http13client/_patches/fix_code.patch 2014-03-20 12:26:55 +0000 |
4804 | @@ -0,0 +1,739 @@ |
4805 | +=== modified file 'http13client/client.go' |
4806 | +--- http13client/client.go 2014-03-19 20:20:19 +0000 |
4807 | ++++ http13client/client.go 2014-03-19 22:27:37 +0000 |
4808 | +@@ -17,6 +17,7 @@ |
4809 | + "io/ioutil" |
4810 | + "log" |
4811 | + "net/url" |
4812 | ++ "net/http" |
4813 | + "strings" |
4814 | + "sync" |
4815 | + "time" |
4816 | +@@ -54,7 +55,7 @@ |
4817 | + // Jar specifies the cookie jar. |
4818 | + // If Jar is nil, cookies are not sent in requests and ignored |
4819 | + // in responses. |
4820 | +- Jar CookieJar |
4821 | ++ Jar http.CookieJar |
4822 | + |
4823 | + // Timeout specifies a time limit for requests made by this |
4824 | + // Client. The timeout includes connection time, any |
4825 | +@@ -177,7 +178,7 @@ |
4826 | + // Headers, leaving it uninitialized. We guarantee to the |
4827 | + // Transport that this has been initialized, though. |
4828 | + if req.Header == nil { |
4829 | +- req.Header = make(Header) |
4830 | ++ req.Header = make(http.Header) |
4831 | + } |
4832 | + |
4833 | + if u := req.URL.User; u != nil { |
4834 | +@@ -308,7 +309,7 @@ |
4835 | + if ireq.Method == "POST" || ireq.Method == "PUT" { |
4836 | + nreq.Method = "GET" |
4837 | + } |
4838 | +- nreq.Header = make(Header) |
4839 | ++ nreq.Header = make(http.Header) |
4840 | + nreq.URL, err = base.Parse(urlStr) |
4841 | + if err != nil { |
4842 | + break |
4843 | + |
4844 | +=== modified file 'http13client/cookie.go' |
4845 | +--- http13client/cookie.go 2014-03-19 20:20:19 +0000 |
4846 | ++++ http13client/cookie.go 2014-03-19 22:27:37 +0000 |
4847 | +@@ -5,10 +5,9 @@ |
4848 | + package http |
4849 | + |
4850 | + import ( |
4851 | +- "bytes" |
4852 | +- "fmt" |
4853 | + "log" |
4854 | + "net" |
4855 | ++ "net/http" |
4856 | + "strconv" |
4857 | + "strings" |
4858 | + "time" |
4859 | +@@ -18,30 +17,10 @@ |
4860 | + // |
4861 | + // http://tools.ietf.org/html/rfc6265 |
4862 | + |
4863 | +-// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an |
4864 | +-// HTTP response or the Cookie header of an HTTP request. |
4865 | +-type Cookie struct { |
4866 | +- Name string |
4867 | +- Value string |
4868 | +- Path string |
4869 | +- Domain string |
4870 | +- Expires time.Time |
4871 | +- RawExpires string |
4872 | +- |
4873 | +- // MaxAge=0 means no 'Max-Age' attribute specified. |
4874 | +- // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' |
4875 | +- // MaxAge>0 means Max-Age attribute present and given in seconds |
4876 | +- MaxAge int |
4877 | +- Secure bool |
4878 | +- HttpOnly bool |
4879 | +- Raw string |
4880 | +- Unparsed []string // Raw text of unparsed attribute-value pairs |
4881 | +-} |
4882 | +- |
4883 | + // readSetCookies parses all "Set-Cookie" values from |
4884 | + // the header h and returns the successfully parsed Cookies. |
4885 | +-func readSetCookies(h Header) []*Cookie { |
4886 | +- cookies := []*Cookie{} |
4887 | ++func readSetCookies(h http.Header) []*http.Cookie { |
4888 | ++ cookies := []*http.Cookie{} |
4889 | + for _, line := range h["Set-Cookie"] { |
4890 | + parts := strings.Split(strings.TrimSpace(line), ";") |
4891 | + if len(parts) == 1 && parts[0] == "" { |
4892 | +@@ -60,7 +39,7 @@ |
4893 | + if !success { |
4894 | + continue |
4895 | + } |
4896 | +- c := &Cookie{ |
4897 | ++ c := &http.Cookie{ |
4898 | + Name: name, |
4899 | + Value: value, |
4900 | + Raw: line, |
4901 | +@@ -129,59 +108,12 @@ |
4902 | + return cookies |
4903 | + } |
4904 | + |
4905 | +-// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers. |
4906 | +-func SetCookie(w ResponseWriter, cookie *Cookie) { |
4907 | +- w.Header().Add("Set-Cookie", cookie.String()) |
4908 | +-} |
4909 | +- |
4910 | +-// String returns the serialization of the cookie for use in a Cookie |
4911 | +-// header (if only Name and Value are set) or a Set-Cookie response |
4912 | +-// header (if other fields are set). |
4913 | +-func (c *Cookie) String() string { |
4914 | +- var b bytes.Buffer |
4915 | +- fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) |
4916 | +- if len(c.Path) > 0 { |
4917 | +- fmt.Fprintf(&b, "; Path=%s", sanitizeCookiePath(c.Path)) |
4918 | +- } |
4919 | +- if len(c.Domain) > 0 { |
4920 | +- if validCookieDomain(c.Domain) { |
4921 | +- // A c.Domain containing illegal characters is not |
4922 | +- // sanitized but simply dropped which turns the cookie |
4923 | +- // into a host-only cookie. A leading dot is okay |
4924 | +- // but won't be sent. |
4925 | +- d := c.Domain |
4926 | +- if d[0] == '.' { |
4927 | +- d = d[1:] |
4928 | +- } |
4929 | +- fmt.Fprintf(&b, "; Domain=%s", d) |
4930 | +- } else { |
4931 | +- log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", |
4932 | +- c.Domain) |
4933 | +- } |
4934 | +- } |
4935 | +- if c.Expires.Unix() > 0 { |
4936 | +- fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123)) |
4937 | +- } |
4938 | +- if c.MaxAge > 0 { |
4939 | +- fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge) |
4940 | +- } else if c.MaxAge < 0 { |
4941 | +- fmt.Fprintf(&b, "; Max-Age=0") |
4942 | +- } |
4943 | +- if c.HttpOnly { |
4944 | +- fmt.Fprintf(&b, "; HttpOnly") |
4945 | +- } |
4946 | +- if c.Secure { |
4947 | +- fmt.Fprintf(&b, "; Secure") |
4948 | +- } |
4949 | +- return b.String() |
4950 | +-} |
4951 | +- |
4952 | + // readCookies parses all "Cookie" values from the header h and |
4953 | + // returns the successfully parsed Cookies. |
4954 | + // |
4955 | + // if filter isn't empty, only cookies of that name are returned |
4956 | +-func readCookies(h Header, filter string) []*Cookie { |
4957 | +- cookies := []*Cookie{} |
4958 | ++func readCookies(h http.Header, filter string) []*http.Cookie { |
4959 | ++ cookies := []*http.Cookie{} |
4960 | + lines, ok := h["Cookie"] |
4961 | + if !ok { |
4962 | + return cookies |
4963 | +@@ -213,7 +145,7 @@ |
4964 | + if !success { |
4965 | + continue |
4966 | + } |
4967 | +- cookies = append(cookies, &Cookie{Name: name, Value: val}) |
4968 | ++ cookies = append(cookies, &http.Cookie{Name: name, Value: val}) |
4969 | + parsedPairs++ |
4970 | + } |
4971 | + } |
4972 | + |
4973 | +=== modified file 'http13client/header.go' |
4974 | +--- http13client/header.go 2014-03-19 20:20:19 +0000 |
4975 | ++++ http13client/header.go 2014-03-19 22:27:37 +0000 |
4976 | +@@ -5,176 +5,9 @@ |
4977 | + package http |
4978 | + |
4979 | + import ( |
4980 | +- "io" |
4981 | +- "net/textproto" |
4982 | +- "sort" |
4983 | + "strings" |
4984 | +- "time" |
4985 | + ) |
4986 | + |
4987 | +-var raceEnabled = false // set by race.go |
4988 | +- |
4989 | +-// A Header represents the key-value pairs in an HTTP header. |
4990 | +-type Header map[string][]string |
4991 | +- |
4992 | +-// Add adds the key, value pair to the header. |
4993 | +-// It appends to any existing values associated with key. |
4994 | +-func (h Header) Add(key, value string) { |
4995 | +- textproto.MIMEHeader(h).Add(key, value) |
4996 | +-} |
4997 | +- |
4998 | +-// Set sets the header entries associated with key to |
4999 | +-// the single element value. It replaces any existing |
5000 | +-// values associated with key. |
The diff has been truncated for viewing.
I think you just stole the "Biggest diff evar" trophy from me.