libgo: Update to Go 1.1.1.
[official-gcc.git] / libgo / go / net / http / transport_test.go
blob9f64a6e4b5fd35e361c789dad332f80933b414b3
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Tests for transport.go
7 package http_test
9 import (
10 "bufio"
11 "bytes"
12 "compress/gzip"
13 "crypto/rand"
14 "fmt"
15 "io"
16 "io/ioutil"
17 "net"
18 . "net/http"
19 "net/http/httptest"
20 "net/url"
21 "os"
22 "runtime"
23 "strconv"
24 "strings"
25 "sync"
26 "testing"
27 "time"
30 // TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close
31 // and then verify that the final 2 responses get errors back.
33 // hostPortHandler writes back the client's "host:port".
34 var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
35 if r.FormValue("close") == "true" {
36 w.Header().Set("Connection", "close")
38 w.Write([]byte(r.RemoteAddr))
41 // testCloseConn is a net.Conn tracked by a testConnSet.
42 type testCloseConn struct {
43 net.Conn
44 set *testConnSet
47 func (c *testCloseConn) Close() error {
48 c.set.remove(c)
49 return c.Conn.Close()
52 // testConnSet tracks a set of TCP connections and whether they've
53 // been closed.
54 type testConnSet struct {
55 t *testing.T
56 closed map[net.Conn]bool
57 list []net.Conn // in order created
58 mutex sync.Mutex
61 func (tcs *testConnSet) insert(c net.Conn) {
62 tcs.mutex.Lock()
63 defer tcs.mutex.Unlock()
64 tcs.closed[c] = false
65 tcs.list = append(tcs.list, c)
68 func (tcs *testConnSet) remove(c net.Conn) {
69 tcs.mutex.Lock()
70 defer tcs.mutex.Unlock()
71 tcs.closed[c] = true
74 // some tests use this to manage raw tcp connections for later inspection
75 func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, error)) {
76 connSet := &testConnSet{
77 t: t,
78 closed: make(map[net.Conn]bool),
80 dial := func(n, addr string) (net.Conn, error) {
81 c, err := net.Dial(n, addr)
82 if err != nil {
83 return nil, err
85 tc := &testCloseConn{c, connSet}
86 connSet.insert(tc)
87 return tc, nil
89 return connSet, dial
92 func (tcs *testConnSet) check(t *testing.T) {
93 tcs.mutex.Lock()
94 defer tcs.mutex.Unlock()
96 for i, c := range tcs.list {
97 if !tcs.closed[c] {
98 t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list))
103 // Two subsequent requests and verify their response is the same.
104 // The response from the server is our own IP:port
105 func TestTransportKeepAlives(t *testing.T) {
106 defer afterTest(t)
107 ts := httptest.NewServer(hostPortHandler)
108 defer ts.Close()
110 for _, disableKeepAlive := range []bool{false, true} {
111 tr := &Transport{DisableKeepAlives: disableKeepAlive}
112 defer tr.CloseIdleConnections()
113 c := &Client{Transport: tr}
115 fetch := func(n int) string {
116 res, err := c.Get(ts.URL)
117 if err != nil {
118 t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err)
120 body, err := ioutil.ReadAll(res.Body)
121 if err != nil {
122 t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err)
124 return string(body)
127 body1 := fetch(1)
128 body2 := fetch(2)
130 bodiesDiffer := body1 != body2
131 if bodiesDiffer != disableKeepAlive {
132 t.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
133 disableKeepAlive, bodiesDiffer, body1, body2)
138 func TestTransportConnectionCloseOnResponse(t *testing.T) {
139 defer afterTest(t)
140 ts := httptest.NewServer(hostPortHandler)
141 defer ts.Close()
143 connSet, testDial := makeTestDial(t)
145 for _, connectionClose := range []bool{false, true} {
146 tr := &Transport{
147 Dial: testDial,
149 c := &Client{Transport: tr}
151 fetch := func(n int) string {
152 req := new(Request)
153 var err error
154 req.URL, err = url.Parse(ts.URL + fmt.Sprintf("/?close=%v", connectionClose))
155 if err != nil {
156 t.Fatalf("URL parse error: %v", err)
158 req.Method = "GET"
159 req.Proto = "HTTP/1.1"
160 req.ProtoMajor = 1
161 req.ProtoMinor = 1
163 res, err := c.Do(req)
164 if err != nil {
165 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
167 defer res.Body.Close()
168 body, err := ioutil.ReadAll(res.Body)
169 if err != nil {
170 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
172 return string(body)
175 body1 := fetch(1)
176 body2 := fetch(2)
177 bodiesDiffer := body1 != body2
178 if bodiesDiffer != connectionClose {
179 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
180 connectionClose, bodiesDiffer, body1, body2)
183 tr.CloseIdleConnections()
186 connSet.check(t)
189 func TestTransportConnectionCloseOnRequest(t *testing.T) {
190 defer afterTest(t)
191 ts := httptest.NewServer(hostPortHandler)
192 defer ts.Close()
194 connSet, testDial := makeTestDial(t)
196 for _, connectionClose := range []bool{false, true} {
197 tr := &Transport{
198 Dial: testDial,
200 c := &Client{Transport: tr}
202 fetch := func(n int) string {
203 req := new(Request)
204 var err error
205 req.URL, err = url.Parse(ts.URL)
206 if err != nil {
207 t.Fatalf("URL parse error: %v", err)
209 req.Method = "GET"
210 req.Proto = "HTTP/1.1"
211 req.ProtoMajor = 1
212 req.ProtoMinor = 1
213 req.Close = connectionClose
215 res, err := c.Do(req)
216 if err != nil {
217 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
219 body, err := ioutil.ReadAll(res.Body)
220 if err != nil {
221 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
223 return string(body)
226 body1 := fetch(1)
227 body2 := fetch(2)
228 bodiesDiffer := body1 != body2
229 if bodiesDiffer != connectionClose {
230 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
231 connectionClose, bodiesDiffer, body1, body2)
234 tr.CloseIdleConnections()
237 connSet.check(t)
240 func TestTransportIdleCacheKeys(t *testing.T) {
241 defer afterTest(t)
242 ts := httptest.NewServer(hostPortHandler)
243 defer ts.Close()
245 tr := &Transport{DisableKeepAlives: false}
246 c := &Client{Transport: tr}
248 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
249 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
252 resp, err := c.Get(ts.URL)
253 if err != nil {
254 t.Error(err)
256 ioutil.ReadAll(resp.Body)
258 keys := tr.IdleConnKeysForTesting()
259 if e, g := 1, len(keys); e != g {
260 t.Fatalf("After Get expected %d idle conn cache keys; got %d", e, g)
263 if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e {
264 t.Errorf("Expected idle cache key %q; got %q", e, keys[0])
267 tr.CloseIdleConnections()
268 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
269 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
273 func TestTransportMaxPerHostIdleConns(t *testing.T) {
274 defer afterTest(t)
275 resch := make(chan string)
276 gotReq := make(chan bool)
277 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
278 gotReq <- true
279 msg := <-resch
280 _, err := w.Write([]byte(msg))
281 if err != nil {
282 t.Fatalf("Write: %v", err)
285 defer ts.Close()
286 maxIdleConns := 2
287 tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns}
288 c := &Client{Transport: tr}
290 // Start 3 outstanding requests and wait for the server to get them.
291 // Their responses will hang until we write to resch, though.
292 donech := make(chan bool)
293 doReq := func() {
294 resp, err := c.Get(ts.URL)
295 if err != nil {
296 t.Error(err)
298 _, err = ioutil.ReadAll(resp.Body)
299 if err != nil {
300 t.Fatalf("ReadAll: %v", err)
302 donech <- true
304 go doReq()
305 <-gotReq
306 go doReq()
307 <-gotReq
308 go doReq()
309 <-gotReq
311 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
312 t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g)
315 resch <- "res1"
316 <-donech
317 keys := tr.IdleConnKeysForTesting()
318 if e, g := 1, len(keys); e != g {
319 t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g)
321 cacheKey := "|http|" + ts.Listener.Addr().String()
322 if keys[0] != cacheKey {
323 t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0])
325 if e, g := 1, tr.IdleConnCountForTesting(cacheKey); e != g {
326 t.Errorf("after first response, expected %d idle conns; got %d", e, g)
329 resch <- "res2"
330 <-donech
331 if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g {
332 t.Errorf("after second response, expected %d idle conns; got %d", e, g)
335 resch <- "res3"
336 <-donech
337 if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g {
338 t.Errorf("after third response, still expected %d idle conns; got %d", e, g)
342 func TestTransportServerClosingUnexpectedly(t *testing.T) {
343 defer afterTest(t)
344 ts := httptest.NewServer(hostPortHandler)
345 defer ts.Close()
347 tr := &Transport{}
348 c := &Client{Transport: tr}
350 fetch := func(n, retries int) string {
351 condFatalf := func(format string, arg ...interface{}) {
352 if retries <= 0 {
353 t.Fatalf(format, arg...)
355 t.Logf("retrying shortly after expected error: "+format, arg...)
356 time.Sleep(time.Second / time.Duration(retries))
358 for retries >= 0 {
359 retries--
360 res, err := c.Get(ts.URL)
361 if err != nil {
362 condFatalf("error in req #%d, GET: %v", n, err)
363 continue
365 body, err := ioutil.ReadAll(res.Body)
366 if err != nil {
367 condFatalf("error in req #%d, ReadAll: %v", n, err)
368 continue
370 res.Body.Close()
371 return string(body)
373 panic("unreachable")
376 body1 := fetch(1, 0)
377 body2 := fetch(2, 0)
379 ts.CloseClientConnections() // surprise!
381 // This test has an expected race. Sleeping for 25 ms prevents
382 // it on most fast machines, causing the next fetch() call to
383 // succeed quickly. But if we do get errors, fetch() will retry 5
384 // times with some delays between.
385 time.Sleep(25 * time.Millisecond)
387 body3 := fetch(3, 5)
389 if body1 != body2 {
390 t.Errorf("expected body1 and body2 to be equal")
392 if body2 == body3 {
393 t.Errorf("expected body2 and body3 to be different")
397 // Test for http://golang.org/issue/2616 (appropriate issue number)
398 // This fails pretty reliably with GOMAXPROCS=100 or something high.
399 func TestStressSurpriseServerCloses(t *testing.T) {
400 defer afterTest(t)
401 if testing.Short() {
402 t.Skip("skipping test in short mode")
404 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
405 w.Header().Set("Content-Length", "5")
406 w.Header().Set("Content-Type", "text/plain")
407 w.Write([]byte("Hello"))
408 w.(Flusher).Flush()
409 conn, buf, _ := w.(Hijacker).Hijack()
410 buf.Flush()
411 conn.Close()
413 defer ts.Close()
415 tr := &Transport{DisableKeepAlives: false}
416 c := &Client{Transport: tr}
418 // Do a bunch of traffic from different goroutines. Send to activityc
419 // after each request completes, regardless of whether it failed.
420 const (
421 numClients = 50
422 reqsPerClient = 250
424 activityc := make(chan bool)
425 for i := 0; i < numClients; i++ {
426 go func() {
427 for i := 0; i < reqsPerClient; i++ {
428 res, err := c.Get(ts.URL)
429 if err == nil {
430 // We expect errors since the server is
431 // hanging up on us after telling us to
432 // send more requests, so we don't
433 // actually care what the error is.
434 // But we want to close the body in cases
435 // where we won the race.
436 res.Body.Close()
438 activityc <- true
443 // Make sure all the request come back, one way or another.
444 for i := 0; i < numClients*reqsPerClient; i++ {
445 select {
446 case <-activityc:
447 case <-time.After(5 * time.Second):
448 t.Fatalf("presumed deadlock; no HTTP client activity seen in awhile")
453 // TestTransportHeadResponses verifies that we deal with Content-Lengths
454 // with no bodies properly
455 func TestTransportHeadResponses(t *testing.T) {
456 defer afterTest(t)
457 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
458 if r.Method != "HEAD" {
459 panic("expected HEAD; got " + r.Method)
461 w.Header().Set("Content-Length", "123")
462 w.WriteHeader(200)
464 defer ts.Close()
466 tr := &Transport{DisableKeepAlives: false}
467 c := &Client{Transport: tr}
468 for i := 0; i < 2; i++ {
469 res, err := c.Head(ts.URL)
470 if err != nil {
471 t.Errorf("error on loop %d: %v", i, err)
473 if e, g := "123", res.Header.Get("Content-Length"); e != g {
474 t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g)
476 if e, g := int64(123), res.ContentLength; e != g {
477 t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g)
482 // TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
483 // on responses to HEAD requests.
484 func TestTransportHeadChunkedResponse(t *testing.T) {
485 defer afterTest(t)
486 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
487 if r.Method != "HEAD" {
488 panic("expected HEAD; got " + r.Method)
490 w.Header().Set("Transfer-Encoding", "chunked") // client should ignore
491 w.Header().Set("x-client-ipport", r.RemoteAddr)
492 w.WriteHeader(200)
494 defer ts.Close()
496 tr := &Transport{DisableKeepAlives: false}
497 c := &Client{Transport: tr}
499 res1, err := c.Head(ts.URL)
500 if err != nil {
501 t.Fatalf("request 1 error: %v", err)
503 res2, err := c.Head(ts.URL)
504 if err != nil {
505 t.Fatalf("request 2 error: %v", err)
507 if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 {
508 t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2)
512 var roundTripTests = []struct {
513 accept string
514 expectAccept string
515 compressed bool
517 // Requests with no accept-encoding header use transparent compression
518 {"", "gzip", false},
519 // Requests with other accept-encoding should pass through unmodified
520 {"foo", "foo", false},
521 // Requests with accept-encoding == gzip should be passed through
522 {"gzip", "gzip", true},
525 // Test that the modification made to the Request by the RoundTripper is cleaned up
526 func TestRoundTripGzip(t *testing.T) {
527 defer afterTest(t)
528 const responseBody = "test response body"
529 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
530 accept := req.Header.Get("Accept-Encoding")
531 if expect := req.FormValue("expect_accept"); accept != expect {
532 t.Errorf("in handler, test %v: Accept-Encoding = %q, want %q",
533 req.FormValue("testnum"), accept, expect)
535 if accept == "gzip" {
536 rw.Header().Set("Content-Encoding", "gzip")
537 gz := gzip.NewWriter(rw)
538 gz.Write([]byte(responseBody))
539 gz.Close()
540 } else {
541 rw.Header().Set("Content-Encoding", accept)
542 rw.Write([]byte(responseBody))
545 defer ts.Close()
547 for i, test := range roundTripTests {
548 // Test basic request (no accept-encoding)
549 req, _ := NewRequest("GET", fmt.Sprintf("%s/?testnum=%d&expect_accept=%s", ts.URL, i, test.expectAccept), nil)
550 if test.accept != "" {
551 req.Header.Set("Accept-Encoding", test.accept)
553 res, err := DefaultTransport.RoundTrip(req)
554 var body []byte
555 if test.compressed {
556 gzip, err := gzip.NewReader(res.Body)
557 if err != nil {
558 t.Errorf("%d. gzip NewReader: %v", i, err)
559 continue
561 body, err = ioutil.ReadAll(gzip)
562 res.Body.Close()
563 } else {
564 body, err = ioutil.ReadAll(res.Body)
566 if err != nil {
567 t.Errorf("%d. Error: %q", i, err)
568 continue
570 if g, e := string(body), responseBody; g != e {
571 t.Errorf("%d. body = %q; want %q", i, g, e)
573 if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e {
574 t.Errorf("%d. Accept-Encoding = %q; want %q (it was mutated, in violation of RoundTrip contract)", i, g, e)
576 if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e {
577 t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e)
583 func TestTransportGzip(t *testing.T) {
584 defer afterTest(t)
585 const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
586 const nRandBytes = 1024 * 1024
587 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
588 if g, e := req.Header.Get("Accept-Encoding"), "gzip"; g != e {
589 t.Errorf("Accept-Encoding = %q, want %q", g, e)
591 rw.Header().Set("Content-Encoding", "gzip")
592 if req.Method == "HEAD" {
593 return
596 var w io.Writer = rw
597 var buf bytes.Buffer
598 if req.FormValue("chunked") == "0" {
599 w = &buf
600 defer io.Copy(rw, &buf)
601 defer func() {
602 rw.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
605 gz := gzip.NewWriter(w)
606 gz.Write([]byte(testString))
607 if req.FormValue("body") == "large" {
608 io.CopyN(gz, rand.Reader, nRandBytes)
610 gz.Close()
612 defer ts.Close()
614 for _, chunked := range []string{"1", "0"} {
615 c := &Client{Transport: &Transport{}}
617 // First fetch something large, but only read some of it.
618 res, err := c.Get(ts.URL + "/?body=large&chunked=" + chunked)
619 if err != nil {
620 t.Fatalf("large get: %v", err)
622 buf := make([]byte, len(testString))
623 n, err := io.ReadFull(res.Body, buf)
624 if err != nil {
625 t.Fatalf("partial read of large response: size=%d, %v", n, err)
627 if e, g := testString, string(buf); e != g {
628 t.Errorf("partial read got %q, expected %q", g, e)
630 res.Body.Close()
631 // Read on the body, even though it's closed
632 n, err = res.Body.Read(buf)
633 if n != 0 || err == nil {
634 t.Errorf("expected error post-closed large Read; got = %d, %v", n, err)
637 // Then something small.
638 res, err = c.Get(ts.URL + "/?chunked=" + chunked)
639 if err != nil {
640 t.Fatal(err)
642 body, err := ioutil.ReadAll(res.Body)
643 if err != nil {
644 t.Fatal(err)
646 if g, e := string(body), testString; g != e {
647 t.Fatalf("body = %q; want %q", g, e)
649 if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
650 t.Fatalf("Content-Encoding = %q; want %q", g, e)
653 // Read on the body after it's been fully read:
654 n, err = res.Body.Read(buf)
655 if n != 0 || err == nil {
656 t.Errorf("expected Read error after exhausted reads; got %d, %v", n, err)
658 res.Body.Close()
659 n, err = res.Body.Read(buf)
660 if n != 0 || err == nil {
661 t.Errorf("expected Read error after Close; got %d, %v", n, err)
665 // And a HEAD request too, because they're always weird.
666 c := &Client{Transport: &Transport{}}
667 res, err := c.Head(ts.URL)
668 if err != nil {
669 t.Fatalf("Head: %v", err)
671 if res.StatusCode != 200 {
672 t.Errorf("Head status=%d; want=200", res.StatusCode)
676 func TestTransportProxy(t *testing.T) {
677 defer afterTest(t)
678 ch := make(chan string, 1)
679 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
680 ch <- "real server"
682 defer ts.Close()
683 proxy := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
684 ch <- "proxy for " + r.URL.String()
686 defer proxy.Close()
688 pu, err := url.Parse(proxy.URL)
689 if err != nil {
690 t.Fatal(err)
692 c := &Client{Transport: &Transport{Proxy: ProxyURL(pu)}}
693 c.Head(ts.URL)
694 got := <-ch
695 want := "proxy for " + ts.URL + "/"
696 if got != want {
697 t.Errorf("want %q, got %q", want, got)
701 // TestTransportGzipRecursive sends a gzip quine and checks that the
702 // client gets the same value back. This is more cute than anything,
703 // but checks that we don't recurse forever, and checks that
704 // Content-Encoding is removed.
705 func TestTransportGzipRecursive(t *testing.T) {
706 defer afterTest(t)
707 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
708 w.Header().Set("Content-Encoding", "gzip")
709 w.Write(rgz)
711 defer ts.Close()
713 c := &Client{Transport: &Transport{}}
714 res, err := c.Get(ts.URL)
715 if err != nil {
716 t.Fatal(err)
718 body, err := ioutil.ReadAll(res.Body)
719 if err != nil {
720 t.Fatal(err)
722 if !bytes.Equal(body, rgz) {
723 t.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x",
724 body, rgz)
726 if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
727 t.Fatalf("Content-Encoding = %q; want %q", g, e)
731 // tests that persistent goroutine connections shut down when no longer desired.
732 func TestTransportPersistConnLeak(t *testing.T) {
733 defer afterTest(t)
734 gotReqCh := make(chan bool)
735 unblockCh := make(chan bool)
736 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
737 gotReqCh <- true
738 <-unblockCh
739 w.Header().Set("Content-Length", "0")
740 w.WriteHeader(204)
742 defer ts.Close()
744 tr := &Transport{}
745 c := &Client{Transport: tr}
747 n0 := runtime.NumGoroutine()
749 const numReq = 25
750 didReqCh := make(chan bool)
751 for i := 0; i < numReq; i++ {
752 go func() {
753 res, err := c.Get(ts.URL)
754 didReqCh <- true
755 if err != nil {
756 t.Errorf("client fetch error: %v", err)
757 return
759 res.Body.Close()
763 // Wait for all goroutines to be stuck in the Handler.
764 for i := 0; i < numReq; i++ {
765 <-gotReqCh
768 nhigh := runtime.NumGoroutine()
770 // Tell all handlers to unblock and reply.
771 for i := 0; i < numReq; i++ {
772 unblockCh <- true
775 // Wait for all HTTP clients to be done.
776 for i := 0; i < numReq; i++ {
777 <-didReqCh
780 tr.CloseIdleConnections()
781 time.Sleep(100 * time.Millisecond)
782 runtime.GC()
783 runtime.GC() // even more.
784 nfinal := runtime.NumGoroutine()
786 growth := nfinal - n0
788 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
789 // Previously we were leaking one per numReq.
790 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
791 if int(growth) > 5 {
792 t.Error("too many new goroutines")
796 // golang.org/issue/4531: Transport leaks goroutines when
797 // request.ContentLength is explicitly short
798 func TestTransportPersistConnLeakShortBody(t *testing.T) {
799 defer afterTest(t)
800 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
802 defer ts.Close()
804 tr := &Transport{}
805 c := &Client{Transport: tr}
807 n0 := runtime.NumGoroutine()
808 body := []byte("Hello")
809 for i := 0; i < 20; i++ {
810 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body))
811 if err != nil {
812 t.Fatal(err)
814 req.ContentLength = int64(len(body) - 2) // explicitly short
815 _, err = c.Do(req)
816 if err == nil {
817 t.Fatal("Expect an error from writing too long of a body.")
820 nhigh := runtime.NumGoroutine()
821 tr.CloseIdleConnections()
822 time.Sleep(50 * time.Millisecond)
823 runtime.GC()
824 nfinal := runtime.NumGoroutine()
826 growth := nfinal - n0
828 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
829 // Previously we were leaking one per numReq.
830 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
831 if int(growth) > 5 {
832 t.Error("too many new goroutines")
836 // This used to crash; http://golang.org/issue/3266
837 func TestTransportIdleConnCrash(t *testing.T) {
838 defer afterTest(t)
839 tr := &Transport{}
840 c := &Client{Transport: tr}
842 unblockCh := make(chan bool, 1)
843 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
844 <-unblockCh
845 tr.CloseIdleConnections()
847 defer ts.Close()
849 didreq := make(chan bool)
850 go func() {
851 res, err := c.Get(ts.URL)
852 if err != nil {
853 t.Error(err)
854 } else {
855 res.Body.Close() // returns idle conn
857 didreq <- true
859 unblockCh <- true
860 <-didreq
863 // Test that the transport doesn't close the TCP connection early,
864 // before the response body has been read. This was a regression
865 // which sadly lacked a triggering test. The large response body made
866 // the old race easier to trigger.
867 func TestIssue3644(t *testing.T) {
868 defer afterTest(t)
869 const numFoos = 5000
870 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
871 w.Header().Set("Connection", "close")
872 for i := 0; i < numFoos; i++ {
873 w.Write([]byte("foo "))
876 defer ts.Close()
877 tr := &Transport{}
878 c := &Client{Transport: tr}
879 res, err := c.Get(ts.URL)
880 if err != nil {
881 t.Fatal(err)
883 defer res.Body.Close()
884 bs, err := ioutil.ReadAll(res.Body)
885 if err != nil {
886 t.Fatal(err)
888 if len(bs) != numFoos*len("foo ") {
889 t.Errorf("unexpected response length")
893 // Test that a client receives a server's reply, even if the server doesn't read
894 // the entire request body.
895 func TestIssue3595(t *testing.T) {
896 defer afterTest(t)
897 const deniedMsg = "sorry, denied."
898 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
899 Error(w, deniedMsg, StatusUnauthorized)
901 defer ts.Close()
902 tr := &Transport{}
903 c := &Client{Transport: tr}
904 res, err := c.Post(ts.URL, "application/octet-stream", neverEnding('a'))
905 if err != nil {
906 t.Errorf("Post: %v", err)
907 return
909 got, err := ioutil.ReadAll(res.Body)
910 if err != nil {
911 t.Fatalf("Body ReadAll: %v", err)
913 if !strings.Contains(string(got), deniedMsg) {
914 t.Errorf("Known bug: response %q does not contain %q", got, deniedMsg)
918 // From http://golang.org/issue/4454 ,
919 // "client fails to handle requests with no body and chunked encoding"
920 func TestChunkedNoContent(t *testing.T) {
921 defer afterTest(t)
922 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
923 w.WriteHeader(StatusNoContent)
925 defer ts.Close()
927 for _, closeBody := range []bool{true, false} {
928 c := &Client{Transport: &Transport{}}
929 const n = 4
930 for i := 1; i <= n; i++ {
931 res, err := c.Get(ts.URL)
932 if err != nil {
933 t.Errorf("closingBody=%v, req %d/%d: %v", closeBody, i, n, err)
934 } else {
935 if closeBody {
936 res.Body.Close()
943 func TestTransportConcurrency(t *testing.T) {
944 defer afterTest(t)
945 maxProcs, numReqs := 16, 500
946 if testing.Short() {
947 maxProcs, numReqs = 4, 50
949 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
950 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
951 fmt.Fprintf(w, "%v", r.FormValue("echo"))
953 defer ts.Close()
955 var wg sync.WaitGroup
956 wg.Add(numReqs)
958 tr := &Transport{
959 Dial: func(netw, addr string) (c net.Conn, err error) {
960 // Due to the Transport's "socket late
961 // binding" (see idleConnCh in transport.go),
962 // the numReqs HTTP requests below can finish
963 // with a dial still outstanding. So count
964 // our dials as work too so the leak checker
965 // doesn't complain at us.
966 wg.Add(1)
967 defer wg.Done()
968 return net.Dial(netw, addr)
971 defer tr.CloseIdleConnections()
972 c := &Client{Transport: tr}
973 reqs := make(chan string)
974 defer close(reqs)
976 for i := 0; i < maxProcs*2; i++ {
977 go func() {
978 for req := range reqs {
979 res, err := c.Get(ts.URL + "/?echo=" + req)
980 if err != nil {
981 t.Errorf("error on req %s: %v", req, err)
982 wg.Done()
983 continue
985 all, err := ioutil.ReadAll(res.Body)
986 if err != nil {
987 t.Errorf("read error on req %s: %v", req, err)
988 wg.Done()
989 continue
991 if string(all) != req {
992 t.Errorf("body of req %s = %q; want %q", req, all, req)
994 res.Body.Close()
995 wg.Done()
999 for i := 0; i < numReqs; i++ {
1000 reqs <- fmt.Sprintf("request-%d", i)
1002 wg.Wait()
1005 func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
1006 defer afterTest(t)
1007 const debug = false
1008 mux := NewServeMux()
1009 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
1010 io.Copy(w, neverEnding('a'))
1012 ts := httptest.NewServer(mux)
1013 timeout := 100 * time.Millisecond
1015 client := &Client{
1016 Transport: &Transport{
1017 Dial: func(n, addr string) (net.Conn, error) {
1018 conn, err := net.Dial(n, addr)
1019 if err != nil {
1020 return nil, err
1022 conn.SetDeadline(time.Now().Add(timeout))
1023 if debug {
1024 conn = NewLoggingConn("client", conn)
1026 return conn, nil
1028 DisableKeepAlives: true,
1032 getFailed := false
1033 nRuns := 5
1034 if testing.Short() {
1035 nRuns = 1
1037 for i := 0; i < nRuns; i++ {
1038 if debug {
1039 println("run", i+1, "of", nRuns)
1041 sres, err := client.Get(ts.URL + "/get")
1042 if err != nil {
1043 if !getFailed {
1044 // Make the timeout longer, once.
1045 getFailed = true
1046 t.Logf("increasing timeout")
1048 timeout *= 10
1049 continue
1051 t.Errorf("Error issuing GET: %v", err)
1052 break
1054 _, err = io.Copy(ioutil.Discard, sres.Body)
1055 if err == nil {
1056 t.Errorf("Unexpected successful copy")
1057 break
1060 if debug {
1061 println("tests complete; waiting for handlers to finish")
1063 ts.Close()
1066 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
1067 defer afterTest(t)
1068 const debug = false
1069 mux := NewServeMux()
1070 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
1071 io.Copy(w, neverEnding('a'))
1073 mux.HandleFunc("/put", func(w ResponseWriter, r *Request) {
1074 defer r.Body.Close()
1075 io.Copy(ioutil.Discard, r.Body)
1077 ts := httptest.NewServer(mux)
1078 timeout := 100 * time.Millisecond
1080 client := &Client{
1081 Transport: &Transport{
1082 Dial: func(n, addr string) (net.Conn, error) {
1083 conn, err := net.Dial(n, addr)
1084 if err != nil {
1085 return nil, err
1087 conn.SetDeadline(time.Now().Add(timeout))
1088 if debug {
1089 conn = NewLoggingConn("client", conn)
1091 return conn, nil
1093 DisableKeepAlives: true,
1097 getFailed := false
1098 nRuns := 5
1099 if testing.Short() {
1100 nRuns = 1
1102 for i := 0; i < nRuns; i++ {
1103 if debug {
1104 println("run", i+1, "of", nRuns)
1106 sres, err := client.Get(ts.URL + "/get")
1107 if err != nil {
1108 if !getFailed {
1109 // Make the timeout longer, once.
1110 getFailed = true
1111 t.Logf("increasing timeout")
1113 timeout *= 10
1114 continue
1116 t.Errorf("Error issuing GET: %v", err)
1117 break
1119 req, _ := NewRequest("PUT", ts.URL+"/put", sres.Body)
1120 _, err = client.Do(req)
1121 if err == nil {
1122 sres.Body.Close()
1123 t.Errorf("Unexpected successful PUT")
1124 break
1126 sres.Body.Close()
1128 if debug {
1129 println("tests complete; waiting for handlers to finish")
1131 ts.Close()
1134 func TestTransportResponseHeaderTimeout(t *testing.T) {
1135 defer afterTest(t)
1136 if testing.Short() {
1137 t.Skip("skipping timeout test in -short mode")
1139 mux := NewServeMux()
1140 mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {})
1141 mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) {
1142 time.Sleep(2 * time.Second)
1144 ts := httptest.NewServer(mux)
1145 defer ts.Close()
1147 tr := &Transport{
1148 ResponseHeaderTimeout: 500 * time.Millisecond,
1150 defer tr.CloseIdleConnections()
1151 c := &Client{Transport: tr}
1153 tests := []struct {
1154 path string
1155 want int
1156 wantErr string
1158 {path: "/fast", want: 200},
1159 {path: "/slow", wantErr: "timeout awaiting response headers"},
1160 {path: "/fast", want: 200},
1162 for i, tt := range tests {
1163 res, err := c.Get(ts.URL + tt.path)
1164 if err != nil {
1165 if strings.Contains(err.Error(), tt.wantErr) {
1166 continue
1168 t.Errorf("%d. unexpected error: %v", i, err)
1169 continue
1171 if tt.wantErr != "" {
1172 t.Errorf("%d. no error. expected error: %v", i, tt.wantErr)
1173 continue
1175 if res.StatusCode != tt.want {
1176 t.Errorf("%d for path %q status = %d; want %d", i, tt.path, res.StatusCode, tt.want)
1181 func TestTransportCancelRequest(t *testing.T) {
1182 defer afterTest(t)
1183 if testing.Short() {
1184 t.Skip("skipping test in -short mode")
1186 unblockc := make(chan bool)
1187 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
1188 fmt.Fprintf(w, "Hello")
1189 w.(Flusher).Flush() // send headers and some body
1190 <-unblockc
1192 defer ts.Close()
1193 defer close(unblockc)
1195 tr := &Transport{}
1196 defer tr.CloseIdleConnections()
1197 c := &Client{Transport: tr}
1199 req, _ := NewRequest("GET", ts.URL, nil)
1200 res, err := c.Do(req)
1201 if err != nil {
1202 t.Fatal(err)
1204 go func() {
1205 time.Sleep(1 * time.Second)
1206 tr.CancelRequest(req)
1208 t0 := time.Now()
1209 body, err := ioutil.ReadAll(res.Body)
1210 d := time.Since(t0)
1212 if err == nil {
1213 t.Error("expected an error reading the body")
1215 if string(body) != "Hello" {
1216 t.Errorf("Body = %q; want Hello", body)
1218 if d < 500*time.Millisecond {
1219 t.Errorf("expected ~1 second delay; got %v", d)
1221 // Verify no outstanding requests after readLoop/writeLoop
1222 // goroutines shut down.
1223 for tries := 3; tries > 0; tries-- {
1224 n := tr.NumPendingRequestsForTesting()
1225 if n == 0 {
1226 break
1228 time.Sleep(100 * time.Millisecond)
1229 if tries == 1 {
1230 t.Errorf("pending requests = %d; want 0", n)
1235 // golang.org/issue/3672 -- Client can't close HTTP stream
1236 // Calling Close on a Response.Body used to just read until EOF.
1237 // Now it actually closes the TCP connection.
1238 func TestTransportCloseResponseBody(t *testing.T) {
1239 defer afterTest(t)
1240 writeErr := make(chan error, 1)
1241 msg := []byte("young\n")
1242 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
1243 for {
1244 _, err := w.Write(msg)
1245 if err != nil {
1246 writeErr <- err
1247 return
1249 w.(Flusher).Flush()
1252 defer ts.Close()
1254 tr := &Transport{}
1255 defer tr.CloseIdleConnections()
1256 c := &Client{Transport: tr}
1258 req, _ := NewRequest("GET", ts.URL, nil)
1259 defer tr.CancelRequest(req)
1261 res, err := c.Do(req)
1262 if err != nil {
1263 t.Fatal(err)
1266 const repeats = 3
1267 buf := make([]byte, len(msg)*repeats)
1268 want := bytes.Repeat(msg, repeats)
1270 _, err = io.ReadFull(res.Body, buf)
1271 if err != nil {
1272 t.Fatal(err)
1274 if !bytes.Equal(buf, want) {
1275 t.Errorf("read %q; want %q", buf, want)
1277 didClose := make(chan error, 1)
1278 go func() {
1279 didClose <- res.Body.Close()
1281 select {
1282 case err := <-didClose:
1283 if err != nil {
1284 t.Errorf("Close = %v", err)
1286 case <-time.After(10 * time.Second):
1287 t.Fatal("too long waiting for close")
1289 select {
1290 case err := <-writeErr:
1291 if err == nil {
1292 t.Errorf("expected non-nil write error")
1294 case <-time.After(10 * time.Second):
1295 t.Fatal("too long waiting for write error")
1299 type fooProto struct{}
1301 func (fooProto) RoundTrip(req *Request) (*Response, error) {
1302 res := &Response{
1303 Status: "200 OK",
1304 StatusCode: 200,
1305 Header: make(Header),
1306 Body: ioutil.NopCloser(strings.NewReader("You wanted " + req.URL.String())),
1308 return res, nil
1311 func TestTransportAltProto(t *testing.T) {
1312 defer afterTest(t)
1313 tr := &Transport{}
1314 c := &Client{Transport: tr}
1315 tr.RegisterProtocol("foo", fooProto{})
1316 res, err := c.Get("foo://bar.com/path")
1317 if err != nil {
1318 t.Fatal(err)
1320 bodyb, err := ioutil.ReadAll(res.Body)
1321 if err != nil {
1322 t.Fatal(err)
1324 body := string(bodyb)
1325 if e := "You wanted foo://bar.com/path"; body != e {
1326 t.Errorf("got response %q, want %q", body, e)
1330 func TestTransportNoHost(t *testing.T) {
1331 defer afterTest(t)
1332 tr := &Transport{}
1333 _, err := tr.RoundTrip(&Request{
1334 Header: make(Header),
1335 URL: &url.URL{
1336 Scheme: "http",
1339 want := "http: no Host in request URL"
1340 if got := fmt.Sprint(err); got != want {
1341 t.Errorf("error = %v; want %q", err, want)
1345 func TestTransportSocketLateBinding(t *testing.T) {
1346 defer afterTest(t)
1348 mux := NewServeMux()
1349 fooGate := make(chan bool, 1)
1350 mux.HandleFunc("/foo", func(w ResponseWriter, r *Request) {
1351 w.Header().Set("foo-ipport", r.RemoteAddr)
1352 w.(Flusher).Flush()
1353 <-fooGate
1355 mux.HandleFunc("/bar", func(w ResponseWriter, r *Request) {
1356 w.Header().Set("bar-ipport", r.RemoteAddr)
1358 ts := httptest.NewServer(mux)
1359 defer ts.Close()
1361 dialGate := make(chan bool, 1)
1362 tr := &Transport{
1363 Dial: func(n, addr string) (net.Conn, error) {
1364 <-dialGate
1365 return net.Dial(n, addr)
1367 DisableKeepAlives: false,
1369 defer tr.CloseIdleConnections()
1370 c := &Client{
1371 Transport: tr,
1374 dialGate <- true // only allow one dial
1375 fooRes, err := c.Get(ts.URL + "/foo")
1376 if err != nil {
1377 t.Fatal(err)
1379 fooAddr := fooRes.Header.Get("foo-ipport")
1380 if fooAddr == "" {
1381 t.Fatal("No addr on /foo request")
1383 time.AfterFunc(200*time.Millisecond, func() {
1384 // let the foo response finish so we can use its
1385 // connection for /bar
1386 fooGate <- true
1387 io.Copy(ioutil.Discard, fooRes.Body)
1388 fooRes.Body.Close()
1391 barRes, err := c.Get(ts.URL + "/bar")
1392 if err != nil {
1393 t.Fatal(err)
1395 barAddr := barRes.Header.Get("bar-ipport")
1396 if barAddr != fooAddr {
1397 t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr)
1399 barRes.Body.Close()
1400 dialGate <- true
1403 // Issue 2184
1404 func TestTransportReading100Continue(t *testing.T) {
1405 defer afterTest(t)
1407 const numReqs = 5
1408 reqBody := func(n int) string { return fmt.Sprintf("request body %d", n) }
1409 reqID := func(n int) string { return fmt.Sprintf("REQ-ID-%d", n) }
1411 send100Response := func(w *io.PipeWriter, r *io.PipeReader) {
1412 defer w.Close()
1413 defer r.Close()
1414 br := bufio.NewReader(r)
1415 n := 0
1416 for {
1418 req, err := ReadRequest(br)
1419 if err == io.EOF {
1420 return
1422 if err != nil {
1423 t.Error(err)
1424 return
1426 slurp, err := ioutil.ReadAll(req.Body)
1427 if err != nil {
1428 t.Errorf("Server request body slurp: %v", err)
1429 return
1431 id := req.Header.Get("Request-Id")
1432 resCode := req.Header.Get("X-Want-Response-Code")
1433 if resCode == "" {
1434 resCode = "100 Continue"
1435 if string(slurp) != reqBody(n) {
1436 t.Errorf("Server got %q, %v; want %q", slurp, err, reqBody(n))
1439 body := fmt.Sprintf("Response number %d", n)
1440 v := []byte(strings.Replace(fmt.Sprintf(`HTTP/1.1 %s
1441 Date: Thu, 28 Feb 2013 17:55:41 GMT
1443 HTTP/1.1 200 OK
1444 Content-Type: text/html
1445 Echo-Request-Id: %s
1446 Content-Length: %d
1448 %s`, resCode, id, len(body), body), "\n", "\r\n", -1))
1449 w.Write(v)
1450 if id == reqID(numReqs) {
1451 return
1457 tr := &Transport{
1458 Dial: func(n, addr string) (net.Conn, error) {
1459 sr, sw := io.Pipe() // server read/write
1460 cr, cw := io.Pipe() // client read/write
1461 conn := &rwTestConn{
1462 Reader: cr,
1463 Writer: sw,
1464 closeFunc: func() error {
1465 sw.Close()
1466 cw.Close()
1467 return nil
1470 go send100Response(cw, sr)
1471 return conn, nil
1473 DisableKeepAlives: false,
1475 defer tr.CloseIdleConnections()
1476 c := &Client{Transport: tr}
1478 testResponse := func(req *Request, name string, wantCode int) {
1479 res, err := c.Do(req)
1480 if err != nil {
1481 t.Fatalf("%s: Do: %v", name, err)
1483 if res.StatusCode != wantCode {
1484 t.Fatalf("%s: Response Statuscode=%d; want %d", name, res.StatusCode, wantCode)
1486 if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack {
1487 t.Errorf("%s: response id %q != request id %q", name, idBack, id)
1489 _, err = ioutil.ReadAll(res.Body)
1490 if err != nil {
1491 t.Fatalf("%s: Slurp error: %v", name, err)
1495 // Few 100 responses, making sure we're not off-by-one.
1496 for i := 1; i <= numReqs; i++ {
1497 req, _ := NewRequest("POST", "http://dummy.tld/", strings.NewReader(reqBody(i)))
1498 req.Header.Set("Request-Id", reqID(i))
1499 testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200)
1502 // And some other informational 1xx but non-100 responses, to test
1503 // we return them but don't re-use the connection.
1504 for i := 1; i <= numReqs; i++ {
1505 req, _ := NewRequest("POST", "http://other.tld/", strings.NewReader(reqBody(i)))
1506 req.Header.Set("X-Want-Response-Code", "123 Sesame Street")
1507 testResponse(req, fmt.Sprintf("123, %d/%d", i, numReqs), 123)
1511 type proxyFromEnvTest struct {
1512 req string // URL to fetch; blank means "http://example.com"
1513 env string
1514 noenv string
1515 want string
1516 wanterr error
1519 func (t proxyFromEnvTest) String() string {
1520 var buf bytes.Buffer
1521 if t.env != "" {
1522 fmt.Fprintf(&buf, "http_proxy=%q", t.env)
1524 if t.noenv != "" {
1525 fmt.Fprintf(&buf, " no_proxy=%q", t.noenv)
1527 req := "http://example.com"
1528 if t.req != "" {
1529 req = t.req
1531 fmt.Fprintf(&buf, " req=%q", req)
1532 return strings.TrimSpace(buf.String())
1535 var proxyFromEnvTests = []proxyFromEnvTest{
1536 {env: "127.0.0.1:8080", want: "http://127.0.0.1:8080"},
1537 {env: "cache.corp.example.com:1234", want: "http://cache.corp.example.com:1234"},
1538 {env: "cache.corp.example.com", want: "http://cache.corp.example.com"},
1539 {env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"},
1540 {env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"},
1541 {env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"},
1542 {want: "<nil>"},
1543 {noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
1544 {noenv: ".example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
1545 {noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"},
1546 {noenv: "example.com", req: "http://foo.example.com/", env: "proxy", want: "<nil>"},
1547 {noenv: ".foo.com", req: "http://example.com/", env: "proxy", want: "http://proxy"},
1550 func TestProxyFromEnvironment(t *testing.T) {
1551 os.Setenv("HTTP_PROXY", "")
1552 os.Setenv("http_proxy", "")
1553 os.Setenv("NO_PROXY", "")
1554 os.Setenv("no_proxy", "")
1555 for _, tt := range proxyFromEnvTests {
1556 os.Setenv("HTTP_PROXY", tt.env)
1557 os.Setenv("NO_PROXY", tt.noenv)
1558 reqURL := tt.req
1559 if reqURL == "" {
1560 reqURL = "http://example.com"
1562 req, _ := NewRequest("GET", reqURL, nil)
1563 url, err := ProxyFromEnvironment(req)
1564 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
1565 t.Errorf("%v: got error = %q, want %q", tt, g, e)
1566 continue
1568 if got := fmt.Sprintf("%s", url); got != tt.want {
1569 t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
1574 // rgz is a gzip quine that uncompresses to itself.
1575 var rgz = []byte{
1576 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
1577 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73,
1578 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0,
1579 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2,
1580 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17,
1581 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60,
1582 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2,
1583 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00,
1584 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00,
1585 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16,
1586 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05,
1587 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff,
1588 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00,
1589 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00,
1590 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
1591 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88,
1592 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff,
1593 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00,
1594 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00,
1595 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
1596 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
1597 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff,
1598 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00,
1599 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
1600 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16,
1601 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08,
1602 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa,
1603 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06,
1604 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00,
1605 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
1606 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
1607 0x00, 0x00,