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 // More tests are in clientserver_test.go (for things testing both client & server for both
8 // HTTP/1 and HTTP/2). This
47 // TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close
48 // and then verify that the final 2 responses get errors back.
50 // hostPortHandler writes back the client's "host:port".
51 var hostPortHandler
= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
52 if r
.FormValue("close") == "true" {
53 w
.Header().Set("Connection", "close")
55 w
.Header().Set("X-Saw-Close", fmt
.Sprint(r
.Close
))
56 w
.Write([]byte(r
.RemoteAddr
))
59 // testCloseConn is a net.Conn tracked by a testConnSet.
60 type testCloseConn
struct {
65 func (c
*testCloseConn
) Close() error
{
70 // testConnSet tracks a set of TCP connections and whether they've
72 type testConnSet
struct {
74 mu sync
.Mutex
// guards closed and list
75 closed map[net
.Conn
]bool
76 list
[]net
.Conn
// in order created
79 func (tcs
*testConnSet
) insert(c net
.Conn
) {
83 tcs
.list
= append(tcs
.list
, c
)
86 func (tcs
*testConnSet
) remove(c net
.Conn
) {
92 // some tests use this to manage raw tcp connections for later inspection
93 func makeTestDial(t
*testing
.T
) (*testConnSet
, func(n
, addr
string) (net
.Conn
, error
)) {
94 connSet
:= &testConnSet
{
96 closed: make(map[net
.Conn
]bool),
98 dial
:= func(n
, addr
string) (net
.Conn
, error
) {
99 c
, err
:= net
.Dial(n
, addr
)
103 tc
:= &testCloseConn
{c
, connSet
}
110 func (tcs
*testConnSet
) check(t
*testing
.T
) {
112 defer tcs
.mu
.Unlock()
113 for i
:= 4; i
>= 0; i
-- {
114 for i
, c
:= range tcs
.list
{
120 time
.Sleep(50 * time
.Millisecond
)
124 t
.Errorf("TCP connection #%d, %p (of %d total) was not closed", i
+1, c
, len(tcs
.list
))
129 func TestReuseRequest(t
*testing
.T
) {
131 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
132 w
.Write([]byte("{}"))
137 req
, _
:= NewRequest("GET", ts
.URL
, nil)
138 res
, err
:= c
.Do(req
)
142 err
= res
.Body
.Close()
151 err
= res
.Body
.Close()
157 // Two subsequent requests and verify their response is the same.
158 // The response from the server is our own IP:port
159 func TestTransportKeepAlives(t
*testing
.T
) {
161 ts
:= httptest
.NewServer(hostPortHandler
)
165 for _
, disableKeepAlive
:= range []bool{false, true} {
166 c
.Transport
.(*Transport
).DisableKeepAlives
= disableKeepAlive
167 fetch
:= func(n
int) string {
168 res
, err
:= c
.Get(ts
.URL
)
170 t
.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive
, n
, err
)
172 body
, err
:= ioutil
.ReadAll(res
.Body
)
174 t
.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive
, n
, err
)
182 bodiesDiffer
:= body1
!= body2
183 if bodiesDiffer
!= disableKeepAlive
{
184 t
.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
185 disableKeepAlive
, bodiesDiffer
, body1
, body2
)
190 func TestTransportConnectionCloseOnResponse(t
*testing
.T
) {
192 ts
:= httptest
.NewServer(hostPortHandler
)
195 connSet
, testDial
:= makeTestDial(t
)
198 tr
:= c
.Transport
.(*Transport
)
201 for _
, connectionClose
:= range []bool{false, true} {
202 fetch
:= func(n
int) string {
205 req
.URL
, err
= url
.Parse(ts
.URL
+ fmt
.Sprintf("/?close=%v", connectionClose
))
207 t
.Fatalf("URL parse error: %v", err
)
210 req
.Proto
= "HTTP/1.1"
214 res
, err
:= c
.Do(req
)
216 t
.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose
, n
, err
)
218 defer res
.Body
.Close()
219 body
, err
:= ioutil
.ReadAll(res
.Body
)
221 t
.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose
, n
, err
)
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()
240 func TestTransportConnectionCloseOnRequest(t
*testing
.T
) {
242 ts
:= httptest
.NewServer(hostPortHandler
)
245 connSet
, testDial
:= makeTestDial(t
)
248 tr
:= c
.Transport
.(*Transport
)
250 for _
, connectionClose
:= range []bool{false, true} {
251 fetch
:= func(n
int) string {
254 req
.URL
, err
= url
.Parse(ts
.URL
)
256 t
.Fatalf("URL parse error: %v", err
)
259 req
.Proto
= "HTTP/1.1"
262 req
.Close
= connectionClose
264 res
, err
:= c
.Do(req
)
266 t
.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose
, n
, err
)
268 if got
, want
:= res
.Header
.Get("X-Saw-Close"), fmt
.Sprint(connectionClose
); got
!= want
{
269 t
.Errorf("For connectionClose = %v; handler's X-Saw-Close was %v; want %v",
270 connectionClose
, got
, !connectionClose
)
272 body
, err
:= ioutil
.ReadAll(res
.Body
)
274 t
.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose
, n
, err
)
281 bodiesDiffer
:= body1
!= body2
282 if bodiesDiffer
!= connectionClose
{
283 t
.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
284 connectionClose
, bodiesDiffer
, body1
, body2
)
287 tr
.CloseIdleConnections()
293 // if the Transport's DisableKeepAlives is set, all requests should
294 // send Connection: close.
295 // HTTP/1-only (Connection: close doesn't exist in h2)
296 func TestTransportConnectionCloseOnRequestDisableKeepAlive(t
*testing
.T
) {
298 ts
:= httptest
.NewServer(hostPortHandler
)
302 c
.Transport
.(*Transport
).DisableKeepAlives
= true
304 res
, err
:= c
.Get(ts
.URL
)
309 if res
.Header
.Get("X-Saw-Close") != "true" {
310 t
.Errorf("handler didn't see Connection: close ")
314 func TestTransportIdleCacheKeys(t
*testing
.T
) {
316 ts
:= httptest
.NewServer(hostPortHandler
)
319 tr
:= c
.Transport
.(*Transport
)
321 if e
, g
:= 0, len(tr
.IdleConnKeysForTesting()); e
!= g
{
322 t
.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e
, g
)
325 resp
, err
:= c
.Get(ts
.URL
)
329 ioutil
.ReadAll(resp
.Body
)
331 keys
:= tr
.IdleConnKeysForTesting()
332 if e
, g
:= 1, len(keys
); e
!= g
{
333 t
.Fatalf("After Get expected %d idle conn cache keys; got %d", e
, g
)
336 if e
:= "|http|" + ts
.Listener
.Addr().String(); keys
[0] != e
{
337 t
.Errorf("Expected idle cache key %q; got %q", e
, keys
[0])
340 tr
.CloseIdleConnections()
341 if e
, g
:= 0, len(tr
.IdleConnKeysForTesting()); e
!= g
{
342 t
.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e
, g
)
346 // Tests that the HTTP transport re-uses connections when a client
347 // reads to the end of a response Body without closing it.
348 func TestTransportReadToEndReusesConn(t
*testing
.T
) {
352 var addrSeen
map[string]int
353 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
354 addrSeen
[r
.RemoteAddr
]++
355 if r
.URL
.Path
== "/chunked/" {
359 w
.Header().Set("Content-Type", strconv
.Itoa(len(msg
)))
366 buf
:= make([]byte, len(msg
))
368 for pi
, path
:= range []string{"/content-length/", "/chunked/"} {
369 wantLen
:= []int{len(msg
), -1}[pi
]
370 addrSeen
= make(map[string]int)
371 for i
:= 0; i
< 3; i
++ {
372 res
, err
:= Get(ts
.URL
+ path
)
374 t
.Errorf("Get %s: %v", path
, err
)
377 // We want to close this body eventually (before the
378 // defer afterTest at top runs), but not before the
379 // len(addrSeen) check at the bottom of this test,
380 // since Closing this early in the loop would risk
381 // making connections be re-used for the wrong reason.
382 defer res
.Body
.Close()
384 if res
.ContentLength
!= int64(wantLen
) {
385 t
.Errorf("%s res.ContentLength = %d; want %d", path
, res
.ContentLength
, wantLen
)
387 n
, err
:= res
.Body
.Read(buf
)
388 if n
!= len(msg
) || err
!= io
.EOF
{
389 t
.Errorf("%s Read = %v, %v; want %d, EOF", path
, n
, err
, len(msg
))
392 if len(addrSeen
) != 1 {
393 t
.Errorf("for %s, server saw %d distinct client addresses; want 1", path
, len(addrSeen
))
398 func TestTransportMaxPerHostIdleConns(t
*testing
.T
) {
400 resch
:= make(chan string)
401 gotReq
:= make(chan bool)
402 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
405 _
, err
:= w
.Write([]byte(msg
))
407 t
.Fatalf("Write: %v", err
)
413 tr
:= c
.Transport
.(*Transport
)
414 maxIdleConnsPerHost
:= 2
415 tr
.MaxIdleConnsPerHost
= maxIdleConnsPerHost
417 // Start 3 outstanding requests and wait for the server to get them.
418 // Their responses will hang until we write to resch, though.
419 donech
:= make(chan bool)
421 resp
, err
:= c
.Get(ts
.URL
)
426 if _
, err
:= ioutil
.ReadAll(resp
.Body
); err
!= nil {
427 t
.Errorf("ReadAll: %v", err
)
439 if e
, g
:= 0, len(tr
.IdleConnKeysForTesting()); e
!= g
{
440 t
.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e
, g
)
445 keys
:= tr
.IdleConnKeysForTesting()
446 if e
, g
:= 1, len(keys
); e
!= g
{
447 t
.Fatalf("after first response, expected %d idle conn cache keys; got %d", e
, g
)
449 addr
:= ts
.Listener
.Addr().String()
450 cacheKey
:= "|http|" + addr
451 if keys
[0] != cacheKey
{
452 t
.Fatalf("Expected idle cache key %q; got %q", cacheKey
, keys
[0])
454 if e
, g
:= 1, tr
.IdleConnCountForTesting("http", addr
); e
!= g
{
455 t
.Errorf("after first response, expected %d idle conns; got %d", e
, g
)
460 if g
, w
:= tr
.IdleConnCountForTesting("http", addr
), 2; g
!= w
{
461 t
.Errorf("after second response, idle conns = %d; want %d", g
, w
)
466 if g
, w
:= tr
.IdleConnCountForTesting("http", addr
), maxIdleConnsPerHost
; g
!= w
{
467 t
.Errorf("after third response, idle conns = %d; want %d", g
, w
)
471 func TestTransportMaxConnsPerHostIncludeDialInProgress(t
*testing
.T
) {
473 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
474 _
, err
:= w
.Write([]byte("foo"))
476 t
.Fatalf("Write: %v", err
)
481 tr
:= c
.Transport
.(*Transport
)
482 dialStarted
:= make(chan struct{})
483 stallDial
:= make(chan struct{})
484 tr
.Dial
= func(network
, addr
string) (net
.Conn
, error
) {
485 dialStarted
<- struct{}{}
487 return net
.Dial(network
, addr
)
490 tr
.DisableKeepAlives
= true
491 tr
.MaxConnsPerHost
= 1
493 preDial
:= make(chan struct{})
494 reqComplete
:= make(chan struct{})
495 doReq
:= func(reqId
string) {
496 req
, _
:= NewRequest("GET", ts
.URL
, nil)
497 trace
:= &httptrace
.ClientTrace
{
498 GetConn
: func(hostPort
string) {
499 preDial
<- struct{}{}
502 req
= req
.WithContext(httptrace
.WithClientTrace(req
.Context(), trace
))
503 resp
, err
:= tr
.RoundTrip(req
)
505 t
.Errorf("unexpected error for request %s: %v", reqId
, err
)
507 _
, err
= ioutil
.ReadAll(resp
.Body
)
509 t
.Errorf("unexpected error for request %s: %v", reqId
, err
)
511 reqComplete
<- struct{}{}
513 // get req1 to dial-in-progress
518 // get req2 to waiting on conns per host to go down below max
523 t
.Error("req2 dial started while req1 dial in progress")
529 stallDial
<- struct{}{}
534 stallDial
<- struct{}{}
538 func TestTransportRemovesDeadIdleConnections(t
*testing
.T
) {
541 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
542 io
.WriteString(w
, r
.RemoteAddr
)
547 tr
:= c
.Transport
.(*Transport
)
549 doReq
:= func(name
string) string {
550 // Do a POST instead of a GET to prevent the Transport's
551 // idempotent request retry logic from kicking in...
552 res
, err
:= c
.Post(ts
.URL
, "", nil)
554 t
.Fatalf("%s: %v", name
, err
)
556 if res
.StatusCode
!= 200 {
557 t
.Fatalf("%s: %v", name
, res
.Status
)
559 defer res
.Body
.Close()
560 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
562 t
.Fatalf("%s: %v", name
, err
)
567 first
:= doReq("first")
568 keys1
:= tr
.IdleConnKeysForTesting()
570 ts
.CloseClientConnections()
573 if !waitCondition(3*time
.Second
, 50*time
.Millisecond
, func() bool {
574 keys2
= tr
.IdleConnKeysForTesting()
575 return len(keys2
) == 0
577 t
.Fatalf("Transport didn't notice idle connection's death.\nbefore: %q\n after: %q\n", keys1
, keys2
)
580 second
:= doReq("second")
582 t
.Errorf("expected a different connection between requests. got %q both times", first
)
586 func TestTransportServerClosingUnexpectedly(t
*testing
.T
) {
589 ts
:= httptest
.NewServer(hostPortHandler
)
593 fetch
:= func(n
, retries
int) string {
594 condFatalf
:= func(format
string, arg
...interface{}) {
596 t
.Fatalf(format
, arg
...)
598 t
.Logf("retrying shortly after expected error: "+format
, arg
...)
599 time
.Sleep(time
.Second
/ time
.Duration(retries
))
603 res
, err
:= c
.Get(ts
.URL
)
605 condFatalf("error in req #%d, GET: %v", n
, err
)
608 body
, err
:= ioutil
.ReadAll(res
.Body
)
610 condFatalf("error in req #%d, ReadAll: %v", n
, err
)
622 ts
.CloseClientConnections() // surprise!
624 // This test has an expected race. Sleeping for 25 ms prevents
625 // it on most fast machines, causing the next fetch() call to
626 // succeed quickly. But if we do get errors, fetch() will retry 5
627 // times with some delays between.
628 time
.Sleep(25 * time
.Millisecond
)
633 t
.Errorf("expected body1 and body2 to be equal")
636 t
.Errorf("expected body2 and body3 to be different")
640 // Test for https://golang.org/issue/2616 (appropriate issue number)
641 // This fails pretty reliably with GOMAXPROCS=100 or something high.
642 func TestStressSurpriseServerCloses(t
*testing
.T
) {
645 t
.Skip("skipping test in short mode")
647 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
648 w
.Header().Set("Content-Length", "5")
649 w
.Header().Set("Content-Type", "text/plain")
650 w
.Write([]byte("Hello"))
652 conn
, buf
, _
:= w
.(Hijacker
).Hijack()
659 // Do a bunch of traffic from different goroutines. Send to activityc
660 // after each request completes, regardless of whether it failed.
661 // If these are too high, OS X exhausts its ephemeral ports
662 // and hangs waiting for them to transition TCP states. That's
663 // not what we want to test. TODO(bradfitz): use an io.Pipe
664 // dialer for this test instead?
669 activityc
:= make(chan bool)
670 for i
:= 0; i
< numClients
; i
++ {
672 for i
:= 0; i
< reqsPerClient
; i
++ {
673 res
, err
:= c
.Get(ts
.URL
)
675 // We expect errors since the server is
676 // hanging up on us after telling us to
677 // send more requests, so we don't
678 // actually care what the error is.
679 // But we want to close the body in cases
680 // where we won the race.
688 // Make sure all the request come back, one way or another.
689 for i
:= 0; i
< numClients
*reqsPerClient
; i
++ {
692 case <-time
.After(5 * time
.Second
):
693 t
.Fatalf("presumed deadlock; no HTTP client activity seen in awhile")
698 // TestTransportHeadResponses verifies that we deal with Content-Lengths
699 // with no bodies properly
700 func TestTransportHeadResponses(t
*testing
.T
) {
702 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
703 if r
.Method
!= "HEAD" {
704 panic("expected HEAD; got " + r
.Method
)
706 w
.Header().Set("Content-Length", "123")
712 for i
:= 0; i
< 2; i
++ {
713 res
, err
:= c
.Head(ts
.URL
)
715 t
.Errorf("error on loop %d: %v", i
, err
)
718 if e
, g
:= "123", res
.Header
.Get("Content-Length"); e
!= g
{
719 t
.Errorf("loop %d: expected Content-Length header of %q, got %q", i
, e
, g
)
721 if e
, g
:= int64(123), res
.ContentLength
; e
!= g
{
722 t
.Errorf("loop %d: expected res.ContentLength of %v, got %v", i
, e
, g
)
724 if all
, err
:= ioutil
.ReadAll(res
.Body
); err
!= nil {
725 t
.Errorf("loop %d: Body ReadAll: %v", i
, err
)
726 } else if len(all
) != 0 {
727 t
.Errorf("Bogus body %q", all
)
732 // TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
733 // on responses to HEAD requests.
734 func TestTransportHeadChunkedResponse(t
*testing
.T
) {
736 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
737 if r
.Method
!= "HEAD" {
738 panic("expected HEAD; got " + r
.Method
)
740 w
.Header().Set("Transfer-Encoding", "chunked") // client should ignore
741 w
.Header().Set("x-client-ipport", r
.RemoteAddr
)
747 // Ensure that we wait for the readLoop to complete before
748 // calling Head again
749 didRead
:= make(chan bool)
750 SetReadLoopBeforeNextReadHook(func() { didRead
<- true })
751 defer SetReadLoopBeforeNextReadHook(nil)
753 res1
, err
:= c
.Head(ts
.URL
)
757 t
.Fatalf("request 1 error: %v", err
)
760 res2
, err
:= c
.Head(ts
.URL
)
764 t
.Fatalf("request 2 error: %v", err
)
766 if v1
, v2
:= res1
.Header
.Get("x-client-ipport"), res2
.Header
.Get("x-client-ipport"); v1
!= v2
{
767 t
.Errorf("ip/ports differed between head requests: %q vs %q", v1
, v2
)
771 var roundTripTests
= []struct {
776 // Requests with no accept-encoding header use transparent compression
778 // Requests with other accept-encoding should pass through unmodified
779 {"foo", "foo", false},
780 // Requests with accept-encoding == gzip should be passed through
781 {"gzip", "gzip", true},
784 // Test that the modification made to the Request by the RoundTripper is cleaned up
785 func TestRoundTripGzip(t
*testing
.T
) {
788 const responseBody
= "test response body"
789 ts
:= httptest
.NewServer(HandlerFunc(func(rw ResponseWriter
, req
*Request
) {
790 accept
:= req
.Header
.Get("Accept-Encoding")
791 if expect
:= req
.FormValue("expect_accept"); accept
!= expect
{
792 t
.Errorf("in handler, test %v: Accept-Encoding = %q, want %q",
793 req
.FormValue("testnum"), accept
, expect
)
795 if accept
== "gzip" {
796 rw
.Header().Set("Content-Encoding", "gzip")
797 gz
:= gzip
.NewWriter(rw
)
798 gz
.Write([]byte(responseBody
))
801 rw
.Header().Set("Content-Encoding", accept
)
802 rw
.Write([]byte(responseBody
))
806 tr
:= ts
.Client().Transport
.(*Transport
)
808 for i
, test
:= range roundTripTests
{
809 // Test basic request (no accept-encoding)
810 req
, _
:= NewRequest("GET", fmt
.Sprintf("%s/?testnum=%d&expect_accept=%s", ts
.URL
, i
, test
.expectAccept
), nil)
811 if test
.accept
!= "" {
812 req
.Header
.Set("Accept-Encoding", test
.accept
)
814 res
, err
:= tr
.RoundTrip(req
)
818 r
, err
= gzip
.NewReader(res
.Body
)
820 t
.Errorf("%d. gzip NewReader: %v", i
, err
)
823 body
, err
= ioutil
.ReadAll(r
)
826 body
, err
= ioutil
.ReadAll(res
.Body
)
829 t
.Errorf("%d. Error: %q", i
, err
)
832 if g
, e
:= string(body
), responseBody
; g
!= e
{
833 t
.Errorf("%d. body = %q; want %q", i
, g
, e
)
835 if g
, e
:= req
.Header
.Get("Accept-Encoding"), test
.accept
; g
!= e
{
836 t
.Errorf("%d. Accept-Encoding = %q; want %q (it was mutated, in violation of RoundTrip contract)", i
, g
, e
)
838 if g
, e
:= res
.Header
.Get("Content-Encoding"), test
.accept
; g
!= e
{
839 t
.Errorf("%d. Content-Encoding = %q; want %q", i
, g
, e
)
845 func TestTransportGzip(t
*testing
.T
) {
848 const testString
= "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
849 const nRandBytes
= 1024 * 1024
850 ts
:= httptest
.NewServer(HandlerFunc(func(rw ResponseWriter
, req
*Request
) {
851 if req
.Method
== "HEAD" {
852 if g
:= req
.Header
.Get("Accept-Encoding"); g
!= "" {
853 t
.Errorf("HEAD request sent with Accept-Encoding of %q; want none", g
)
857 if g
, e
:= req
.Header
.Get("Accept-Encoding"), "gzip"; g
!= e
{
858 t
.Errorf("Accept-Encoding = %q, want %q", g
, e
)
860 rw
.Header().Set("Content-Encoding", "gzip")
864 if req
.FormValue("chunked") == "0" {
866 defer io
.Copy(rw
, &buf
)
868 rw
.Header().Set("Content-Length", strconv
.Itoa(buf
.Len()))
871 gz
:= gzip
.NewWriter(w
)
872 gz
.Write([]byte(testString
))
873 if req
.FormValue("body") == "large" {
874 io
.CopyN(gz
, rand
.Reader
, nRandBytes
)
881 for _
, chunked
:= range []string{"1", "0"} {
882 // First fetch something large, but only read some of it.
883 res
, err
:= c
.Get(ts
.URL
+ "/?body=large&chunked=" + chunked
)
885 t
.Fatalf("large get: %v", err
)
887 buf
:= make([]byte, len(testString
))
888 n
, err
:= io
.ReadFull(res
.Body
, buf
)
890 t
.Fatalf("partial read of large response: size=%d, %v", n
, err
)
892 if e
, g
:= testString
, string(buf
); e
!= g
{
893 t
.Errorf("partial read got %q, expected %q", g
, e
)
896 // Read on the body, even though it's closed
897 n
, err
= res
.Body
.Read(buf
)
898 if n
!= 0 || err
== nil {
899 t
.Errorf("expected error post-closed large Read; got = %d, %v", n
, err
)
902 // Then something small.
903 res
, err
= c
.Get(ts
.URL
+ "/?chunked=" + chunked
)
907 body
, err
:= ioutil
.ReadAll(res
.Body
)
911 if g
, e
:= string(body
), testString
; g
!= e
{
912 t
.Fatalf("body = %q; want %q", g
, e
)
914 if g
, e
:= res
.Header
.Get("Content-Encoding"), ""; g
!= e
{
915 t
.Fatalf("Content-Encoding = %q; want %q", g
, e
)
918 // Read on the body after it's been fully read:
919 n
, err
= res
.Body
.Read(buf
)
920 if n
!= 0 || err
== nil {
921 t
.Errorf("expected Read error after exhausted reads; got %d, %v", n
, err
)
924 n
, err
= res
.Body
.Read(buf
)
925 if n
!= 0 || err
== nil {
926 t
.Errorf("expected Read error after Close; got %d, %v", n
, err
)
930 // And a HEAD request too, because they're always weird.
931 res
, err
:= c
.Head(ts
.URL
)
933 t
.Fatalf("Head: %v", err
)
935 if res
.StatusCode
!= 200 {
936 t
.Errorf("Head status=%d; want=200", res
.StatusCode
)
940 // If a request has Expect:100-continue header, the request blocks sending body until the first response.
941 // Premature consumption of the request body should not be occurred.
942 func TestTransportExpect100Continue(t
*testing
.T
) {
946 ts
:= httptest
.NewServer(HandlerFunc(func(rw ResponseWriter
, req
*Request
) {
947 switch req
.URL
.Path
{
949 // This endpoint implicitly responds 100 Continue and reads body.
950 if _
, err
:= io
.Copy(ioutil
.Discard
, req
.Body
); err
!= nil {
951 t
.Error("Failed to read Body", err
)
953 rw
.WriteHeader(StatusOK
)
955 // Go 1.5 adds Connection: close header if the client expect
956 // continue but not entire request body is consumed.
957 rw
.WriteHeader(StatusOK
)
959 rw
.WriteHeader(StatusInternalServerError
)
961 // This hijacked endpoint responds error without Connection:close.
962 _
, bufrw
, err
:= rw
.(Hijacker
).Hijack()
966 bufrw
.WriteString("HTTP/1.1 500 Internal Server Error\r\n")
967 bufrw
.WriteString("Content-Length: 0\r\n\r\n")
970 // This endpoint tries to read body without 100 (Continue) response.
971 // After ExpectContinueTimeout, the reading will be started.
972 conn
, bufrw
, err
:= rw
.(Hijacker
).Hijack()
976 if _
, err
:= io
.CopyN(ioutil
.Discard
, bufrw
, req
.ContentLength
); err
!= nil {
977 t
.Error("Failed to read Body", err
)
979 bufrw
.WriteString("HTTP/1.1 200 OK\r\n\r\n")
993 {path
: "/100", body
: []byte("hello"), sent
: 5, status
: 200}, // Got 100 followed by 200, entire body is sent.
994 {path
: "/200", body
: []byte("hello"), sent
: 0, status
: 200}, // Got 200 without 100. body isn't sent.
995 {path
: "/500", body
: []byte("hello"), sent
: 0, status
: 500}, // Got 500 without 100. body isn't sent.
996 {path
: "/keepalive", body
: []byte("hello"), sent
: 0, status
: 500}, // Although without Connection:close, body isn't sent.
997 {path
: "/timeout", body
: []byte("hello"), sent
: 5, status
: 200}, // Timeout exceeded and entire body is sent.
1001 for i
, v
:= range tests
{
1003 ExpectContinueTimeout
: 2 * time
.Second
,
1005 defer tr
.CloseIdleConnections()
1007 body
:= bytes
.NewReader(v
.body
)
1008 req
, err
:= NewRequest("PUT", ts
.URL
+v
.path
, body
)
1012 req
.Header
.Set("Expect", "100-continue")
1013 req
.ContentLength
= int64(len(v
.body
))
1015 resp
, err
:= c
.Do(req
)
1021 sent
:= len(v
.body
) - body
.Len()
1022 if v
.status
!= resp
.StatusCode
{
1023 t
.Errorf("test %d: status code should be %d but got %d. (%s)", i
, v
.status
, resp
.StatusCode
, v
.path
)
1026 t
.Errorf("test %d: sent body should be %d but sent %d. (%s)", i
, v
.sent
, sent
, v
.path
)
1031 func TestSOCKS5Proxy(t
*testing
.T
) {
1033 ch
:= make(chan string, 1)
1034 l
:= newLocalListener(t
)
1037 proxy
:= func(t
*testing
.T
) {
1038 s
, err
:= l
.Accept()
1040 t
.Errorf("socks5 proxy Accept(): %v", err
)
1045 if _
, err
:= io
.ReadFull(s
, buf
[:3]); err
!= nil {
1046 t
.Errorf("socks5 proxy initial read: %v", err
)
1049 if want
:= []byte{5, 1, 0}; !bytes
.Equal(buf
[:3], want
) {
1050 t
.Errorf("socks5 proxy initial read: got %v, want %v", buf
[:3], want
)
1053 if _
, err
:= s
.Write([]byte{5, 0}); err
!= nil {
1054 t
.Errorf("socks5 proxy initial write: %v", err
)
1057 if _
, err
:= io
.ReadFull(s
, buf
[:4]); err
!= nil {
1058 t
.Errorf("socks5 proxy second read: %v", err
)
1061 if want
:= []byte{5, 1, 0}; !bytes
.Equal(buf
[:3], want
) {
1062 t
.Errorf("socks5 proxy second read: got %v, want %v", buf
[:3], want
)
1072 t
.Errorf("socks5 proxy second read: unexpected address type %v", buf
[4])
1075 if _
, err
:= io
.ReadFull(s
, buf
[4:ipLen
+6]); err
!= nil {
1076 t
.Errorf("socks5 proxy address read: %v", err
)
1079 ip
:= net
.IP(buf
[4 : ipLen
+4])
1080 port
:= binary
.BigEndian
.Uint16(buf
[ipLen
+4 : ipLen
+6])
1081 copy(buf
[:3], []byte{5, 0, 0})
1082 if _
, err
:= s
.Write(buf
[:ipLen
+6]); err
!= nil {
1083 t
.Errorf("socks5 proxy connect write: %v", err
)
1086 ch
<- fmt
.Sprintf("proxy for %s:%d", ip
, port
)
1088 // Implement proxying.
1089 targetHost
:= net
.JoinHostPort(ip
.String(), strconv
.Itoa(int(port
)))
1090 targetConn
, err
:= net
.Dial("tcp", targetHost
)
1092 t
.Errorf("net.Dial failed")
1095 go io
.Copy(targetConn
, s
)
1096 io
.Copy(s
, targetConn
) // Wait for the client to close the socket.
1100 pu
, err
:= url
.Parse("socks5://" + l
.Addr().String())
1105 sentinelHeader
:= "X-Sentinel"
1106 sentinelValue
:= "12345"
1107 h
:= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1108 w
.Header().Set(sentinelHeader
, sentinelValue
)
1110 for _
, useTLS
:= range []bool{false, true} {
1111 t
.Run(fmt
.Sprintf("useTLS=%v", useTLS
), func(t
*testing
.T
) {
1112 var ts
*httptest
.Server
1114 ts
= httptest
.NewTLSServer(h
)
1116 ts
= httptest
.NewServer(h
)
1120 c
.Transport
.(*Transport
).Proxy
= ProxyURL(pu
)
1121 r
, err
:= c
.Head(ts
.URL
)
1125 if r
.Header
.Get(sentinelHeader
) != sentinelValue
{
1126 t
.Errorf("Failed to retrieve sentinel value")
1131 case <-time
.After(5 * time
.Second
):
1132 t
.Fatal("timeout connecting to socks5 proxy")
1135 tsu
, err
:= url
.Parse(ts
.URL
)
1139 want
:= "proxy for " + tsu
.Host
1141 t
.Errorf("got %q, want %q", got
, want
)
1147 func TestTransportProxy(t
*testing
.T
) {
1149 testCases
:= []struct{ httpsSite
, httpsProxy
bool }{
1155 for _
, testCase
:= range testCases
{
1156 httpsSite
:= testCase
.httpsSite
1157 httpsProxy
:= testCase
.httpsProxy
1158 t
.Run(fmt
.Sprintf("httpsSite=%v, httpsProxy=%v", httpsSite
, httpsProxy
), func(t
*testing
.T
) {
1159 siteCh
:= make(chan *Request
, 1)
1160 h1
:= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1163 proxyCh
:= make(chan *Request
, 1)
1164 h2
:= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1166 // Implement an entire CONNECT proxy
1167 if r
.Method
== "CONNECT" {
1168 hijacker
, ok
:= w
.(Hijacker
)
1170 t
.Errorf("hijack not allowed")
1173 clientConn
, _
, err
:= hijacker
.Hijack()
1175 t
.Errorf("hijacking failed")
1179 StatusCode
: StatusOK
,
1183 Header
: make(Header
),
1186 targetConn
, err
:= net
.Dial("tcp", r
.URL
.Host
)
1188 t
.Errorf("net.Dial(%q) failed: %v", r
.URL
.Host
, err
)
1192 if err
:= res
.Write(clientConn
); err
!= nil {
1193 t
.Errorf("Writing 200 OK failed: %v", err
)
1197 go io
.Copy(targetConn
, clientConn
)
1199 io
.Copy(clientConn
, targetConn
)
1204 var ts
*httptest
.Server
1206 ts
= httptest
.NewTLSServer(h1
)
1208 ts
= httptest
.NewServer(h1
)
1210 var proxy
*httptest
.Server
1212 proxy
= httptest
.NewTLSServer(h2
)
1214 proxy
= httptest
.NewServer(h2
)
1217 pu
, err
:= url
.Parse(proxy
.URL
)
1222 // If neither server is HTTPS or both are, then c may be derived from either.
1223 // If only one server is HTTPS, c must be derived from that server in order
1224 // to ensure that it is configured to use the fake root CA from testcert.go.
1230 c
.Transport
.(*Transport
).Proxy
= ProxyURL(pu
)
1231 if _
, err
:= c
.Head(ts
.URL
); err
!= nil {
1236 case got
= <-proxyCh
:
1237 case <-time
.After(5 * time
.Second
):
1238 t
.Fatal("timeout connecting to http proxy")
1240 c
.Transport
.(*Transport
).CloseIdleConnections()
1244 // First message should be a CONNECT, asking for a socket to the real server,
1245 if got
.Method
!= "CONNECT" {
1246 t
.Errorf("Wrong method for secure proxying: %q", got
.Method
)
1248 gotHost
:= got
.URL
.Host
1249 pu
, err
:= url
.Parse(ts
.URL
)
1251 t
.Fatal("Invalid site URL")
1253 if wantHost
:= pu
.Host
; gotHost
!= wantHost
{
1254 t
.Errorf("Got CONNECT host %q, want %q", gotHost
, wantHost
)
1257 // The next message on the channel should be from the site's server.
1259 if next
.Method
!= "HEAD" {
1260 t
.Errorf("Wrong method at destination: %s", next
.Method
)
1262 if nextURL
:= next
.URL
.String(); nextURL
!= "/" {
1263 t
.Errorf("Wrong URL at destination: %s", nextURL
)
1266 if got
.Method
!= "HEAD" {
1267 t
.Errorf("Wrong method for destination: %q", got
.Method
)
1269 gotURL
:= got
.URL
.String()
1270 wantURL
:= ts
.URL
+ "/"
1271 if gotURL
!= wantURL
{
1272 t
.Errorf("Got URL %q, want %q", gotURL
, wantURL
)
1279 // Issue 16997: test transport dial preserves typed errors
1280 func TestTransportDialPreservesNetOpProxyError(t
*testing
.T
) {
1283 var errDial
= errors
.New("some dial error")
1286 Proxy
: func(*Request
) (*url
.URL
, error
) {
1287 return url
.Parse("http://proxy.fake.tld/")
1289 Dial
: func(string, string) (net
.Conn
, error
) {
1293 defer tr
.CloseIdleConnections()
1295 c
:= &Client
{Transport
: tr
}
1296 req
, _
:= NewRequest("GET", "http://fake.tld", nil)
1297 res
, err
:= c
.Do(req
)
1300 t
.Fatal("wanted a non-nil error")
1303 uerr
, ok
:= err
.(*url
.Error
)
1305 t
.Fatalf("got %T, want *url.Error", err
)
1307 oe
, ok
:= uerr
.Err
.(*net
.OpError
)
1309 t
.Fatalf("url.Error.Err = %T; want *net.OpError", uerr
.Err
)
1311 want
:= &net
.OpError
{
1314 Err
: errDial
, // original error, unwrapped.
1316 if !reflect
.DeepEqual(oe
, want
) {
1317 t
.Errorf("Got error %#v; want %#v", oe
, want
)
1321 // TestTransportGzipRecursive sends a gzip quine and checks that the
1322 // client gets the same value back. This is more cute than anything,
1323 // but checks that we don't recurse forever, and checks that
1324 // Content-Encoding is removed.
1325 func TestTransportGzipRecursive(t
*testing
.T
) {
1327 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1328 w
.Header().Set("Content-Encoding", "gzip")
1334 res
, err
:= c
.Get(ts
.URL
)
1338 body
, err
:= ioutil
.ReadAll(res
.Body
)
1342 if !bytes
.Equal(body
, rgz
) {
1343 t
.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x",
1346 if g
, e
:= res
.Header
.Get("Content-Encoding"), ""; g
!= e
{
1347 t
.Fatalf("Content-Encoding = %q; want %q", g
, e
)
1351 // golang.org/issue/7750: request fails when server replies with
1352 // a short gzip body
1353 func TestTransportGzipShort(t
*testing
.T
) {
1355 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1356 w
.Header().Set("Content-Encoding", "gzip")
1357 w
.Write([]byte{0x1f, 0x8b})
1362 res
, err
:= c
.Get(ts
.URL
)
1366 defer res
.Body
.Close()
1367 _
, err
= ioutil
.ReadAll(res
.Body
)
1369 t
.Fatal("Expect an error from reading a body.")
1371 if err
!= io
.ErrUnexpectedEOF
{
1372 t
.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err
)
1376 // Wait until number of goroutines is no greater than nmax, or time out.
1377 func waitNumGoroutine(nmax
int) int {
1378 nfinal
:= runtime
.NumGoroutine()
1379 for ntries
:= 10; ntries
> 0 && nfinal
> nmax
; ntries
-- {
1380 time
.Sleep(50 * time
.Millisecond
)
1382 nfinal
= runtime
.NumGoroutine()
1387 // tests that persistent goroutine connections shut down when no longer desired.
1388 func TestTransportPersistConnLeak(t
*testing
.T
) {
1389 // Not parallel: counts goroutines
1393 gotReqCh
:= make(chan bool, numReq
)
1394 unblockCh
:= make(chan bool, numReq
)
1395 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1398 w
.Header().Set("Content-Length", "0")
1403 tr
:= c
.Transport
.(*Transport
)
1405 n0
:= runtime
.NumGoroutine()
1407 didReqCh
:= make(chan bool, numReq
)
1408 failed
:= make(chan bool, numReq
)
1409 for i
:= 0; i
< numReq
; i
++ {
1411 res
, err
:= c
.Get(ts
.URL
)
1414 t
.Errorf("client fetch error: %v", err
)
1422 // Wait for all goroutines to be stuck in the Handler.
1423 for i
:= 0; i
< numReq
; i
++ {
1433 nhigh
:= runtime
.NumGoroutine()
1435 // Tell all handlers to unblock and reply.
1436 for i
:= 0; i
< numReq
; i
++ {
1440 // Wait for all HTTP clients to be done.
1441 for i
:= 0; i
< numReq
; i
++ {
1445 tr
.CloseIdleConnections()
1446 nfinal
:= waitNumGoroutine(n0
+ 5)
1448 growth
:= nfinal
- n0
1450 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
1451 // Previously we were leaking one per numReq.
1452 if int(growth
) > 5 {
1453 t
.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0
, nhigh
, nfinal
, growth
)
1454 t
.Error("too many new goroutines")
1458 // golang.org/issue/4531: Transport leaks goroutines when
1459 // request.ContentLength is explicitly short
1460 func TestTransportPersistConnLeakShortBody(t
*testing
.T
) {
1461 // Not parallel: measures goroutines.
1463 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1467 tr
:= c
.Transport
.(*Transport
)
1469 n0
:= runtime
.NumGoroutine()
1470 body
:= []byte("Hello")
1471 for i
:= 0; i
< 20; i
++ {
1472 req
, err
:= NewRequest("POST", ts
.URL
, bytes
.NewReader(body
))
1476 req
.ContentLength
= int64(len(body
) - 2) // explicitly short
1479 t
.Fatal("Expect an error from writing too long of a body.")
1482 nhigh
:= runtime
.NumGoroutine()
1483 tr
.CloseIdleConnections()
1484 nfinal
:= waitNumGoroutine(n0
+ 5)
1486 growth
:= nfinal
- n0
1488 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
1489 // Previously we were leaking one per numReq.
1490 t
.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0
, nhigh
, nfinal
, growth
)
1491 if int(growth
) > 5 {
1492 t
.Error("too many new goroutines")
1496 // This used to crash; https://golang.org/issue/3266
1497 func TestTransportIdleConnCrash(t
*testing
.T
) {
1501 unblockCh
:= make(chan bool, 1)
1502 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1504 tr
.CloseIdleConnections()
1508 tr
= c
.Transport
.(*Transport
)
1510 didreq
:= make(chan bool)
1512 res
, err
:= c
.Get(ts
.URL
)
1516 res
.Body
.Close() // returns idle conn
1524 // Test that the transport doesn't close the TCP connection early,
1525 // before the response body has been read. This was a regression
1526 // which sadly lacked a triggering test. The large response body made
1527 // the old race easier to trigger.
1528 func TestIssue3644(t
*testing
.T
) {
1530 const numFoos
= 5000
1531 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1532 w
.Header().Set("Connection", "close")
1533 for i
:= 0; i
< numFoos
; i
++ {
1534 w
.Write([]byte("foo "))
1539 res
, err
:= c
.Get(ts
.URL
)
1543 defer res
.Body
.Close()
1544 bs
, err
:= ioutil
.ReadAll(res
.Body
)
1548 if len(bs
) != numFoos
*len("foo ") {
1549 t
.Errorf("unexpected response length")
1553 // Test that a client receives a server's reply, even if the server doesn't read
1554 // the entire request body.
1555 func TestIssue3595(t
*testing
.T
) {
1558 const deniedMsg
= "sorry, denied."
1559 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1560 Error(w
, deniedMsg
, StatusUnauthorized
)
1564 res
, err
:= c
.Post(ts
.URL
, "application/octet-stream", neverEnding('a'))
1566 t
.Errorf("Post: %v", err
)
1569 got
, err
:= ioutil
.ReadAll(res
.Body
)
1571 t
.Fatalf("Body ReadAll: %v", err
)
1573 if !strings
.Contains(string(got
), deniedMsg
) {
1574 t
.Errorf("Known bug: response %q does not contain %q", got
, deniedMsg
)
1578 // From https://golang.org/issue/4454 ,
1579 // "client fails to handle requests with no body and chunked encoding"
1580 func TestChunkedNoContent(t
*testing
.T
) {
1582 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1583 w
.WriteHeader(StatusNoContent
)
1588 for _
, closeBody
:= range []bool{true, false} {
1590 for i
:= 1; i
<= n
; i
++ {
1591 res
, err
:= c
.Get(ts
.URL
)
1593 t
.Errorf("closingBody=%v, req %d/%d: %v", closeBody
, i
, n
, err
)
1603 func TestTransportConcurrency(t
*testing
.T
) {
1604 // Not parallel: uses global test hooks.
1606 maxProcs
, numReqs
:= 16, 500
1607 if testing
.Short() {
1608 maxProcs
, numReqs
= 4, 50
1610 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(maxProcs
))
1611 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1612 fmt
.Fprintf(w
, "%v", r
.FormValue("echo"))
1616 var wg sync
.WaitGroup
1619 // Due to the Transport's "socket late binding" (see
1620 // idleConnCh in transport.go), the numReqs HTTP requests
1621 // below can finish with a dial still outstanding. To keep
1622 // the leak checker happy, keep track of pending dials and
1623 // wait for them to finish (and be closed or returned to the
1624 // idle pool) before we close idle connections.
1625 SetPendingDialHooks(func() { wg
.Add(1) }, wg
.Done
)
1626 defer SetPendingDialHooks(nil, nil)
1629 reqs
:= make(chan string)
1632 for i
:= 0; i
< maxProcs
*2; i
++ {
1634 for req
:= range reqs
{
1635 res
, err
:= c
.Get(ts
.URL
+ "/?echo=" + req
)
1637 t
.Errorf("error on req %s: %v", req
, err
)
1641 all
, err
:= ioutil
.ReadAll(res
.Body
)
1643 t
.Errorf("read error on req %s: %v", req
, err
)
1647 if string(all
) != req
{
1648 t
.Errorf("body of req %s = %q; want %q", req
, all
, req
)
1655 for i
:= 0; i
< numReqs
; i
++ {
1656 reqs
<- fmt
.Sprintf("request-%d", i
)
1661 func TestIssue4191_InfiniteGetTimeout(t
*testing
.T
) {
1665 mux
:= NewServeMux()
1666 mux
.HandleFunc("/get", func(w ResponseWriter
, r
*Request
) {
1667 io
.Copy(w
, neverEnding('a'))
1669 ts
:= httptest
.NewServer(mux
)
1671 timeout
:= 100 * time
.Millisecond
1674 c
.Transport
.(*Transport
).Dial
= func(n
, addr
string) (net
.Conn
, error
) {
1675 conn
, err
:= net
.Dial(n
, addr
)
1679 conn
.SetDeadline(time
.Now().Add(timeout
))
1681 conn
= NewLoggingConn("client", conn
)
1688 if testing
.Short() {
1691 for i
:= 0; i
< nRuns
; i
++ {
1693 println("run", i
+1, "of", nRuns
)
1695 sres
, err
:= c
.Get(ts
.URL
+ "/get")
1698 // Make the timeout longer, once.
1700 t
.Logf("increasing timeout")
1705 t
.Errorf("Error issuing GET: %v", err
)
1708 _
, err
= io
.Copy(ioutil
.Discard
, sres
.Body
)
1710 t
.Errorf("Unexpected successful copy")
1715 println("tests complete; waiting for handlers to finish")
1719 func TestIssue4191_InfiniteGetToPutTimeout(t
*testing
.T
) {
1723 mux
:= NewServeMux()
1724 mux
.HandleFunc("/get", func(w ResponseWriter
, r
*Request
) {
1725 io
.Copy(w
, neverEnding('a'))
1727 mux
.HandleFunc("/put", func(w ResponseWriter
, r
*Request
) {
1728 defer r
.Body
.Close()
1729 io
.Copy(ioutil
.Discard
, r
.Body
)
1731 ts
:= httptest
.NewServer(mux
)
1732 timeout
:= 100 * time
.Millisecond
1735 c
.Transport
.(*Transport
).Dial
= func(n
, addr
string) (net
.Conn
, error
) {
1736 conn
, err
:= net
.Dial(n
, addr
)
1740 conn
.SetDeadline(time
.Now().Add(timeout
))
1742 conn
= NewLoggingConn("client", conn
)
1749 if testing
.Short() {
1752 for i
:= 0; i
< nRuns
; i
++ {
1754 println("run", i
+1, "of", nRuns
)
1756 sres
, err
:= c
.Get(ts
.URL
+ "/get")
1759 // Make the timeout longer, once.
1761 t
.Logf("increasing timeout")
1766 t
.Errorf("Error issuing GET: %v", err
)
1769 req
, _
:= NewRequest("PUT", ts
.URL
+"/put", sres
.Body
)
1773 t
.Errorf("Unexpected successful PUT")
1779 println("tests complete; waiting for handlers to finish")
1784 func TestTransportResponseHeaderTimeout(t
*testing
.T
) {
1787 if testing
.Short() {
1788 t
.Skip("skipping timeout test in -short mode")
1790 inHandler
:= make(chan bool, 1)
1791 mux
:= NewServeMux()
1792 mux
.HandleFunc("/fast", func(w ResponseWriter
, r
*Request
) {
1795 mux
.HandleFunc("/slow", func(w ResponseWriter
, r
*Request
) {
1797 time
.Sleep(2 * time
.Second
)
1799 ts
:= httptest
.NewServer(mux
)
1803 c
.Transport
.(*Transport
).ResponseHeaderTimeout
= 500 * time
.Millisecond
1810 {path
: "/fast", want
: 200},
1811 {path
: "/slow", wantErr
: "timeout awaiting response headers"},
1812 {path
: "/fast", want
: 200},
1814 for i
, tt
:= range tests
{
1815 req
, _
:= NewRequest("GET", ts
.URL
+tt
.path
, nil)
1817 res
, err
:= c
.Do(req
)
1820 case <-time
.After(5 * time
.Second
):
1821 t
.Errorf("never entered handler for test index %d, %s", i
, tt
.path
)
1825 uerr
, ok
:= err
.(*url
.Error
)
1827 t
.Errorf("error is not an url.Error; got: %#v", err
)
1830 nerr
, ok
:= uerr
.Err
.(net
.Error
)
1832 t
.Errorf("error does not satisfy net.Error interface; got: %#v", err
)
1835 if !nerr
.Timeout() {
1836 t
.Errorf("want timeout error; got: %q", nerr
)
1839 if strings
.Contains(err
.Error(), tt
.wantErr
) {
1842 t
.Errorf("%d. unexpected error: %v", i
, err
)
1845 if tt
.wantErr
!= "" {
1846 t
.Errorf("%d. no error. expected error: %v", i
, tt
.wantErr
)
1849 if res
.StatusCode
!= tt
.want
{
1850 t
.Errorf("%d for path %q status = %d; want %d", i
, tt
.path
, res
.StatusCode
, tt
.want
)
1855 func TestTransportCancelRequest(t
*testing
.T
) {
1858 if testing
.Short() {
1859 t
.Skip("skipping test in -short mode")
1861 unblockc
:= make(chan bool)
1862 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1863 fmt
.Fprintf(w
, "Hello")
1864 w
.(Flusher
).Flush() // send headers and some body
1868 defer close(unblockc
)
1871 tr
:= c
.Transport
.(*Transport
)
1873 req
, _
:= NewRequest("GET", ts
.URL
, nil)
1874 res
, err
:= c
.Do(req
)
1879 time
.Sleep(1 * time
.Second
)
1880 tr
.CancelRequest(req
)
1883 body
, err
:= ioutil
.ReadAll(res
.Body
)
1886 if err
!= ExportErrRequestCanceled
{
1887 t
.Errorf("Body.Read error = %v; want errRequestCanceled", err
)
1889 if string(body
) != "Hello" {
1890 t
.Errorf("Body = %q; want Hello", body
)
1892 if d
< 500*time
.Millisecond
{
1893 t
.Errorf("expected ~1 second delay; got %v", d
)
1895 // Verify no outstanding requests after readLoop/writeLoop
1896 // goroutines shut down.
1897 for tries
:= 5; tries
> 0; tries
-- {
1898 n
:= tr
.NumPendingRequestsForTesting()
1902 time
.Sleep(100 * time
.Millisecond
)
1904 t
.Errorf("pending requests = %d; want 0", n
)
1909 func TestTransportCancelRequestInDial(t
*testing
.T
) {
1911 if testing
.Short() {
1912 t
.Skip("skipping test in -short mode")
1914 var logbuf bytes
.Buffer
1915 eventLog
:= log
.New(&logbuf
, "", 0)
1917 unblockDial
:= make(chan bool)
1918 defer close(unblockDial
)
1920 inDial
:= make(chan bool)
1922 Dial
: func(network
, addr
string) (net
.Conn
, error
) {
1923 eventLog
.Println("dial: blocking")
1926 return nil, errors
.New("nope")
1929 cl
:= &Client
{Transport
: tr
}
1930 gotres
:= make(chan bool)
1931 req
, _
:= NewRequest("GET", "http://something.no-network.tld/", nil)
1933 _
, err
:= cl
.Do(req
)
1934 eventLog
.Printf("Get = %v", err
)
1940 case <-time
.After(5 * time
.Second
):
1941 t
.Fatal("timeout; never saw blocking dial")
1944 eventLog
.Printf("canceling")
1945 tr
.CancelRequest(req
)
1946 tr
.CancelRequest(req
) // used to panic on second call
1950 case <-time
.After(5 * time
.Second
):
1951 panic("hang. events are: " + logbuf
.String())
1954 got
:= logbuf
.String()
1955 want
:= `dial: blocking
1957 Get = Get http://something.no-network.tld/: net/http: request canceled while waiting for connection
1960 t
.Errorf("Got events:\n%s\nWant:\n%s", got
, want
)
1964 func TestCancelRequestWithChannel(t
*testing
.T
) {
1967 if testing
.Short() {
1968 t
.Skip("skipping test in -short mode")
1970 unblockc
:= make(chan bool)
1971 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1972 fmt
.Fprintf(w
, "Hello")
1973 w
.(Flusher
).Flush() // send headers and some body
1977 defer close(unblockc
)
1980 tr
:= c
.Transport
.(*Transport
)
1982 req
, _
:= NewRequest("GET", ts
.URL
, nil)
1983 ch
:= make(chan struct{})
1986 res
, err
:= c
.Do(req
)
1991 time
.Sleep(1 * time
.Second
)
1995 body
, err
:= ioutil
.ReadAll(res
.Body
)
1998 if err
!= ExportErrRequestCanceled
{
1999 t
.Errorf("Body.Read error = %v; want errRequestCanceled", err
)
2001 if string(body
) != "Hello" {
2002 t
.Errorf("Body = %q; want Hello", body
)
2004 if d
< 500*time
.Millisecond
{
2005 t
.Errorf("expected ~1 second delay; got %v", d
)
2007 // Verify no outstanding requests after readLoop/writeLoop
2008 // goroutines shut down.
2009 for tries
:= 5; tries
> 0; tries
-- {
2010 n
:= tr
.NumPendingRequestsForTesting()
2014 time
.Sleep(100 * time
.Millisecond
)
2016 t
.Errorf("pending requests = %d; want 0", n
)
2021 func TestCancelRequestWithChannelBeforeDo_Cancel(t
*testing
.T
) {
2022 testCancelRequestWithChannelBeforeDo(t
, false)
2024 func TestCancelRequestWithChannelBeforeDo_Context(t
*testing
.T
) {
2025 testCancelRequestWithChannelBeforeDo(t
, true)
2027 func testCancelRequestWithChannelBeforeDo(t
*testing
.T
, withCtx
bool) {
2030 unblockc
:= make(chan bool)
2031 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2035 defer close(unblockc
)
2039 req
, _
:= NewRequest("GET", ts
.URL
, nil)
2041 ctx
, cancel
:= context
.WithCancel(context
.Background())
2043 req
= req
.WithContext(ctx
)
2045 ch
:= make(chan struct{})
2051 if ue
, ok
:= err
.(*url
.Error
); ok
{
2055 if err
!= context
.Canceled
{
2056 t
.Errorf("Do error = %v; want %v", err
, context
.Canceled
)
2059 if err
== nil ||
!strings
.Contains(err
.Error(), "canceled") {
2060 t
.Errorf("Do error = %v; want cancelation", err
)
2065 // Issue 11020. The returned error message should be errRequestCanceled
2066 func TestTransportCancelBeforeResponseHeaders(t
*testing
.T
) {
2069 serverConnCh
:= make(chan net
.Conn
, 1)
2071 Dial
: func(network
, addr
string) (net
.Conn
, error
) {
2072 cc
, sc
:= net
.Pipe()
2077 defer tr
.CloseIdleConnections()
2078 errc
:= make(chan error
, 1)
2079 req
, _
:= NewRequest("GET", "http://example.com/", nil)
2081 _
, err
:= tr
.RoundTrip(req
)
2085 sc
:= <-serverConnCh
2086 verb
:= make([]byte, 3)
2087 if _
, err
:= io
.ReadFull(sc
, verb
); err
!= nil {
2088 t
.Errorf("Error reading HTTP verb from server: %v", err
)
2090 if string(verb
) != "GET" {
2091 t
.Errorf("server received %q; want GET", verb
)
2095 tr
.CancelRequest(req
)
2099 t
.Fatalf("unexpected success from RoundTrip")
2101 if err
!= ExportErrRequestCanceled
{
2102 t
.Errorf("RoundTrip error = %v; want ExportErrRequestCanceled", err
)
2106 // golang.org/issue/3672 -- Client can't close HTTP stream
2107 // Calling Close on a Response.Body used to just read until EOF.
2108 // Now it actually closes the TCP connection.
2109 func TestTransportCloseResponseBody(t
*testing
.T
) {
2111 writeErr
:= make(chan error
, 1)
2112 msg
:= []byte("young\n")
2113 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2115 _
, err
:= w
.Write(msg
)
2126 tr
:= c
.Transport
.(*Transport
)
2128 req
, _
:= NewRequest("GET", ts
.URL
, nil)
2129 defer tr
.CancelRequest(req
)
2131 res
, err
:= c
.Do(req
)
2137 buf
:= make([]byte, len(msg
)*repeats
)
2138 want
:= bytes
.Repeat(msg
, repeats
)
2140 _
, err
= io
.ReadFull(res
.Body
, buf
)
2144 if !bytes
.Equal(buf
, want
) {
2145 t
.Fatalf("read %q; want %q", buf
, want
)
2147 didClose
:= make(chan error
, 1)
2149 didClose
<- res
.Body
.Close()
2152 case err
:= <-didClose
:
2154 t
.Errorf("Close = %v", err
)
2156 case <-time
.After(10 * time
.Second
):
2157 t
.Fatal("too long waiting for close")
2160 case err
:= <-writeErr
:
2162 t
.Errorf("expected non-nil write error")
2164 case <-time
.After(10 * time
.Second
):
2165 t
.Fatal("too long waiting for write error")
2169 type fooProto
struct{}
2171 func (fooProto
) RoundTrip(req
*Request
) (*Response
, error
) {
2175 Header
: make(Header
),
2176 Body
: ioutil
.NopCloser(strings
.NewReader("You wanted " + req
.URL
.String())),
2181 func TestTransportAltProto(t
*testing
.T
) {
2184 c
:= &Client
{Transport
: tr
}
2185 tr
.RegisterProtocol("foo", fooProto
{})
2186 res
, err
:= c
.Get("foo://bar.com/path")
2190 bodyb
, err
:= ioutil
.ReadAll(res
.Body
)
2194 body
:= string(bodyb
)
2195 if e
:= "You wanted foo://bar.com/path"; body
!= e
{
2196 t
.Errorf("got response %q, want %q", body
, e
)
2200 func TestTransportNoHost(t
*testing
.T
) {
2203 _
, err
:= tr
.RoundTrip(&Request
{
2204 Header
: make(Header
),
2209 want
:= "http: no Host in request URL"
2210 if got
:= fmt
.Sprint(err
); got
!= want
{
2211 t
.Errorf("error = %v; want %q", err
, want
)
2216 func TestTransportEmptyMethod(t
*testing
.T
) {
2217 req
, _
:= NewRequest("GET", "http://foo.com/", nil)
2218 req
.Method
= "" // docs say "For client requests an empty string means GET"
2219 got
, err
:= httputil
.DumpRequestOut(req
, false) // DumpRequestOut uses Transport
2223 if !strings
.Contains(string(got
), "GET ") {
2224 t
.Fatalf("expected substring 'GET '; got: %s", got
)
2228 func TestTransportSocketLateBinding(t
*testing
.T
) {
2232 mux
:= NewServeMux()
2233 fooGate
:= make(chan bool, 1)
2234 mux
.HandleFunc("/foo", func(w ResponseWriter
, r
*Request
) {
2235 w
.Header().Set("foo-ipport", r
.RemoteAddr
)
2239 mux
.HandleFunc("/bar", func(w ResponseWriter
, r
*Request
) {
2240 w
.Header().Set("bar-ipport", r
.RemoteAddr
)
2242 ts
:= httptest
.NewServer(mux
)
2245 dialGate
:= make(chan bool, 1)
2247 c
.Transport
.(*Transport
).Dial
= func(n
, addr
string) (net
.Conn
, error
) {
2249 return net
.Dial(n
, addr
)
2251 return nil, errors
.New("manually closed")
2254 dialGate
<- true // only allow one dial
2255 fooRes
, err
:= c
.Get(ts
.URL
+ "/foo")
2259 fooAddr
:= fooRes
.Header
.Get("foo-ipport")
2261 t
.Fatal("No addr on /foo request")
2263 time
.AfterFunc(200*time
.Millisecond
, func() {
2264 // let the foo response finish so we can use its
2265 // connection for /bar
2267 io
.Copy(ioutil
.Discard
, fooRes
.Body
)
2271 barRes
, err
:= c
.Get(ts
.URL
+ "/bar")
2275 barAddr
:= barRes
.Header
.Get("bar-ipport")
2276 if barAddr
!= fooAddr
{
2277 t
.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr
, barAddr
)
2284 func TestTransportReading100Continue(t
*testing
.T
) {
2288 reqBody
:= func(n
int) string { return fmt
.Sprintf("request body %d", n
) }
2289 reqID
:= func(n
int) string { return fmt
.Sprintf("REQ-ID-%d", n
) }
2291 send100Response
:= func(w
*io
.PipeWriter
, r
*io
.PipeReader
) {
2294 br
:= bufio
.NewReader(r
)
2298 req
, err
:= ReadRequest(br
)
2306 slurp
, err
:= ioutil
.ReadAll(req
.Body
)
2308 t
.Errorf("Server request body slurp: %v", err
)
2311 id
:= req
.Header
.Get("Request-Id")
2312 resCode
:= req
.Header
.Get("X-Want-Response-Code")
2314 resCode
= "100 Continue"
2315 if string(slurp
) != reqBody(n
) {
2316 t
.Errorf("Server got %q, %v; want %q", slurp
, err
, reqBody(n
))
2319 body
:= fmt
.Sprintf("Response number %d", n
)
2320 v
:= []byte(strings
.Replace(fmt
.Sprintf(`HTTP/1.1 %s
2321 Date: Thu, 28 Feb 2013 17:55:41 GMT
2324 Content-Type: text/html
2328 %s`, resCode
, id
, len(body
), body
), "\n", "\r\n", -1))
2330 if id
== reqID(numReqs
) {
2338 Dial
: func(n
, addr
string) (net
.Conn
, error
) {
2339 sr
, sw
:= io
.Pipe() // server read/write
2340 cr
, cw
:= io
.Pipe() // client read/write
2341 conn
:= &rwTestConn
{
2344 closeFunc
: func() error
{
2350 go send100Response(cw
, sr
)
2353 DisableKeepAlives
: false,
2355 defer tr
.CloseIdleConnections()
2356 c
:= &Client
{Transport
: tr
}
2358 testResponse
:= func(req
*Request
, name
string, wantCode
int) {
2360 res
, err
:= c
.Do(req
)
2362 t
.Fatalf("%s: Do: %v", name
, err
)
2364 if res
.StatusCode
!= wantCode
{
2365 t
.Fatalf("%s: Response Statuscode=%d; want %d", name
, res
.StatusCode
, wantCode
)
2367 if id
, idBack
:= req
.Header
.Get("Request-Id"), res
.Header
.Get("Echo-Request-Id"); id
!= "" && id
!= idBack
{
2368 t
.Errorf("%s: response id %q != request id %q", name
, idBack
, id
)
2370 _
, err
= ioutil
.ReadAll(res
.Body
)
2372 t
.Fatalf("%s: Slurp error: %v", name
, err
)
2376 // Few 100 responses, making sure we're not off-by-one.
2377 for i
:= 1; i
<= numReqs
; i
++ {
2378 req
, _
:= NewRequest("POST", "http://dummy.tld/", strings
.NewReader(reqBody(i
)))
2379 req
.Header
.Set("Request-Id", reqID(i
))
2380 testResponse(req
, fmt
.Sprintf("100, %d/%d", i
, numReqs
), 200)
2384 // Issue 17739: the HTTP client must ignore any unknown 1xx
2385 // informational responses before the actual response.
2386 func TestTransportIgnore1xxResponses(t
*testing
.T
) {
2389 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2390 conn
, buf
, _
:= w
.(Hijacker
).Hijack()
2391 buf
.Write([]byte("HTTP/1.1 123 OneTwoThree\r\nFoo: bar\r\n\r\nHTTP/1.1 200 OK\r\nBar: baz\r\nContent-Length: 5\r\n\r\nHello"))
2396 cst
.tr
.DisableKeepAlives
= true // prevent log spam; our test server is hanging up anyway
2398 var got bytes
.Buffer
2400 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
2401 req
= req
.WithContext(httptrace
.WithClientTrace(context
.Background(), &httptrace
.ClientTrace
{
2402 Got1xxResponse
: func(code
int, header textproto
.MIMEHeader
) error
{
2403 fmt
.Fprintf(&got
, "1xx: code=%v, header=%v\n", code
, header
)
2407 res
, err
:= cst
.c
.Do(req
)
2411 defer res
.Body
.Close()
2414 want
:= "1xx: code=123, header=map[Foo:[bar]]\nHTTP/1.1 200 OK\r\nContent-Length: 5\r\nBar: baz\r\n\r\nHello"
2415 if got
.String() != want
{
2416 t
.Errorf(" got: %q\nwant: %q\n", got
.Bytes(), want
)
2420 func TestTransportLimits1xxResponses(t
*testing
.T
) {
2423 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2424 conn
, buf
, _
:= w
.(Hijacker
).Hijack()
2425 for i
:= 0; i
< 10; i
++ {
2426 buf
.Write([]byte("HTTP/1.1 123 OneTwoThree\r\n\r\n"))
2428 buf
.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n"))
2433 cst
.tr
.DisableKeepAlives
= true // prevent log spam; our test server is hanging up anyway
2435 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
2437 defer res
.Body
.Close()
2439 got
:= fmt
.Sprint(err
)
2440 wantSub
:= "too many 1xx informational responses"
2441 if !strings
.Contains(got
, wantSub
) {
2442 t
.Errorf("Get error = %v; want substring %q", err
, wantSub
)
2446 // Issue 26161: the HTTP client must treat 101 responses
2447 // as the final response.
2448 func TestTransportTreat101Terminal(t
*testing
.T
) {
2451 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2452 conn
, buf
, _
:= w
.(Hijacker
).Hijack()
2453 buf
.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n\r\n"))
2454 buf
.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n"))
2459 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
2463 defer res
.Body
.Close()
2464 if res
.StatusCode
!= StatusSwitchingProtocols
{
2465 t
.Errorf("StatusCode = %v; want 101 Switching Protocols", res
.StatusCode
)
2469 type proxyFromEnvTest
struct {
2470 req
string // URL to fetch; blank means "http://example.com"
2472 env
string // HTTP_PROXY
2473 httpsenv
string // HTTPS_PROXY
2474 noenv
string // NO_PROXY
2475 reqmeth
string // REQUEST_METHOD
2481 func (t proxyFromEnvTest
) String() string {
2482 var buf bytes
.Buffer
2489 fmt
.Fprintf(&buf
, "http_proxy=%q", t
.env
)
2491 if t
.httpsenv
!= "" {
2493 fmt
.Fprintf(&buf
, "https_proxy=%q", t
.httpsenv
)
2497 fmt
.Fprintf(&buf
, "no_proxy=%q", t
.noenv
)
2499 if t
.reqmeth
!= "" {
2501 fmt
.Fprintf(&buf
, "request_method=%q", t
.reqmeth
)
2503 req
:= "http://example.com"
2508 fmt
.Fprintf(&buf
, "req=%q", req
)
2509 return strings
.TrimSpace(buf
.String())
2512 var proxyFromEnvTests
= []proxyFromEnvTest
{
2513 {env
: "127.0.0.1:8080", want
: "http://127.0.0.1:8080"},
2514 {env
: "cache.corp.example.com:1234", want
: "http://cache.corp.example.com:1234"},
2515 {env
: "cache.corp.example.com", want
: "http://cache.corp.example.com"},
2516 {env
: "https://cache.corp.example.com", want
: "https://cache.corp.example.com"},
2517 {env
: "http://127.0.0.1:8080", want
: "http://127.0.0.1:8080"},
2518 {env
: "https://127.0.0.1:8080", want
: "https://127.0.0.1:8080"},
2519 {env
: "socks5://127.0.0.1", want
: "socks5://127.0.0.1"},
2521 // Don't use secure for http
2522 {req
: "http://insecure.tld/", env
: "http.proxy.tld", httpsenv
: "secure.proxy.tld", want
: "http://http.proxy.tld"},
2523 // Use secure for https.
2524 {req
: "https://secure.tld/", env
: "http.proxy.tld", httpsenv
: "secure.proxy.tld", want
: "http://secure.proxy.tld"},
2525 {req
: "https://secure.tld/", env
: "http.proxy.tld", httpsenv
: "https://secure.proxy.tld", want
: "https://secure.proxy.tld"},
2527 // Issue 16405: don't use HTTP_PROXY in a CGI environment,
2528 // where HTTP_PROXY can be attacker-controlled.
2529 {env
: "http://10.1.2.3:8080", reqmeth
: "POST",
2531 wanterr
: errors
.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")},
2535 {noenv
: "example.com", req
: "http://example.com/", env
: "proxy", want
: "<nil>"},
2536 {noenv
: ".example.com", req
: "http://example.com/", env
: "proxy", want
: "http://proxy"},
2537 {noenv
: "ample.com", req
: "http://example.com/", env
: "proxy", want
: "http://proxy"},
2538 {noenv
: "example.com", req
: "http://foo.example.com/", env
: "proxy", want
: "<nil>"},
2539 {noenv
: ".foo.com", req
: "http://example.com/", env
: "proxy", want
: "http://proxy"},
2542 func testProxyForRequest(t
*testing
.T
, tt proxyFromEnvTest
, proxyForRequest
func(req
*Request
) (*url
.URL
, error
)) {
2546 reqURL
= "http://example.com"
2548 req
, _
:= NewRequest("GET", reqURL
, nil)
2549 url
, err
:= proxyForRequest(req
)
2550 if g
, e
:= fmt
.Sprintf("%v", err
), fmt
.Sprintf("%v", tt
.wanterr
); g
!= e
{
2551 t
.Errorf("%v: got error = %q, want %q", tt
, g
, e
)
2554 if got
:= fmt
.Sprintf("%s", url
); got
!= tt
.want
{
2555 t
.Errorf("%v: got URL = %q, want %q", tt
, url
, tt
.want
)
2559 func TestProxyFromEnvironment(t
*testing
.T
) {
2561 defer ResetProxyEnv()
2562 for _
, tt
:= range proxyFromEnvTests
{
2563 testProxyForRequest(t
, tt
, func(req
*Request
) (*url
.URL
, error
) {
2564 os
.Setenv("HTTP_PROXY", tt
.env
)
2565 os
.Setenv("HTTPS_PROXY", tt
.httpsenv
)
2566 os
.Setenv("NO_PROXY", tt
.noenv
)
2567 os
.Setenv("REQUEST_METHOD", tt
.reqmeth
)
2568 ResetCachedEnvironment()
2569 return ProxyFromEnvironment(req
)
2574 func TestProxyFromEnvironmentLowerCase(t
*testing
.T
) {
2576 defer ResetProxyEnv()
2577 for _
, tt
:= range proxyFromEnvTests
{
2578 testProxyForRequest(t
, tt
, func(req
*Request
) (*url
.URL
, error
) {
2579 os
.Setenv("http_proxy", tt
.env
)
2580 os
.Setenv("https_proxy", tt
.httpsenv
)
2581 os
.Setenv("no_proxy", tt
.noenv
)
2582 os
.Setenv("REQUEST_METHOD", tt
.reqmeth
)
2583 ResetCachedEnvironment()
2584 return ProxyFromEnvironment(req
)
2589 func TestIdleConnChannelLeak(t
*testing
.T
) {
2590 // Not parallel: uses global test hooks.
2594 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2602 didRead
:= make(chan bool, nReqs
)
2603 SetReadLoopBeforeNextReadHook(func() { didRead
<- true })
2604 defer SetReadLoopBeforeNextReadHook(nil)
2607 tr
:= c
.Transport
.(*Transport
)
2608 tr
.Dial
= func(netw
, addr
string) (net
.Conn
, error
) {
2609 return net
.Dial(netw
, ts
.Listener
.Addr().String())
2612 // First, without keep-alives.
2613 for _
, disableKeep
:= range []bool{true, false} {
2614 tr
.DisableKeepAlives
= disableKeep
2615 for i
:= 0; i
< nReqs
; i
++ {
2616 _
, err
:= c
.Get(fmt
.Sprintf("http://foo-host-%d.tld/", i
))
2620 // Note: no res.Body.Close is needed here, since the
2621 // response Content-Length is zero. Perhaps the test
2622 // should be more explicit and use a HEAD, but tests
2623 // elsewhere guarantee that zero byte responses generate
2624 // a "Content-Length: 0" instead of chunking.
2627 // At this point, each of the 5 Transport.readLoop goroutines
2628 // are scheduling noting that there are no response bodies (see
2629 // earlier comment), and are then calling putIdleConn, which
2630 // decrements this count. Usually that happens quickly, which is
2631 // why this test has seemed to work for ages. But it's still
2632 // racey: we have wait for them to finish first. See Issue 10427
2633 for i
:= 0; i
< nReqs
; i
++ {
2637 if got
:= tr
.IdleConnChMapSizeForTesting(); got
!= 0 {
2638 t
.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep
, got
)
2643 // Verify the status quo: that the Client.Post function coerces its
2644 // body into a ReadCloser if it's a Closer, and that the Transport
2646 func TestTransportClosesRequestBody(t
*testing
.T
) {
2648 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2649 io
.Copy(ioutil
.Discard
, r
.Body
)
2657 res
, err
:= c
.Post(ts
.URL
, "text/plain", countCloseReader
{&closes
, strings
.NewReader("hello")})
2663 t
.Errorf("closes = %d; want 1", closes
)
2667 func TestTransportTLSHandshakeTimeout(t
*testing
.T
) {
2669 if testing
.Short() {
2670 t
.Skip("skipping in short mode")
2672 ln
:= newLocalListener(t
)
2674 testdonec
:= make(chan struct{})
2675 defer close(testdonec
)
2678 c
, err
:= ln
.Accept()
2687 getdonec
:= make(chan struct{})
2689 defer close(getdonec
)
2691 Dial
: func(_
, _
string) (net
.Conn
, error
) {
2692 return net
.Dial("tcp", ln
.Addr().String())
2694 TLSHandshakeTimeout
: 250 * time
.Millisecond
,
2696 cl
:= &Client
{Transport
: tr
}
2697 _
, err
:= cl
.Get("https://dummy.tld/")
2699 t
.Error("expected error")
2702 ue
, ok
:= err
.(*url
.Error
)
2704 t
.Errorf("expected url.Error; got %#v", err
)
2707 ne
, ok
:= ue
.Err
.(net
.Error
)
2709 t
.Errorf("expected net.Error; got %#v", err
)
2713 t
.Errorf("expected timeout error; got %v", err
)
2715 if !strings
.Contains(err
.Error(), "handshake timeout") {
2716 t
.Errorf("expected 'handshake timeout' in error; got %v", err
)
2721 case <-time
.After(5 * time
.Second
):
2722 t
.Error("test timeout; TLS handshake hung?")
2726 // Trying to repro golang.org/issue/3514
2727 func TestTLSServerClosesConnection(t
*testing
.T
) {
2729 testenv
.SkipFlaky(t
, 7634)
2731 closedc
:= make(chan bool, 1)
2732 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2733 if strings
.Contains(r
.URL
.Path
, "/keep-alive-then-die") {
2734 conn
, _
, _
:= w
.(Hijacker
).Hijack()
2735 conn
.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"))
2740 fmt
.Fprintf(w
, "hello")
2745 tr
:= c
.Transport
.(*Transport
)
2750 for i
:= 0; i
< trials
; i
++ {
2751 tr
.CloseIdleConnections()
2752 res
, err
:= c
.Get(ts
.URL
+ "/keep-alive-then-die")
2757 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
2761 if string(slurp
) != "foo" {
2762 t
.Errorf("Got %q, want foo", slurp
)
2765 // Now try again and see if we successfully
2766 // pick a new connection.
2767 res
, err
= c
.Get(ts
.URL
+ "/")
2769 errs
= append(errs
, err
)
2772 slurp
, err
= ioutil
.ReadAll(res
.Body
)
2774 errs
= append(errs
, err
)
2780 t
.Logf("successes = %d of %d", nSuccess
, trials
)
2782 t
.Errorf("All runs failed:")
2784 for _
, err
:= range errs
{
2785 t
.Logf(" err: %v", err
)
2789 // byteFromChanReader is an io.Reader that reads a single byte at a
2790 // time from the channel. When the channel is closed, the reader
2792 type byteFromChanReader
chan byte
2794 func (c byteFromChanReader
) Read(p
[]byte) (n
int, err error
) {
2806 // Verifies that the Transport doesn't reuse a connection in the case
2807 // where the server replies before the request has been fully
2808 // written. We still honor that reply (see TestIssue3595), but don't
2809 // send future requests on the connection because it's then in a
2810 // questionable state.
2811 // golang.org/issue/7569
2812 func TestTransportNoReuseAfterEarlyResponse(t
*testing
.T
) {
2820 closeConn
:= func() {
2822 defer sconn
.Unlock()
2827 t
.Logf("Closed server connection")
2833 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2834 if r
.Method
== "GET" {
2835 io
.WriteString(w
, "bar")
2838 conn
, _
, _
:= w
.(Hijacker
).Hijack()
2842 conn
.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive
2843 go io
.Copy(ioutil
.Discard
, conn
)
2848 const bodySize
= 256 << 10
2849 finalBit
:= make(byteFromChanReader
, 1)
2850 req
, _
:= NewRequest("POST", ts
.URL
, io
.MultiReader(io
.LimitReader(neverEnding('x'), bodySize
-1), finalBit
))
2851 req
.ContentLength
= bodySize
2852 res
, err
:= c
.Do(req
)
2853 if err
:= wantBody(res
, err
, "foo"); err
!= nil {
2854 t
.Errorf("POST response: %v", err
)
2856 donec
:= make(chan bool)
2859 res
, err
= c
.Get(ts
.URL
)
2860 if err
:= wantBody(res
, err
, "bar"); err
!= nil {
2861 t
.Errorf("GET response: %v", err
)
2864 getOkay
= true // suppress test noise
2866 time
.AfterFunc(5*time
.Second
, closeConn
)
2869 finalBit
<- 'x' // unblock the writeloop of the first Post
2871 case <-time
.After(7 * time
.Second
):
2872 t
.Fatal("timeout waiting for GET request to finish")
2876 // Tests that we don't leak Transport persistConn.readLoop goroutines
2877 // when a server hangs up immediately after saying it would keep-alive.
2878 func TestTransportIssue10457(t
*testing
.T
) {
2879 defer afterTest(t
) // used to fail in goroutine leak check
2880 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
2881 // Send a response with no body, keep-alive
2882 // (implicit), and then lie and immediately close the
2883 // connection. This forces the Transport's readLoop to
2884 // immediately Peek an io.EOF and get to the point
2885 // that used to hang.
2886 conn
, _
, _
:= w
.(Hijacker
).Hijack()
2887 conn
.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n")) // keep-alive
2893 res
, err
:= c
.Get(ts
.URL
)
2895 t
.Fatalf("Get: %v", err
)
2897 defer res
.Body
.Close()
2899 // Just a sanity check that we at least get the response. The real
2900 // test here is that the "defer afterTest" above doesn't find any
2901 // leaked goroutines.
2902 if got
, want
:= res
.Header
.Get("Foo"), "Bar"; got
!= want
{
2903 t
.Errorf("Foo header = %q; want %q", got
, want
)
2907 type errorReader
struct {
2911 func (e errorReader
) Read(p
[]byte) (int, error
) { return 0, e
.err
}
2913 type closerFunc
func() error
2915 func (f closerFunc
) Close() error
{ return f() }
2917 type writerFuncConn
struct {
2919 write
func(p
[]byte) (n
int, err error
)
2922 func (c writerFuncConn
) Write(p
[]byte) (n
int, err error
) { return c
.write(p
) }
2924 // Issues 4677, 18241, and 17844. If we try to reuse a connection that the
2925 // server is in the process of closing, we may end up successfully writing out
2926 // our request (or a portion of our request) only to find a connection error
2927 // when we try to read from (or finish writing to) the socket.
2929 // NOTE: we resend a request only if:
2930 // - we reused a keep-alive connection
2931 // - we haven't yet received any header data
2932 // - either we wrote no bytes to the server, or the request is idempotent
2933 // This automatically prevents an infinite resend loop because we'll run out of
2934 // the cached keep-alive connections eventually.
2935 func TestRetryRequestsOnError(t
*testing
.T
) {
2936 newRequest
:= func(method
, urlStr
string, body io
.Reader
) *Request
{
2937 req
, err
:= NewRequest(method
, urlStr
, body
)
2944 testCases
:= []struct {
2948 // Note that we can't just re-use the Request object across calls to c.Do
2949 // because we need to rewind Body between calls. (GetBody is only used to
2950 // rewind Body on failure and redirects, not just because it's done.)
2955 name
: "IdempotentNoBodySomeWritten",
2956 // Believe that we've written some bytes to the server, so we know we're
2957 // not just in the "retry when no bytes sent" case".
2959 // Use the specific error that shouldRetryRequest looks for with idempotent requests.
2960 failureErr
: ExportErrServerClosedIdle
,
2961 req
: func() *Request
{
2962 return newRequest("GET", "http://fake.golang", nil)
2964 reqString
: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`,
2967 name
: "IdempotentGetBodySomeWritten",
2968 // Believe that we've written some bytes to the server, so we know we're
2969 // not just in the "retry when no bytes sent" case".
2971 // Use the specific error that shouldRetryRequest looks for with idempotent requests.
2972 failureErr
: ExportErrServerClosedIdle
,
2973 req
: func() *Request
{
2974 return newRequest("GET", "http://fake.golang", strings
.NewReader("foo\n"))
2976 reqString
: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
2979 name
: "NothingWrittenNoBody",
2980 // It's key that we return 0 here -- that's what enables Transport to know
2981 // that nothing was written, even though this is a non-idempotent request.
2983 failureErr
: errors
.New("second write fails"),
2984 req
: func() *Request
{
2985 return newRequest("DELETE", "http://fake.golang", nil)
2987 reqString
: `DELETE / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`,
2990 name
: "NothingWrittenGetBody",
2991 // It's key that we return 0 here -- that's what enables Transport to know
2992 // that nothing was written, even though this is a non-idempotent request.
2994 failureErr
: errors
.New("second write fails"),
2995 // Note that NewRequest will set up GetBody for strings.Reader, which is
2996 // required for the retry to occur
2997 req
: func() *Request
{
2998 return newRequest("POST", "http://fake.golang", strings
.NewReader("foo\n"))
3000 reqString
: `POST / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
3004 for _
, tc
:= range testCases
{
3005 t
.Run(tc
.name
, func(t
*testing
.T
) {
3012 logf
:= func(format
string, args
...interface{}) {
3015 fmt
.Fprintf(&logbuf
, format
, args
...)
3016 logbuf
.WriteByte('\n')
3019 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3021 w
.Header().Set("X-Status", "ok")
3025 var writeNumAtomic
int32
3027 c
.Transport
.(*Transport
).Dial
= func(network
, addr
string) (net
.Conn
, error
) {
3029 c
, err
:= net
.Dial(network
, ts
.Listener
.Addr().String())
3031 logf("Dial error: %v", err
)
3034 return &writerFuncConn
{
3036 write
: func(p
[]byte) (n
int, err error
) {
3037 if atomic
.AddInt32(&writeNumAtomic
, 1) == 2 {
3038 logf("intentional write failure")
3039 return tc
.failureN
, tc
.failureErr
3041 logf("Write(%q)", p
)
3047 SetRoundTripRetried(func() {
3050 defer SetRoundTripRetried(nil)
3052 for i
:= 0; i
< 3; i
++ {
3054 res
, err
:= c
.Do(tc
.req())
3056 if time
.Since(t0
) < MaxWriteWaitBeforeConnReuse
/2 {
3058 got
:= logbuf
.String()
3060 t
.Fatalf("i=%d: Do = %v; log:\n%s", i
, err
, got
)
3062 t
.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", MaxWriteWaitBeforeConnReuse
)
3068 got
:= logbuf
.String()
3070 want
:= fmt
.Sprintf(`Dial
3073 intentional write failure
3080 `, tc
.reqString
, tc
.reqString
, tc
.reqString
)
3082 t
.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got
, want
)
3089 func TestTransportClosesBodyOnError(t
*testing
.T
) {
3092 readBody
:= make(chan error
, 1)
3093 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3094 _
, err
:= ioutil
.ReadAll(r
.Body
)
3099 fakeErr
:= errors
.New("fake error")
3100 didClose
:= make(chan bool, 1)
3101 req
, _
:= NewRequest("POST", ts
.URL
, struct {
3105 io
.MultiReader(io
.LimitReader(neverEnding('x'), 1<<20), errorReader
{fakeErr
}),
3106 closerFunc(func() error
{
3108 case didClose
<- true:
3114 res
, err
:= c
.Do(req
)
3116 defer res
.Body
.Close()
3118 if err
== nil ||
!strings
.Contains(err
.Error(), fakeErr
.Error()) {
3119 t
.Fatalf("Do error = %v; want something containing %q", err
, fakeErr
.Error())
3122 case err
:= <-readBody
:
3124 t
.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'")
3126 case <-time
.After(5 * time
.Second
):
3127 t
.Error("timeout waiting for server handler to complete")
3132 t
.Errorf("didn't see Body.Close")
3136 func TestTransportDialTLS(t
*testing
.T
) {
3139 var mu sync
.Mutex
// guards following
3140 var gotReq
, didDial
bool
3142 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3149 c
.Transport
.(*Transport
).DialTLS
= func(netw
, addr
string) (net
.Conn
, error
) {
3153 c
, err
:= tls
.Dial(netw
, addr
, c
.Transport
.(*Transport
).TLSClientConfig
)
3157 return c
, c
.Handshake()
3160 res
, err
:= c
.Get(ts
.URL
)
3167 t
.Error("didn't get request")
3170 t
.Error("didn't use dial hook")
3174 // Test for issue 8755
3175 // Ensure that if a proxy returns an error, it is exposed by RoundTrip
3176 func TestRoundTripReturnsProxyError(t
*testing
.T
) {
3177 badProxy
:= func(*Request
) (*url
.URL
, error
) {
3178 return nil, errors
.New("errorMessage")
3181 tr
:= &Transport
{Proxy
: badProxy
}
3183 req
, _
:= NewRequest("GET", "http://example.com", nil)
3185 _
, err
:= tr
.RoundTrip(req
)
3188 t
.Error("Expected proxy error to be returned by RoundTrip")
3192 // tests that putting an idle conn after a call to CloseIdleConns does return it
3193 func TestTransportCloseIdleConnsThenReturn(t
*testing
.T
) {
3195 wantIdle
:= func(when
string, n
int) bool {
3196 got
:= tr
.IdleConnCountForTesting("http", "example.com") // key used by PutIdleTestConn
3200 t
.Errorf("%s: idle conns = %d; want %d", when
, got
, n
)
3203 wantIdle("start", 0)
3204 if !tr
.PutIdleTestConn("http", "example.com") {
3205 t
.Fatal("put failed")
3207 if !tr
.PutIdleTestConn("http", "example.com") {
3208 t
.Fatal("second put failed")
3210 wantIdle("after put", 2)
3211 tr
.CloseIdleConnections()
3212 if !tr
.IsIdleForTesting() {
3213 t
.Error("should be idle after CloseIdleConnections")
3215 wantIdle("after close idle", 0)
3216 if tr
.PutIdleTestConn("http", "example.com") {
3217 t
.Fatal("put didn't fail")
3219 wantIdle("after second put", 0)
3221 tr
.RequestIdleConnChForTesting() // should toggle the transport out of idle mode
3222 if tr
.IsIdleForTesting() {
3223 t
.Error("shouldn't be idle after RequestIdleConnChForTesting")
3225 if !tr
.PutIdleTestConn("http", "example.com") {
3226 t
.Fatal("after re-activation")
3228 wantIdle("after final put", 1)
3231 // This tests that an client requesting a content range won't also
3232 // implicitly ask for gzip support. If they want that, they need to do it
3234 // golang.org/issue/8923
3235 func TestTransportRangeAndGzip(t
*testing
.T
) {
3237 reqc
:= make(chan *Request
, 1)
3238 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3244 req
, _
:= NewRequest("GET", ts
.URL
, nil)
3245 req
.Header
.Set("Range", "bytes=7-11")
3246 res
, err
:= c
.Do(req
)
3253 if strings
.Contains(r
.Header
.Get("Accept-Encoding"), "gzip") {
3254 t
.Error("Transport advertised gzip support in the Accept header")
3256 if r
.Header
.Get("Range") == "" {
3257 t
.Error("no Range in request")
3259 case <-time
.After(10 * time
.Second
):
3265 // Test for issue 10474
3266 func TestTransportResponseCancelRace(t
*testing
.T
) {
3269 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3270 // important that this response has a body.
3275 tr
:= ts
.Client().Transport
.(*Transport
)
3277 req
, err
:= NewRequest("GET", ts
.URL
, nil)
3281 res
, err
:= tr
.RoundTrip(req
)
3285 // If we do an early close, Transport just throws the connection away and
3286 // doesn't reuse it. In order to trigger the bug, it has to reuse the connection
3288 if _
, err
:= io
.Copy(ioutil
.Discard
, res
.Body
); err
!= nil {
3292 req2
, err
:= NewRequest("GET", ts
.URL
, nil)
3296 tr
.CancelRequest(req
)
3297 res
, err
= tr
.RoundTrip(req2
)
3304 // Test for issue 19248: Content-Encoding's value is case insensitive.
3305 func TestTransportContentEncodingCaseInsensitive(t
*testing
.T
) {
3308 for _
, ce
:= range []string{"gzip", "GZIP"} {
3310 t
.Run(ce
, func(t
*testing
.T
) {
3311 const encodedString
= "Hello Gopher"
3312 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3313 w
.Header().Set("Content-Encoding", ce
)
3314 gz
:= gzip
.NewWriter(w
)
3315 gz
.Write([]byte(encodedString
))
3320 res
, err
:= ts
.Client().Get(ts
.URL
)
3325 body
, err
:= ioutil
.ReadAll(res
.Body
)
3331 if string(body
) != encodedString
{
3332 t
.Fatalf("Expected body %q, got: %q\n", encodedString
, string(body
))
3338 func TestTransportDialCancelRace(t
*testing
.T
) {
3341 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {}))
3343 tr
:= ts
.Client().Transport
.(*Transport
)
3345 req
, err
:= NewRequest("GET", ts
.URL
, nil)
3349 SetEnterRoundTripHook(func() {
3350 tr
.CancelRequest(req
)
3352 defer SetEnterRoundTripHook(nil)
3353 res
, err
:= tr
.RoundTrip(req
)
3354 if err
!= ExportErrRequestCanceled
{
3355 t
.Errorf("expected canceled request error; got %v", err
)
3362 // logWritesConn is a net.Conn that logs each Write call to writes
3363 // and then proxies to w.
3364 // It proxies Read calls to a reader it receives from rch.
3365 type logWritesConn
struct {
3366 net
.Conn
// nil. crash on use.
3370 rch
<-chan io
.Reader
3371 r io
.Reader
// nil until received by rch
3377 func (c
*logWritesConn
) Write(p
[]byte) (n
int, err error
) {
3380 c
.writes
= append(c
.writes
, string(p
))
3384 func (c
*logWritesConn
) Read(p
[]byte) (n
int, err error
) {
3391 func (c
*logWritesConn
) Close() error
{ return nil }
3394 func TestTransportFlushesBodyChunks(t
*testing
.T
) {
3396 resBody
:= make(chan io
.Reader
, 1)
3397 connr
, connw
:= io
.Pipe() // connection pipe pair
3398 lw
:= &logWritesConn
{
3403 Dial
: func(network
, addr
string) (net
.Conn
, error
) {
3407 bodyr
, bodyw
:= io
.Pipe() // body pipe pair
3410 for i
:= 0; i
< 3; i
++ {
3411 fmt
.Fprintf(bodyw
, "num%d\n", i
)
3414 resc
:= make(chan *Response
)
3416 req
, _
:= NewRequest("POST", "http://localhost:8080", bodyr
)
3417 req
.Header
.Set("User-Agent", "x") // known value for test
3418 res
, err
:= tr
.RoundTrip(req
)
3420 t
.Errorf("RoundTrip: %v", err
)
3427 // Fully consume the request before checking the Write log vs. want.
3428 req
, err
:= ReadRequest(bufio
.NewReader(connr
))
3432 io
.Copy(ioutil
.Discard
, req
.Body
)
3434 // Unblock the transport's roundTrip goroutine.
3435 resBody
<- strings
.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
3440 defer res
.Body
.Close()
3443 "POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n",
3449 if !reflect
.DeepEqual(lw
.writes
, want
) {
3450 t
.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw
.writes
, want
)
3454 // Issue 22088: flush Transport request headers if we're not sure the body won't block on read.
3455 func TestTransportFlushesRequestHeader(t
*testing
.T
) {
3457 gotReq
:= make(chan struct{})
3458 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3464 req
, err
:= NewRequest("POST", cst
.ts
.URL
, pr
)
3468 gotRes
:= make(chan struct{})
3471 res
, err
:= cst
.tr
.RoundTrip(req
)
3482 case <-time
.After(5 * time
.Second
):
3483 t
.Fatal("timeout waiting for handler to get request")
3489 func TestTransportPrefersResponseOverWriteError(t
*testing
.T
) {
3490 if testing
.Short() {
3491 t
.Skip("skipping in short mode")
3494 const contentLengthLimit
= 1024 * 1024 // 1MB
3495 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3496 if r
.ContentLength
>= contentLengthLimit
{
3497 w
.WriteHeader(StatusBadRequest
)
3501 w
.WriteHeader(StatusOK
)
3508 bigBody
:= strings
.Repeat("a", contentLengthLimit
*2)
3509 for i
:= 0; i
< count
; i
++ {
3510 req
, err
:= NewRequest("PUT", ts
.URL
, strings
.NewReader(bigBody
))
3514 resp
, err
:= c
.Do(req
)
3517 t
.Logf("%d = %#v", i
, err
)
3518 if ue
, ok
:= err
.(*url
.Error
); ok
{
3519 t
.Logf("urlErr = %#v", ue
.Err
)
3520 if ne
, ok
:= ue
.Err
.(*net
.OpError
); ok
{
3521 t
.Logf("netOpError = %#v", ne
.Err
)
3526 if resp
.StatusCode
!= 400 {
3527 t
.Errorf("Expected status code 400, got %v", resp
.Status
)
3532 t
.Errorf("Failed %v out of %v\n", fail
, count
)
3536 func TestTransportAutomaticHTTP2(t
*testing
.T
) {
3537 testTransportAutoHTTP(t
, &Transport
{}, true)
3540 // golang.org/issue/14391: also check DefaultTransport
3541 func TestTransportAutomaticHTTP2_DefaultTransport(t
*testing
.T
) {
3542 testTransportAutoHTTP(t
, DefaultTransport
.(*Transport
), true)
3545 func TestTransportAutomaticHTTP2_TLSNextProto(t
*testing
.T
) {
3546 testTransportAutoHTTP(t
, &Transport
{
3547 TLSNextProto
: make(map[string]func(string, *tls
.Conn
) RoundTripper
),
3551 func TestTransportAutomaticHTTP2_TLSConfig(t
*testing
.T
) {
3552 testTransportAutoHTTP(t
, &Transport
{
3553 TLSClientConfig
: new(tls
.Config
),
3557 func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t
*testing
.T
) {
3558 testTransportAutoHTTP(t
, &Transport
{
3559 ExpectContinueTimeout
: 1 * time
.Second
,
3563 func TestTransportAutomaticHTTP2_Dial(t
*testing
.T
) {
3565 testTransportAutoHTTP(t
, &Transport
{
3570 func TestTransportAutomaticHTTP2_DialTLS(t
*testing
.T
) {
3571 testTransportAutoHTTP(t
, &Transport
{
3572 DialTLS
: func(network
, addr
string) (net
.Conn
, error
) {
3578 func testTransportAutoHTTP(t
*testing
.T
, tr
*Transport
, wantH2
bool) {
3579 _
, err
:= tr
.RoundTrip(new(Request
))
3581 t
.Error("expected error from RoundTrip")
3583 if reg
:= tr
.TLSNextProto
["h2"] != nil; reg
!= wantH2
{
3584 t
.Errorf("HTTP/2 registered = %v; want %v", reg
, wantH2
)
3588 // Issue 13633: there was a race where we returned bodyless responses
3589 // to callers before recycling the persistent connection, which meant
3590 // a client doing two subsequent requests could end up on different
3591 // connections. It's somewhat harmless but enough tests assume it's
3592 // not true in order to test other things that it's worth fixing.
3593 // Plus it's nice to be consistent and not have timing-dependent
3595 func TestTransportReuseConnEmptyResponseBody(t
*testing
.T
) {
3597 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3598 w
.Header().Set("X-Addr", r
.RemoteAddr
)
3599 // Empty response body.
3603 if testing
.Short() {
3606 var firstAddr
string
3607 for i
:= 0; i
< n
; i
++ {
3608 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
3612 addr
:= res
.Header
.Get("X-Addr")
3615 } else if addr
!= firstAddr
{
3616 t
.Fatalf("On request %d, addr %q != original addr %q", i
+1, addr
, firstAddr
)
3623 func TestNoCrashReturningTransportAltConn(t
*testing
.T
) {
3624 cert
, err
:= tls
.X509KeyPair(internal
.LocalhostCert
, internal
.LocalhostKey
)
3628 ln
:= newLocalListener(t
)
3631 handledPendingDial
:= make(chan bool, 1)
3632 SetPendingDialHooks(nil, func() { handledPendingDial
<- true })
3633 defer SetPendingDialHooks(nil, nil)
3635 testDone
:= make(chan struct{})
3636 defer close(testDone
)
3638 tln
:= tls
.NewListener(ln
, &tls
.Config
{
3639 NextProtos
: []string{"foo"},
3640 Certificates
: []tls
.Certificate
{cert
},
3642 sc
, err
:= tln
.Accept()
3647 if err
:= sc
.(*tls
.Conn
).Handshake(); err
!= nil {
3655 addr
:= ln
.Addr().String()
3657 req
, _
:= NewRequest("GET", "https://fake.tld/", nil)
3658 cancel
:= make(chan struct{})
3661 doReturned
:= make(chan bool, 1)
3662 madeRoundTripper
:= make(chan bool, 1)
3665 DisableKeepAlives
: true,
3666 TLSNextProto
: map[string]func(string, *tls
.Conn
) RoundTripper
{
3667 "foo": func(authority
string, c
*tls
.Conn
) RoundTripper
{
3668 madeRoundTripper
<- true
3669 return funcRoundTripper(func() {
3670 t
.Error("foo RoundTripper should not be called")
3674 Dial
: func(_
, _
string) (net
.Conn
, error
) {
3675 panic("shouldn't be called")
3677 DialTLS
: func(_
, _
string) (net
.Conn
, error
) {
3678 tc
, err
:= tls
.Dial("tcp", addr
, &tls
.Config
{
3679 InsecureSkipVerify
: true,
3680 NextProtos
: []string{"foo"},
3685 if err
:= tc
.Handshake(); err
!= nil {
3693 c
:= &Client
{Transport
: tr
}
3696 if ue
, ok
:= err
.(*url
.Error
); !ok || ue
.Err
!= ExportErrRequestCanceledConn
{
3697 t
.Fatalf("Do error = %v; want url.Error with errRequestCanceledConn", err
)
3702 <-handledPendingDial
3705 func TestTransportReuseConnection_Gzip_Chunked(t
*testing
.T
) {
3706 testTransportReuseConnection_Gzip(t
, true)
3709 func TestTransportReuseConnection_Gzip_ContentLength(t
*testing
.T
) {
3710 testTransportReuseConnection_Gzip(t
, false)
3713 // Make sure we re-use underlying TCP connection for gzipped responses too.
3714 func testTransportReuseConnection_Gzip(t
*testing
.T
, chunked
bool) {
3717 addr
:= make(chan string, 2)
3718 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3719 addr
<- r
.RemoteAddr
3720 w
.Header().Set("Content-Encoding", "gzip")
3724 w
.Write(rgz
) // arbitrary gzip response
3729 for i
:= 0; i
< 2; i
++ {
3730 res
, err
:= c
.Get(ts
.URL
)
3734 buf
:= make([]byte, len(rgz
))
3735 if n
, err
:= io
.ReadFull(res
.Body
, buf
); err
!= nil {
3736 t
.Errorf("%d. ReadFull = %v, %v", i
, n
, err
)
3738 // Note: no res.Body.Close call. It should work without it,
3739 // since the flate.Reader's internal buffering will hit EOF
3740 // and that should be sufficient.
3742 a1
, a2
:= <-addr
, <-addr
3744 t
.Fatalf("didn't reuse connection")
3748 func TestTransportResponseHeaderLength(t
*testing
.T
) {
3751 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3752 if r
.URL
.Path
== "/long" {
3753 w
.Header().Set("Long", strings
.Repeat("a", 1<<20))
3758 c
.Transport
.(*Transport
).MaxResponseHeaderBytes
= 512 << 10
3760 if res
, err
:= c
.Get(ts
.URL
); err
!= nil {
3766 res
, err
:= c
.Get(ts
.URL
+ "/long")
3768 defer res
.Body
.Close()
3770 for k
, vv
:= range res
.Header
{
3771 for _
, v
:= range vv
{
3772 n
+= int64(len(k
)) + int64(len(v
))
3775 t
.Fatalf("Unexpected success. Got %v and %d bytes of response headers", res
.Status
, n
)
3777 if want
:= "server response headers exceeded 524288 bytes"; !strings
.Contains(err
.Error(), want
) {
3778 t
.Errorf("got error: %v; want %q", err
, want
)
3782 func TestTransportEventTrace(t
*testing
.T
) { testTransportEventTrace(t
, h1Mode
, false) }
3783 func TestTransportEventTrace_h2(t
*testing
.T
) { testTransportEventTrace(t
, h2Mode
, false) }
3785 // test a non-nil httptrace.ClientTrace but with all hooks set to zero.
3786 func TestTransportEventTrace_NoHooks(t
*testing
.T
) { testTransportEventTrace(t
, h1Mode
, true) }
3787 func TestTransportEventTrace_NoHooks_h2(t
*testing
.T
) { testTransportEventTrace(t
, h2Mode
, true) }
3789 func testTransportEventTrace(t
*testing
.T
, h2
bool, noHooks
bool) {
3791 const resBody
= "some body"
3792 gotWroteReqEvent
:= make(chan struct{}, 500)
3793 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3794 if r
.Method
== "GET" {
3795 // Do nothing for the second request.
3798 if _
, err
:= ioutil
.ReadAll(r
.Body
); err
!= nil {
3803 case <-gotWroteReqEvent
:
3804 case <-time
.After(5 * time
.Second
):
3805 t
.Error("timeout waiting for WroteRequest event")
3808 io
.WriteString(w
, resBody
)
3812 cst
.tr
.ExpectContinueTimeout
= 1 * time
.Second
3814 var mu sync
.Mutex
// guards buf
3815 var buf bytes
.Buffer
3816 logf
:= func(format
string, args
...interface{}) {
3819 fmt
.Fprintf(&buf
, format
, args
...)
3823 addrStr
:= cst
.ts
.Listener
.Addr().String()
3824 ip
, port
, err
:= net
.SplitHostPort(addrStr
)
3829 // Install a fake DNS server.
3830 ctx
:= context
.WithValue(context
.Background(), nettrace
.LookupIPAltResolverKey
{}, func(ctx context
.Context
, host
string) ([]net
.IPAddr
, error
) {
3831 if host
!= "dns-is-faked.golang" {
3832 t
.Errorf("unexpected DNS host lookup for %q", host
)
3835 return []net
.IPAddr
{{IP
: net
.ParseIP(ip
)}}, nil
3839 req
, _
:= NewRequest("POST", cst
.scheme()+"://dns-is-faked.golang:"+port
, strings
.NewReader(body
))
3840 req
.Header
["X-Foo-Multiple-Vals"] = []string{"bar", "baz"}
3841 trace
:= &httptrace
.ClientTrace
{
3842 GetConn
: func(hostPort
string) { logf("Getting conn for %v ...", hostPort
) },
3843 GotConn
: func(ci httptrace
.GotConnInfo
) { logf("got conn: %+v", ci
) },
3844 GotFirstResponseByte
: func() { logf("first response byte") },
3845 PutIdleConn
: func(err error
) { logf("PutIdleConn = %v", err
) },
3846 DNSStart
: func(e httptrace
.DNSStartInfo
) { logf("DNS start: %+v", e
) },
3847 DNSDone
: func(e httptrace
.DNSDoneInfo
) { logf("DNS done: %+v", e
) },
3848 ConnectStart
: func(network
, addr
string) { logf("ConnectStart: Connecting to %s %s ...", network
, addr
) },
3849 ConnectDone
: func(network
, addr
string, err error
) {
3851 t
.Errorf("ConnectDone: %v", err
)
3853 logf("ConnectDone: connected to %s %s = %v", network
, addr
, err
)
3855 WroteHeaderField
: func(key
string, value
[]string) {
3856 logf("WroteHeaderField: %s: %v", key
, value
)
3858 WroteHeaders
: func() {
3859 logf("WroteHeaders")
3861 Wait100Continue
: func() { logf("Wait100Continue") },
3862 Got100Continue
: func() { logf("Got100Continue") },
3863 WroteRequest
: func(e httptrace
.WroteRequestInfo
) {
3864 logf("WroteRequest: %+v", e
)
3865 gotWroteReqEvent
<- struct{}{}
3869 trace
.TLSHandshakeStart
= func() { logf("tls handshake start") }
3870 trace
.TLSHandshakeDone
= func(s tls
.ConnectionState
, err error
) {
3871 logf("tls handshake done. ConnectionState = %v \n err = %v", s
, err
)
3875 // zero out all func pointers, trying to get some path to crash
3876 *trace
= httptrace
.ClientTrace
{}
3878 req
= req
.WithContext(httptrace
.WithClientTrace(ctx
, trace
))
3880 req
.Header
.Set("Expect", "100-continue")
3881 res
, err
:= cst
.c
.Do(req
)
3885 logf("got roundtrip.response")
3886 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
3890 logf("consumed body")
3891 if string(slurp
) != resBody || res
.StatusCode
!= 200 {
3892 t
.Fatalf("Got %q, %v; want %q, 200 OK", slurp
, res
.Status
, resBody
)
3897 // Done at this point. Just testing a full HTTP
3898 // requests can happen with a trace pointing to a zero
3899 // ClientTrace, full of nil func pointers.
3907 wantOnce
:= func(sub
string) {
3908 if strings
.Count(got
, sub
) != 1 {
3909 t
.Errorf("expected substring %q exactly once in output.", sub
)
3912 wantOnceOrMore
:= func(sub
string) {
3913 if strings
.Count(got
, sub
) == 0 {
3914 t
.Errorf("expected substring %q at least once in output.", sub
)
3917 wantOnce("Getting conn for dns-is-faked.golang:" + port
)
3918 wantOnce("DNS start: {Host:dns-is-faked.golang}")
3919 wantOnce("DNS done: {Addrs:[{IP:" + ip
+ " Zone:}] Err:<nil> Coalesced:false}")
3920 wantOnce("got conn: {")
3921 wantOnceOrMore("Connecting to tcp " + addrStr
)
3922 wantOnceOrMore("connected to tcp " + addrStr
+ " = <nil>")
3923 wantOnce("Reused:false WasIdle:false IdleTime:0s")
3924 wantOnce("first response byte")
3926 wantOnce("tls handshake start")
3927 wantOnce("tls handshake done")
3929 wantOnce("PutIdleConn = <nil>")
3930 wantOnce("WroteHeaderField: User-Agent: [Go-http-client/1.1]")
3931 // TODO(meirf): issue 19761. Make these agnostic to h1/h2. (These are not h1 specific, but the
3932 // WroteHeaderField hook is not yet implemented in h2.)
3933 wantOnce(fmt
.Sprintf("WroteHeaderField: Host: [dns-is-faked.golang:%s]", port
))
3934 wantOnce(fmt
.Sprintf("WroteHeaderField: Content-Length: [%d]", len(body
)))
3935 wantOnce("WroteHeaderField: X-Foo-Multiple-Vals: [bar baz]")
3936 wantOnce("WroteHeaderField: Accept-Encoding: [gzip]")
3938 wantOnce("WroteHeaders")
3939 wantOnce("Wait100Continue")
3940 wantOnce("Got100Continue")
3941 wantOnce("WroteRequest: {Err:<nil>}")
3942 if strings
.Contains(got
, " to udp ") {
3943 t
.Errorf("should not see UDP (DNS) connections")
3946 t
.Errorf("Output:\n%s", got
)
3949 // And do a second request:
3950 req
, _
= NewRequest("GET", cst
.scheme()+"://dns-is-faked.golang:"+port
, nil)
3951 req
= req
.WithContext(httptrace
.WithClientTrace(ctx
, trace
))
3952 res
, err
= cst
.c
.Do(req
)
3956 if res
.StatusCode
!= 200 {
3965 sub
:= "Getting conn for dns-is-faked.golang:"
3966 if gotn
, want
:= strings
.Count(got
, sub
), 2; gotn
!= want
{
3967 t
.Errorf("substring %q appeared %d times; want %d. Log:\n%s", sub
, gotn
, want
, got
)
3972 func TestTransportEventTraceTLSVerify(t
*testing
.T
) {
3974 var buf bytes
.Buffer
3975 logf
:= func(format
string, args
...interface{}) {
3978 fmt
.Fprintf(&buf
, format
, args
...)
3982 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
3983 t
.Error("Unexpected request")
3986 ts
.Config
.ErrorLog
= log
.New(funcWriter(func(p
[]byte) (int, error
) {
3991 certpool
:= x509
.NewCertPool()
3992 certpool
.AddCert(ts
.Certificate())
3994 c
:= &Client
{Transport
: &Transport
{
3995 TLSClientConfig
: &tls
.Config
{
3996 ServerName
: "dns-is-faked.golang",
4001 trace
:= &httptrace
.ClientTrace
{
4002 TLSHandshakeStart
: func() { logf("TLSHandshakeStart") },
4003 TLSHandshakeDone
: func(s tls
.ConnectionState
, err error
) {
4004 logf("TLSHandshakeDone: ConnectionState = %v \n err = %v", s
, err
)
4008 req
, _
:= NewRequest("GET", ts
.URL
, nil)
4009 req
= req
.WithContext(httptrace
.WithClientTrace(context
.Background(), trace
))
4012 t
.Error("Expected request to fail TLS verification")
4019 wantOnce
:= func(sub
string) {
4020 if strings
.Count(got
, sub
) != 1 {
4021 t
.Errorf("expected substring %q exactly once in output.", sub
)
4025 wantOnce("TLSHandshakeStart")
4026 wantOnce("TLSHandshakeDone")
4027 wantOnce("err = x509: certificate is valid for example.com")
4030 t
.Errorf("Output:\n%s", got
)
4035 isDNSHijackedOnce sync
.Once
4039 func skipIfDNSHijacked(t
*testing
.T
) {
4040 // Skip this test if the user is using a shady/ISP
4041 // DNS server hijacking queries.
4042 // See issues 16732, 16716.
4043 isDNSHijackedOnce
.Do(func() {
4044 addrs
, _
:= net
.LookupHost("dns-should-not-resolve.golang")
4045 isDNSHijacked
= len(addrs
) != 0
4048 t
.Skip("skipping; test requires non-hijacking DNS server")
4052 func TestTransportEventTraceRealDNS(t
*testing
.T
) {
4053 skipIfDNSHijacked(t
)
4056 defer tr
.CloseIdleConnections()
4057 c
:= &Client
{Transport
: tr
}
4059 var mu sync
.Mutex
// guards buf
4060 var buf bytes
.Buffer
4061 logf
:= func(format
string, args
...interface{}) {
4064 fmt
.Fprintf(&buf
, format
, args
...)
4068 req
, _
:= NewRequest("GET", "http://dns-should-not-resolve.golang:80", nil)
4069 trace
:= &httptrace
.ClientTrace
{
4070 DNSStart
: func(e httptrace
.DNSStartInfo
) { logf("DNSStart: %+v", e
) },
4071 DNSDone
: func(e httptrace
.DNSDoneInfo
) { logf("DNSDone: %+v", e
) },
4072 ConnectStart
: func(network
, addr
string) { logf("ConnectStart: %s %s", network
, addr
) },
4073 ConnectDone
: func(network
, addr
string, err error
) { logf("ConnectDone: %s %s %v", network
, addr
, err
) },
4075 req
= req
.WithContext(httptrace
.WithClientTrace(context
.Background(), trace
))
4077 resp
, err
:= c
.Do(req
)
4080 t
.Fatal("expected error during DNS lookup")
4087 wantSub
:= func(sub
string) {
4088 if !strings
.Contains(got
, sub
) {
4089 t
.Errorf("expected substring %q in output.", sub
)
4092 wantSub("DNSStart: {Host:dns-should-not-resolve.golang}")
4093 wantSub("DNSDone: {Addrs:[] Err:")
4094 if strings
.Contains(got
, "ConnectStart") || strings
.Contains(got
, "ConnectDone") {
4095 t
.Errorf("should not see Connect events")
4098 t
.Errorf("Output:\n%s", got
)
4102 // Issue 14353: port can only contain digits.
4103 func TestTransportRejectsAlphaPort(t
*testing
.T
) {
4104 res
, err
:= Get("http://dummy.tld:123foo/bar")
4107 t
.Fatal("unexpected success")
4109 ue
, ok
:= err
.(*url
.Error
)
4111 t
.Fatalf("got %#v; want *url.Error", err
)
4113 got
:= ue
.Err
.Error()
4114 want
:= `invalid URL port "123foo"`
4116 t
.Errorf("got error %q; want %q", got
, want
)
4120 // Test the httptrace.TLSHandshake{Start,Done} hooks with a https http1
4121 // connections. The http2 test is done in TestTransportEventTrace_h2
4122 func TestTLSHandshakeTrace(t
*testing
.T
) {
4124 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {}))
4128 var start
, done
bool
4129 trace
:= &httptrace
.ClientTrace
{
4130 TLSHandshakeStart
: func() {
4135 TLSHandshakeDone
: func(s tls
.ConnectionState
, err error
) {
4140 t
.Fatal("Expected error to be nil but was:", err
)
4146 req
, err
:= NewRequest("GET", ts
.URL
, nil)
4148 t
.Fatal("Unable to construct test request:", err
)
4150 req
= req
.WithContext(httptrace
.WithClientTrace(req
.Context(), trace
))
4154 t
.Fatal("Unexpected error making request:", err
)
4160 t
.Fatal("Expected TLSHandshakeStart to be called, but wasn't")
4163 t
.Fatal("Expected TLSHandshakeDone to be called, but wasnt't")
4167 func TestTransportMaxIdleConns(t
*testing
.T
) {
4169 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4170 // No body for convenience.
4174 tr
:= c
.Transport
.(*Transport
)
4177 ip
, port
, err
:= net
.SplitHostPort(ts
.Listener
.Addr().String())
4181 ctx
:= context
.WithValue(context
.Background(), nettrace
.LookupIPAltResolverKey
{}, func(ctx context
.Context
, host
string) ([]net
.IPAddr
, error
) {
4182 return []net
.IPAddr
{{IP
: net
.ParseIP(ip
)}}, nil
4185 hitHost
:= func(n
int) {
4186 req
, _
:= NewRequest("GET", fmt
.Sprintf("http://host-%d.dns-is-faked.golang:"+port
, n
), nil)
4187 req
= req
.WithContext(ctx
)
4188 res
, err
:= c
.Do(req
)
4194 for i
:= 0; i
< 4; i
++ {
4198 "|http|host-0.dns-is-faked.golang:" + port
,
4199 "|http|host-1.dns-is-faked.golang:" + port
,
4200 "|http|host-2.dns-is-faked.golang:" + port
,
4201 "|http|host-3.dns-is-faked.golang:" + port
,
4203 if got
:= tr
.IdleConnKeysForTesting(); !reflect
.DeepEqual(got
, want
) {
4204 t
.Fatalf("idle conn keys mismatch.\n got: %q\nwant: %q\n", got
, want
)
4207 // Now hitting the 5th host should kick out the first host:
4210 "|http|host-1.dns-is-faked.golang:" + port
,
4211 "|http|host-2.dns-is-faked.golang:" + port
,
4212 "|http|host-3.dns-is-faked.golang:" + port
,
4213 "|http|host-4.dns-is-faked.golang:" + port
,
4215 if got
:= tr
.IdleConnKeysForTesting(); !reflect
.DeepEqual(got
, want
) {
4216 t
.Fatalf("idle conn keys mismatch after 5th host.\n got: %q\nwant: %q\n", got
, want
)
4220 func TestTransportIdleConnTimeout_h1(t
*testing
.T
) { testTransportIdleConnTimeout(t
, h1Mode
) }
4221 func TestTransportIdleConnTimeout_h2(t
*testing
.T
) { testTransportIdleConnTimeout(t
, h2Mode
) }
4222 func testTransportIdleConnTimeout(t
*testing
.T
, h2
bool) {
4223 if testing
.Short() {
4224 t
.Skip("skipping in short mode")
4228 const timeout
= 1 * time
.Second
4230 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4231 // No body for convenience.
4235 tr
.IdleConnTimeout
= timeout
4236 defer tr
.CloseIdleConnections()
4237 c
:= &Client
{Transport
: tr
}
4239 idleConns
:= func() []string {
4241 return tr
.IdleConnStrsForTesting_h2()
4243 return tr
.IdleConnStrsForTesting()
4248 doReq
:= func(n
int) {
4249 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
4250 req
= req
.WithContext(httptrace
.WithClientTrace(context
.Background(), &httptrace
.ClientTrace
{
4251 PutIdleConn
: func(err error
) {
4253 t
.Errorf("failed to keep idle conn: %v", err
)
4257 res
, err
:= c
.Do(req
)
4262 conns
:= idleConns()
4263 if len(conns
) != 1 {
4264 t
.Fatalf("req %v: unexpected number of idle conns: %q", n
, conns
)
4269 if conn
!= conns
[0] {
4270 t
.Fatalf("req %v: cached connection changed; expected the same one throughout the test", n
)
4273 for i
:= 0; i
< 3; i
++ {
4275 time
.Sleep(timeout
/ 2)
4277 time
.Sleep(timeout
* 3 / 2)
4278 if got
:= idleConns(); len(got
) != 0 {
4279 t
.Errorf("idle conns = %q; want none", got
)
4283 // Issue 16208: Go 1.7 crashed after Transport.IdleConnTimeout if an
4284 // HTTP/2 connection was established but but its caller no longer
4285 // wanted it. (Assuming the connection cache was enabled, which it is
4288 // This test reproduced the crash by setting the IdleConnTimeout low
4289 // (to make the test reasonable) and then making a request which is
4290 // canceled by the DialTLS hook, which then also waits to return the
4291 // real connection until after the RoundTrip saw the error. Then we
4292 // know the successful tls.Dial from DialTLS will need to go into the
4293 // idle pool. Then we give it a of time to explode.
4294 func TestIdleConnH2Crash(t
*testing
.T
) {
4296 cst
:= newClientServerTest(t
, h2Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4301 ctx
, cancel
:= context
.WithCancel(context
.Background())
4304 sawDoErr
:= make(chan bool, 1)
4305 testDone
:= make(chan struct{})
4306 defer close(testDone
)
4308 cst
.tr
.IdleConnTimeout
= 5 * time
.Millisecond
4309 cst
.tr
.DialTLS
= func(network
, addr
string) (net
.Conn
, error
) {
4310 c
, err
:= tls
.Dial(network
, addr
, &tls
.Config
{
4311 InsecureSkipVerify
: true,
4312 NextProtos
: []string{"h2"},
4318 if cs
:= c
.ConnectionState(); cs
.NegotiatedProtocol
!= "h2" {
4319 t
.Errorf("protocol = %q; want %q", cs
.NegotiatedProtocol
, "h2")
4321 return nil, errors
.New("bogus")
4326 failTimer
:= time
.NewTimer(5 * time
.Second
)
4327 defer failTimer
.Stop()
4332 t
.Error("timeout in DialTLS, waiting too long for cst.c.Do to fail")
4337 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
4338 req
= req
.WithContext(ctx
)
4339 res
, err
:= cst
.c
.Do(req
)
4342 t
.Fatal("unexpected success")
4346 // Wait for the explosion.
4347 time
.Sleep(cst
.tr
.IdleConnTimeout
* 10)
4350 type funcConn
struct {
4352 read
func([]byte) (int, error
)
4353 write
func([]byte) (int, error
)
4356 func (c funcConn
) Read(p
[]byte) (int, error
) { return c
.read(p
) }
4357 func (c funcConn
) Write(p
[]byte) (int, error
) { return c
.write(p
) }
4358 func (c funcConn
) Close() error
{ return nil }
4360 // Issue 16465: Transport.RoundTrip should return the raw net.Conn.Read error from Peek
4361 // back to the caller.
4362 func TestTransportReturnsPeekError(t
*testing
.T
) {
4363 errValue
:= errors
.New("specific error value")
4365 wrote
:= make(chan struct{})
4366 var wroteOnce sync
.Once
4369 Dial
: func(network
, addr
string) (net
.Conn
, error
) {
4371 read
: func([]byte) (int, error
) {
4375 write
: func(p
[]byte) (int, error
) {
4376 wroteOnce
.Do(func() { close(wrote
) })
4383 _
, err
:= tr
.RoundTrip(httptest
.NewRequest("GET", "http://fake.tld/", nil))
4384 if err
!= errValue
{
4385 t
.Errorf("error = %#v; want %v", err
, errValue
)
4389 // Issue 13835: international domain names should work
4390 func TestTransportIDNA_h1(t
*testing
.T
) { testTransportIDNA(t
, h1Mode
) }
4391 func TestTransportIDNA_h2(t
*testing
.T
) { testTransportIDNA(t
, h2Mode
) }
4392 func testTransportIDNA(t
*testing
.T
, h2
bool) {
4395 const uniDomain
= "гофер.го"
4396 const punyDomain
= "xn--c1ae0ajs.xn--c1aw"
4399 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4400 want
:= punyDomain
+ ":" + port
4402 t
.Errorf("Host header = %q; want %q", r
.Host
, want
)
4406 t
.Errorf("r.TLS == nil")
4407 } else if r
.TLS
.ServerName
!= punyDomain
{
4408 t
.Errorf("TLS.ServerName = %q; want %q", r
.TLS
.ServerName
, punyDomain
)
4411 w
.Header().Set("Hit-Handler", "1")
4415 ip
, port
, err
:= net
.SplitHostPort(cst
.ts
.Listener
.Addr().String())
4420 // Install a fake DNS server.
4421 ctx
:= context
.WithValue(context
.Background(), nettrace
.LookupIPAltResolverKey
{}, func(ctx context
.Context
, host
string) ([]net
.IPAddr
, error
) {
4422 if host
!= punyDomain
{
4423 t
.Errorf("got DNS host lookup for %q; want %q", host
, punyDomain
)
4426 return []net
.IPAddr
{{IP
: net
.ParseIP(ip
)}}, nil
4429 req
, _
:= NewRequest("GET", cst
.scheme()+"://"+uniDomain
+":"+port
, nil)
4430 trace
:= &httptrace
.ClientTrace
{
4431 GetConn
: func(hostPort
string) {
4432 want
:= net
.JoinHostPort(punyDomain
, port
)
4433 if hostPort
!= want
{
4434 t
.Errorf("getting conn for %q; want %q", hostPort
, want
)
4437 DNSStart
: func(e httptrace
.DNSStartInfo
) {
4438 if e
.Host
!= punyDomain
{
4439 t
.Errorf("DNSStart Host = %q; want %q", e
.Host
, punyDomain
)
4443 req
= req
.WithContext(httptrace
.WithClientTrace(ctx
, trace
))
4445 res
, err
:= cst
.tr
.RoundTrip(req
)
4449 defer res
.Body
.Close()
4450 if res
.Header
.Get("Hit-Handler") != "1" {
4451 out
, err
:= httputil
.DumpResponse(res
, true)
4455 t
.Errorf("Response body wasn't from Handler. Got:\n%s\n", out
)
4459 // Issue 13290: send User-Agent in proxy CONNECT
4460 func TestTransportProxyConnectHeader(t
*testing
.T
) {
4462 reqc
:= make(chan *Request
, 1)
4463 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4464 if r
.Method
!= "CONNECT" {
4465 t
.Errorf("method = %q; want CONNECT", r
.Method
)
4468 c
, _
, err
:= w
.(Hijacker
).Hijack()
4470 t
.Errorf("Hijack: %v", err
)
4478 c
.Transport
.(*Transport
).Proxy
= func(r
*Request
) (*url
.URL
, error
) {
4479 return url
.Parse(ts
.URL
)
4481 c
.Transport
.(*Transport
).ProxyConnectHeader
= Header
{
4482 "User-Agent": {"foo"},
4486 res
, err
:= c
.Get("https://dummy.tld/") // https to force a CONNECT
4489 t
.Errorf("unexpected success")
4492 case <-time
.After(3 * time
.Second
):
4495 if got
, want
:= r
.Header
.Get("User-Agent"), "foo"; got
!= want
{
4496 t
.Errorf("CONNECT request User-Agent = %q; want %q", got
, want
)
4498 if got
, want
:= r
.Header
.Get("Other"), "bar"; got
!= want
{
4499 t
.Errorf("CONNECT request Other = %q; want %q", got
, want
)
4504 var errFakeRoundTrip
= errors
.New("fake roundtrip")
4506 type funcRoundTripper
func()
4508 func (fn funcRoundTripper
) RoundTrip(*Request
) (*Response
, error
) {
4510 return nil, errFakeRoundTrip
4513 func wantBody(res
*Response
, err error
, want
string) error
{
4517 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
4519 return fmt
.Errorf("error reading body: %v", err
)
4521 if string(slurp
) != want
{
4522 return fmt
.Errorf("body = %q; want %q", slurp
, want
)
4524 if err
:= res
.Body
.Close(); err
!= nil {
4525 return fmt
.Errorf("body Close = %v", err
)
4530 func newLocalListener(t
*testing
.T
) net
.Listener
{
4531 ln
, err
:= net
.Listen("tcp", "127.0.0.1:0")
4533 ln
, err
= net
.Listen("tcp6", "[::1]:0")
4541 type countCloseReader
struct {
4546 func (cr countCloseReader
) Close() error
{
4551 // rgz is a gzip quine that uncompresses to itself.
4553 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
4554 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73,
4555 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0,
4556 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2,
4557 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17,
4558 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60,
4559 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2,
4560 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00,
4561 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00,
4562 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16,
4563 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05,
4564 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff,
4565 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00,
4566 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00,
4567 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
4568 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88,
4569 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff,
4570 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00,
4571 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00,
4572 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
4573 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
4574 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff,
4575 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00,
4576 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
4577 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16,
4578 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08,
4579 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa,
4580 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06,
4581 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00,
4582 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
4583 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
4587 // Ensure that a missing status doesn't make the server panic
4588 // See Issue https://golang.org/issues/21701
4589 func TestMissingStatusNoPanic(t
*testing
.T
) {
4592 const want
= "unknown status code"
4594 ln
:= newLocalListener(t
)
4595 addr
:= ln
.Addr().String()
4596 shutdown
:= make(chan bool, 1)
4597 done
:= make(chan bool)
4598 fullAddrURL
:= fmt
.Sprintf("http://%s", addr
)
4599 raw
:= "HTTP/1.1 400\r\n" +
4600 "Date: Wed, 30 Aug 2017 19:09:27 GMT\r\n" +
4601 "Content-Type: text/html; charset=utf-8\r\n" +
4602 "Content-Length: 10\r\n" +
4603 "Last-Modified: Wed, 30 Aug 2017 19:02:02 GMT\r\n" +
4604 "Vary: Accept-Encoding\r\n\r\n" +
4613 conn
, _
:= ln
.Accept()
4615 io
.WriteString(conn
, raw
)
4616 ioutil
.ReadAll(conn
)
4621 proxyURL
, err
:= url
.Parse(fullAddrURL
)
4623 t
.Fatalf("proxyURL: %v", err
)
4626 tr
:= &Transport
{Proxy
: ProxyURL(proxyURL
)}
4628 req
, _
:= NewRequest("GET", "https://golang.org/", nil)
4629 res
, err
, panicked
:= doFetchCheckPanic(tr
, req
)
4631 t
.Error("panicked, expecting an error")
4633 if res
!= nil && res
.Body
!= nil {
4634 io
.Copy(ioutil
.Discard
, res
.Body
)
4638 if err
== nil ||
!strings
.Contains(err
.Error(), want
) {
4639 t
.Errorf("got=%v want=%q", err
, want
)
4646 func doFetchCheckPanic(tr
*Transport
, req
*Request
) (res
*Response
, err error
, panicked
bool) {
4648 if r
:= recover(); r
!= nil {
4652 res
, err
= tr
.RoundTrip(req
)
4656 // Issue 22330: do not allow the response body to be read when the status code
4657 // forbids a response body.
4658 func TestNoBodyOnChunked304Response(t
*testing
.T
) {
4660 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4661 conn
, buf
, _
:= w
.(Hijacker
).Hijack()
4662 buf
.Write([]byte("HTTP/1.1 304 NOT MODIFIED\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n"))
4668 // Our test server above is sending back bogus data after the
4669 // response (the "0\r\n\r\n" part), which causes the Transport
4670 // code to log spam. Disable keep-alives so we never even try
4671 // to reuse the connection.
4672 cst
.tr
.DisableKeepAlives
= true
4674 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
4679 if res
.Body
!= NoBody
{
4680 t
.Errorf("Unexpected body on 304 response")
4684 type funcWriter
func([]byte) (int, error
)
4686 func (f funcWriter
) Write(p
[]byte) (int, error
) { return f(p
) }
4688 type doneContext
struct {
4693 func (doneContext
) Done() <-chan struct{} {
4694 c
:= make(chan struct{})
4699 func (d doneContext
) Err() error
{ return d
.err
}
4701 // Issue 25852: Transport should check whether Context is done early.
4702 func TestTransportCheckContextDoneEarly(t
*testing
.T
) {
4704 req
, _
:= NewRequest("GET", "http://fake.example/", nil)
4705 wantErr
:= errors
.New("some error")
4706 req
= req
.WithContext(doneContext
{context
.Background(), wantErr
})
4707 _
, err
:= tr
.RoundTrip(req
)
4709 t
.Errorf("error = %v; want %v", err
, wantErr
)
4713 // Issue 23399: verify that if a client request times out, the Transport's
4714 // conn is closed so that it's not reused.
4716 // This is the test variant that times out before the server replies with
4717 // any response headers.
4718 func TestClientTimeoutKillsConn_BeforeHeaders(t
*testing
.T
) {
4721 inHandler
:= make(chan net
.Conn
, 1)
4722 handlerReadReturned
:= make(chan bool, 1)
4723 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4724 conn
, _
, err
:= w
.(Hijacker
).Hijack()
4730 n
, err
:= conn
.Read([]byte{0})
4731 if n
!= 0 || err
!= io
.EOF
{
4732 t
.Errorf("unexpected Read result: %v, %v", n
, err
)
4734 handlerReadReturned
<- true
4738 const timeout
= 50 * time
.Millisecond
4739 cst
.c
.Timeout
= timeout
4741 _
, err
:= cst
.c
.Get(cst
.ts
.URL
)
4743 t
.Fatal("unexpected Get succeess")
4747 case c
:= <-inHandler
:
4749 case <-handlerReadReturned
:
4752 case <-time
.After(5 * time
.Second
):
4753 t
.Error("Handler's conn.Read seems to be stuck in Read")
4754 c
.Close() // close it to unblock Handler
4756 case <-time
.After(timeout
* 10):
4757 // If we didn't get into the Handler in 50ms, that probably means
4758 // the builder was just slow and the the Get failed in that time
4759 // but never made it to the server. That's fine. We'll usually
4760 // test the part above on faster machines.
4761 t
.Skip("skipping test on slow builder")
4765 // Issue 23399: verify that if a client request times out, the Transport's
4766 // conn is closed so that it's not reused.
4768 // This is the test variant that has the server send response headers
4769 // first, and time out during the the write of the response body.
4770 func TestClientTimeoutKillsConn_AfterHeaders(t
*testing
.T
) {
4773 inHandler
:= make(chan net
.Conn
, 1)
4774 handlerResult
:= make(chan error
, 1)
4775 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
4776 w
.Header().Set("Content-Length", "100")
4778 conn
, _
, err
:= w
.(Hijacker
).Hijack()
4783 conn
.Write([]byte("foo"))
4785 n
, err
:= conn
.Read([]byte{0})
4786 // The error should be io.EOF or "read tcp
4787 // 127.0.0.1:35827->127.0.0.1:40290: read: connection
4788 // reset by peer" depending on timing. Really we just
4789 // care that it returns at all. But if it returns with
4790 // data, that's weird.
4791 if n
!= 0 || err
== nil {
4792 handlerResult
<- fmt
.Errorf("unexpected Read result: %v, %v", n
, err
)
4795 handlerResult
<- nil
4799 // Set Timeout to something very long but non-zero to exercise
4800 // the codepaths that check for it. But rather than wait for it to fire
4801 // (which would make the test slow), we send on the req.Cancel channel instead,
4802 // which happens to exercise the same code paths.
4803 cst
.c
.Timeout
= time
.Minute
// just to be non-zero, not to hit it.
4804 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
4805 cancel
:= make(chan struct{})
4808 res
, err
:= cst
.c
.Do(req
)
4812 t
.Fatalf("Get error: %v", err
)
4814 // Failed before entering handler. Ignore result.
4815 t
.Skip("skipping test on slow builder")
4820 got
, err
:= ioutil
.ReadAll(res
.Body
)
4822 t
.Fatalf("unexpected success; read %q, nil", got
)
4826 case c
:= <-inHandler
:
4828 case err
:= <-handlerResult
:
4830 t
.Errorf("handler: %v", err
)
4833 case <-time
.After(5 * time
.Second
):
4834 t
.Error("Handler's conn.Read seems to be stuck in Read")
4835 c
.Close() // close it to unblock Handler
4837 case <-time
.After(5 * time
.Second
):