github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/net/http/transport_test.go (about) 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. 4 5 // Tests for transport.go 6 7 package http_test 8 9 import ( 10 "bufio" 11 "bytes" 12 "compress/gzip" 13 "crypto/rand" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "net" 18 "net/http" 19 . "net/http" 20 "net/http/httptest" 21 "net/url" 22 "os" 23 "runtime" 24 "strconv" 25 "strings" 26 "sync" 27 "testing" 28 "time" 29 ) 30 31 // TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close 32 // and then verify that the final 2 responses get errors back. 33 34 // hostPortHandler writes back the client's "host:port". 35 var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 36 if r.FormValue("close") == "true" { 37 w.Header().Set("Connection", "close") 38 } 39 w.Write([]byte(r.RemoteAddr)) 40 }) 41 42 // testCloseConn is a net.Conn tracked by a testConnSet. 43 type testCloseConn struct { 44 net.Conn 45 set *testConnSet 46 } 47 48 func (c *testCloseConn) Close() error { 49 c.set.remove(c) 50 return c.Conn.Close() 51 } 52 53 // testConnSet tracks a set of TCP connections and whether they've 54 // been closed. 55 type testConnSet struct { 56 t *testing.T 57 closed map[net.Conn]bool 58 list []net.Conn // in order created 59 mutex sync.Mutex 60 } 61 62 func (tcs *testConnSet) insert(c net.Conn) { 63 tcs.mutex.Lock() 64 defer tcs.mutex.Unlock() 65 tcs.closed[c] = false 66 tcs.list = append(tcs.list, c) 67 } 68 69 func (tcs *testConnSet) remove(c net.Conn) { 70 tcs.mutex.Lock() 71 defer tcs.mutex.Unlock() 72 tcs.closed[c] = true 73 } 74 75 // some tests use this to manage raw tcp connections for later inspection 76 func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, error)) { 77 connSet := &testConnSet{ 78 t: t, 79 closed: make(map[net.Conn]bool), 80 } 81 dial := func(n, addr string) (net.Conn, error) { 82 c, err := net.Dial(n, addr) 83 if err != nil { 84 return nil, err 85 } 86 tc := &testCloseConn{c, connSet} 87 connSet.insert(tc) 88 return tc, nil 89 } 90 return connSet, dial 91 } 92 93 func (tcs *testConnSet) check(t *testing.T) { 94 tcs.mutex.Lock() 95 defer tcs.mutex.Unlock() 96 97 for i, c := range tcs.list { 98 if !tcs.closed[c] { 99 t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list)) 100 } 101 } 102 } 103 104 // Two subsequent requests and verify their response is the same. 105 // The response from the server is our own IP:port 106 func TestTransportKeepAlives(t *testing.T) { 107 defer afterTest(t) 108 ts := httptest.NewServer(hostPortHandler) 109 defer ts.Close() 110 111 for _, disableKeepAlive := range []bool{false, true} { 112 tr := &Transport{DisableKeepAlives: disableKeepAlive} 113 defer tr.CloseIdleConnections() 114 c := &Client{Transport: tr} 115 116 fetch := func(n int) string { 117 res, err := c.Get(ts.URL) 118 if err != nil { 119 t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err) 120 } 121 body, err := ioutil.ReadAll(res.Body) 122 if err != nil { 123 t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err) 124 } 125 return string(body) 126 } 127 128 body1 := fetch(1) 129 body2 := fetch(2) 130 131 bodiesDiffer := body1 != body2 132 if bodiesDiffer != disableKeepAlive { 133 t.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 134 disableKeepAlive, bodiesDiffer, body1, body2) 135 } 136 } 137 } 138 139 func TestTransportConnectionCloseOnResponse(t *testing.T) { 140 defer afterTest(t) 141 ts := httptest.NewServer(hostPortHandler) 142 defer ts.Close() 143 144 connSet, testDial := makeTestDial(t) 145 146 for _, connectionClose := range []bool{false, true} { 147 tr := &Transport{ 148 Dial: testDial, 149 } 150 c := &Client{Transport: tr} 151 152 fetch := func(n int) string { 153 req := new(Request) 154 var err error 155 req.URL, err = url.Parse(ts.URL + fmt.Sprintf("/?close=%v", connectionClose)) 156 if err != nil { 157 t.Fatalf("URL parse error: %v", err) 158 } 159 req.Method = "GET" 160 req.Proto = "HTTP/1.1" 161 req.ProtoMajor = 1 162 req.ProtoMinor = 1 163 164 res, err := c.Do(req) 165 if err != nil { 166 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) 167 } 168 defer res.Body.Close() 169 body, err := ioutil.ReadAll(res.Body) 170 if err != nil { 171 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) 172 } 173 return string(body) 174 } 175 176 body1 := fetch(1) 177 body2 := fetch(2) 178 bodiesDiffer := body1 != body2 179 if bodiesDiffer != connectionClose { 180 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 181 connectionClose, bodiesDiffer, body1, body2) 182 } 183 184 tr.CloseIdleConnections() 185 } 186 187 connSet.check(t) 188 } 189 190 func TestTransportConnectionCloseOnRequest(t *testing.T) { 191 defer afterTest(t) 192 ts := httptest.NewServer(hostPortHandler) 193 defer ts.Close() 194 195 connSet, testDial := makeTestDial(t) 196 197 for _, connectionClose := range []bool{false, true} { 198 tr := &Transport{ 199 Dial: testDial, 200 } 201 c := &Client{Transport: tr} 202 203 fetch := func(n int) string { 204 req := new(Request) 205 var err error 206 req.URL, err = url.Parse(ts.URL) 207 if err != nil { 208 t.Fatalf("URL parse error: %v", err) 209 } 210 req.Method = "GET" 211 req.Proto = "HTTP/1.1" 212 req.ProtoMajor = 1 213 req.ProtoMinor = 1 214 req.Close = connectionClose 215 216 res, err := c.Do(req) 217 if err != nil { 218 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) 219 } 220 body, err := ioutil.ReadAll(res.Body) 221 if err != nil { 222 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) 223 } 224 return string(body) 225 } 226 227 body1 := fetch(1) 228 body2 := fetch(2) 229 bodiesDiffer := body1 != body2 230 if bodiesDiffer != connectionClose { 231 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 232 connectionClose, bodiesDiffer, body1, body2) 233 } 234 235 tr.CloseIdleConnections() 236 } 237 238 connSet.check(t) 239 } 240 241 func TestTransportIdleCacheKeys(t *testing.T) { 242 defer afterTest(t) 243 ts := httptest.NewServer(hostPortHandler) 244 defer ts.Close() 245 246 tr := &Transport{DisableKeepAlives: false} 247 c := &Client{Transport: tr} 248 249 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 250 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) 251 } 252 253 resp, err := c.Get(ts.URL) 254 if err != nil { 255 t.Error(err) 256 } 257 ioutil.ReadAll(resp.Body) 258 259 keys := tr.IdleConnKeysForTesting() 260 if e, g := 1, len(keys); e != g { 261 t.Fatalf("After Get expected %d idle conn cache keys; got %d", e, g) 262 } 263 264 if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e { 265 t.Errorf("Expected idle cache key %q; got %q", e, keys[0]) 266 } 267 268 tr.CloseIdleConnections() 269 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 270 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) 271 } 272 } 273 274 func TestTransportMaxPerHostIdleConns(t *testing.T) { 275 defer afterTest(t) 276 resch := make(chan string) 277 gotReq := make(chan bool) 278 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 279 gotReq <- true 280 msg := <-resch 281 _, err := w.Write([]byte(msg)) 282 if err != nil { 283 t.Fatalf("Write: %v", err) 284 } 285 })) 286 defer ts.Close() 287 maxIdleConns := 2 288 tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns} 289 c := &Client{Transport: tr} 290 291 // Start 3 outstanding requests and wait for the server to get them. 292 // Their responses will hang until we write to resch, though. 293 donech := make(chan bool) 294 doReq := func() { 295 resp, err := c.Get(ts.URL) 296 if err != nil { 297 t.Error(err) 298 } 299 _, err = ioutil.ReadAll(resp.Body) 300 if err != nil { 301 t.Fatalf("ReadAll: %v", err) 302 } 303 donech <- true 304 } 305 go doReq() 306 <-gotReq 307 go doReq() 308 <-gotReq 309 go doReq() 310 <-gotReq 311 312 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 313 t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g) 314 } 315 316 resch <- "res1" 317 <-donech 318 keys := tr.IdleConnKeysForTesting() 319 if e, g := 1, len(keys); e != g { 320 t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g) 321 } 322 cacheKey := "|http|" + ts.Listener.Addr().String() 323 if keys[0] != cacheKey { 324 t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0]) 325 } 326 if e, g := 1, tr.IdleConnCountForTesting(cacheKey); e != g { 327 t.Errorf("after first response, expected %d idle conns; got %d", e, g) 328 } 329 330 resch <- "res2" 331 <-donech 332 if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g { 333 t.Errorf("after second response, expected %d idle conns; got %d", e, g) 334 } 335 336 resch <- "res3" 337 <-donech 338 if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g { 339 t.Errorf("after third response, still expected %d idle conns; got %d", e, g) 340 } 341 } 342 343 func TestTransportServerClosingUnexpectedly(t *testing.T) { 344 defer afterTest(t) 345 ts := httptest.NewServer(hostPortHandler) 346 defer ts.Close() 347 348 tr := &Transport{} 349 c := &Client{Transport: tr} 350 351 fetch := func(n, retries int) string { 352 condFatalf := func(format string, arg ...interface{}) { 353 if retries <= 0 { 354 t.Fatalf(format, arg...) 355 } 356 t.Logf("retrying shortly after expected error: "+format, arg...) 357 time.Sleep(time.Second / time.Duration(retries)) 358 } 359 for retries >= 0 { 360 retries-- 361 res, err := c.Get(ts.URL) 362 if err != nil { 363 condFatalf("error in req #%d, GET: %v", n, err) 364 continue 365 } 366 body, err := ioutil.ReadAll(res.Body) 367 if err != nil { 368 condFatalf("error in req #%d, ReadAll: %v", n, err) 369 continue 370 } 371 res.Body.Close() 372 return string(body) 373 } 374 panic("unreachable") 375 } 376 377 body1 := fetch(1, 0) 378 body2 := fetch(2, 0) 379 380 ts.CloseClientConnections() // surprise! 381 382 // This test has an expected race. Sleeping for 25 ms prevents 383 // it on most fast machines, causing the next fetch() call to 384 // succeed quickly. But if we do get errors, fetch() will retry 5 385 // times with some delays between. 386 time.Sleep(25 * time.Millisecond) 387 388 body3 := fetch(3, 5) 389 390 if body1 != body2 { 391 t.Errorf("expected body1 and body2 to be equal") 392 } 393 if body2 == body3 { 394 t.Errorf("expected body2 and body3 to be different") 395 } 396 } 397 398 // Test for http://golang.org/issue/2616 (appropriate issue number) 399 // This fails pretty reliably with GOMAXPROCS=100 or something high. 400 func TestStressSurpriseServerCloses(t *testing.T) { 401 defer afterTest(t) 402 if testing.Short() { 403 t.Skip("skipping test in short mode") 404 } 405 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 406 w.Header().Set("Content-Length", "5") 407 w.Header().Set("Content-Type", "text/plain") 408 w.Write([]byte("Hello")) 409 w.(Flusher).Flush() 410 conn, buf, _ := w.(Hijacker).Hijack() 411 buf.Flush() 412 conn.Close() 413 })) 414 defer ts.Close() 415 416 tr := &Transport{DisableKeepAlives: false} 417 c := &Client{Transport: tr} 418 419 // Do a bunch of traffic from different goroutines. Send to activityc 420 // after each request completes, regardless of whether it failed. 421 const ( 422 numClients = 50 423 reqsPerClient = 250 424 ) 425 activityc := make(chan bool) 426 for i := 0; i < numClients; i++ { 427 go func() { 428 for i := 0; i < reqsPerClient; i++ { 429 res, err := c.Get(ts.URL) 430 if err == nil { 431 // We expect errors since the server is 432 // hanging up on us after telling us to 433 // send more requests, so we don't 434 // actually care what the error is. 435 // But we want to close the body in cases 436 // where we won the race. 437 res.Body.Close() 438 } 439 activityc <- true 440 } 441 }() 442 } 443 444 // Make sure all the request come back, one way or another. 445 for i := 0; i < numClients*reqsPerClient; i++ { 446 select { 447 case <-activityc: 448 case <-time.After(5 * time.Second): 449 t.Fatalf("presumed deadlock; no HTTP client activity seen in awhile") 450 } 451 } 452 } 453 454 // TestTransportHeadResponses verifies that we deal with Content-Lengths 455 // with no bodies properly 456 func TestTransportHeadResponses(t *testing.T) { 457 defer afterTest(t) 458 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 459 if r.Method != "HEAD" { 460 panic("expected HEAD; got " + r.Method) 461 } 462 w.Header().Set("Content-Length", "123") 463 w.WriteHeader(200) 464 })) 465 defer ts.Close() 466 467 tr := &Transport{DisableKeepAlives: false} 468 c := &Client{Transport: tr} 469 for i := 0; i < 2; i++ { 470 res, err := c.Head(ts.URL) 471 if err != nil { 472 t.Errorf("error on loop %d: %v", i, err) 473 continue 474 } 475 if e, g := "123", res.Header.Get("Content-Length"); e != g { 476 t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g) 477 } 478 if e, g := int64(123), res.ContentLength; e != g { 479 t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g) 480 } 481 if all, err := ioutil.ReadAll(res.Body); err != nil { 482 t.Errorf("loop %d: Body ReadAll: %v", i, err) 483 } else if len(all) != 0 { 484 t.Errorf("Bogus body %q", all) 485 } 486 } 487 } 488 489 // TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding 490 // on responses to HEAD requests. 491 func TestTransportHeadChunkedResponse(t *testing.T) { 492 defer afterTest(t) 493 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 494 if r.Method != "HEAD" { 495 panic("expected HEAD; got " + r.Method) 496 } 497 w.Header().Set("Transfer-Encoding", "chunked") // client should ignore 498 w.Header().Set("x-client-ipport", r.RemoteAddr) 499 w.WriteHeader(200) 500 })) 501 defer ts.Close() 502 503 tr := &Transport{DisableKeepAlives: false} 504 c := &Client{Transport: tr} 505 506 res1, err := c.Head(ts.URL) 507 if err != nil { 508 t.Fatalf("request 1 error: %v", err) 509 } 510 res2, err := c.Head(ts.URL) 511 if err != nil { 512 t.Fatalf("request 2 error: %v", err) 513 } 514 if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 { 515 t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2) 516 } 517 } 518 519 var roundTripTests = []struct { 520 accept string 521 expectAccept string 522 compressed bool 523 }{ 524 // Requests with no accept-encoding header use transparent compression 525 {"", "gzip", false}, 526 // Requests with other accept-encoding should pass through unmodified 527 {"foo", "foo", false}, 528 // Requests with accept-encoding == gzip should be passed through 529 {"gzip", "gzip", true}, 530 } 531 532 // Test that the modification made to the Request by the RoundTripper is cleaned up 533 func TestRoundTripGzip(t *testing.T) { 534 defer afterTest(t) 535 const responseBody = "test response body" 536 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 537 accept := req.Header.Get("Accept-Encoding") 538 if expect := req.FormValue("expect_accept"); accept != expect { 539 t.Errorf("in handler, test %v: Accept-Encoding = %q, want %q", 540 req.FormValue("testnum"), accept, expect) 541 } 542 if accept == "gzip" { 543 rw.Header().Set("Content-Encoding", "gzip") 544 gz := gzip.NewWriter(rw) 545 gz.Write([]byte(responseBody)) 546 gz.Close() 547 } else { 548 rw.Header().Set("Content-Encoding", accept) 549 rw.Write([]byte(responseBody)) 550 } 551 })) 552 defer ts.Close() 553 554 for i, test := range roundTripTests { 555 // Test basic request (no accept-encoding) 556 req, _ := NewRequest("GET", fmt.Sprintf("%s/?testnum=%d&expect_accept=%s", ts.URL, i, test.expectAccept), nil) 557 if test.accept != "" { 558 req.Header.Set("Accept-Encoding", test.accept) 559 } 560 res, err := DefaultTransport.RoundTrip(req) 561 var body []byte 562 if test.compressed { 563 var r *gzip.Reader 564 r, err = gzip.NewReader(res.Body) 565 if err != nil { 566 t.Errorf("%d. gzip NewReader: %v", i, err) 567 continue 568 } 569 body, err = ioutil.ReadAll(r) 570 res.Body.Close() 571 } else { 572 body, err = ioutil.ReadAll(res.Body) 573 } 574 if err != nil { 575 t.Errorf("%d. Error: %q", i, err) 576 continue 577 } 578 if g, e := string(body), responseBody; g != e { 579 t.Errorf("%d. body = %q; want %q", i, g, e) 580 } 581 if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e { 582 t.Errorf("%d. Accept-Encoding = %q; want %q (it was mutated, in violation of RoundTrip contract)", i, g, e) 583 } 584 if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e { 585 t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e) 586 } 587 } 588 589 } 590 591 func TestTransportGzip(t *testing.T) { 592 defer afterTest(t) 593 const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 594 const nRandBytes = 1024 * 1024 595 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 596 if req.Method == "HEAD" { 597 if g := req.Header.Get("Accept-Encoding"); g != "" { 598 t.Errorf("HEAD request sent with Accept-Encoding of %q; want none", g) 599 } 600 return 601 } 602 if g, e := req.Header.Get("Accept-Encoding"), "gzip"; g != e { 603 t.Errorf("Accept-Encoding = %q, want %q", g, e) 604 } 605 rw.Header().Set("Content-Encoding", "gzip") 606 607 var w io.Writer = rw 608 var buf bytes.Buffer 609 if req.FormValue("chunked") == "0" { 610 w = &buf 611 defer io.Copy(rw, &buf) 612 defer func() { 613 rw.Header().Set("Content-Length", strconv.Itoa(buf.Len())) 614 }() 615 } 616 gz := gzip.NewWriter(w) 617 gz.Write([]byte(testString)) 618 if req.FormValue("body") == "large" { 619 io.CopyN(gz, rand.Reader, nRandBytes) 620 } 621 gz.Close() 622 })) 623 defer ts.Close() 624 625 for _, chunked := range []string{"1", "0"} { 626 c := &Client{Transport: &Transport{}} 627 628 // First fetch something large, but only read some of it. 629 res, err := c.Get(ts.URL + "/?body=large&chunked=" + chunked) 630 if err != nil { 631 t.Fatalf("large get: %v", err) 632 } 633 buf := make([]byte, len(testString)) 634 n, err := io.ReadFull(res.Body, buf) 635 if err != nil { 636 t.Fatalf("partial read of large response: size=%d, %v", n, err) 637 } 638 if e, g := testString, string(buf); e != g { 639 t.Errorf("partial read got %q, expected %q", g, e) 640 } 641 res.Body.Close() 642 // Read on the body, even though it's closed 643 n, err = res.Body.Read(buf) 644 if n != 0 || err == nil { 645 t.Errorf("expected error post-closed large Read; got = %d, %v", n, err) 646 } 647 648 // Then something small. 649 res, err = c.Get(ts.URL + "/?chunked=" + chunked) 650 if err != nil { 651 t.Fatal(err) 652 } 653 body, err := ioutil.ReadAll(res.Body) 654 if err != nil { 655 t.Fatal(err) 656 } 657 if g, e := string(body), testString; g != e { 658 t.Fatalf("body = %q; want %q", g, e) 659 } 660 if g, e := res.Header.Get("Content-Encoding"), ""; g != e { 661 t.Fatalf("Content-Encoding = %q; want %q", g, e) 662 } 663 664 // Read on the body after it's been fully read: 665 n, err = res.Body.Read(buf) 666 if n != 0 || err == nil { 667 t.Errorf("expected Read error after exhausted reads; got %d, %v", n, err) 668 } 669 res.Body.Close() 670 n, err = res.Body.Read(buf) 671 if n != 0 || err == nil { 672 t.Errorf("expected Read error after Close; got %d, %v", n, err) 673 } 674 } 675 676 // And a HEAD request too, because they're always weird. 677 c := &Client{Transport: &Transport{}} 678 res, err := c.Head(ts.URL) 679 if err != nil { 680 t.Fatalf("Head: %v", err) 681 } 682 if res.StatusCode != 200 { 683 t.Errorf("Head status=%d; want=200", res.StatusCode) 684 } 685 } 686 687 func TestTransportProxy(t *testing.T) { 688 defer afterTest(t) 689 ch := make(chan string, 1) 690 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 691 ch <- "real server" 692 })) 693 defer ts.Close() 694 proxy := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 695 ch <- "proxy for " + r.URL.String() 696 })) 697 defer proxy.Close() 698 699 pu, err := url.Parse(proxy.URL) 700 if err != nil { 701 t.Fatal(err) 702 } 703 c := &Client{Transport: &Transport{Proxy: ProxyURL(pu)}} 704 c.Head(ts.URL) 705 got := <-ch 706 want := "proxy for " + ts.URL + "/" 707 if got != want { 708 t.Errorf("want %q, got %q", want, got) 709 } 710 } 711 712 // TestTransportGzipRecursive sends a gzip quine and checks that the 713 // client gets the same value back. This is more cute than anything, 714 // but checks that we don't recurse forever, and checks that 715 // Content-Encoding is removed. 716 func TestTransportGzipRecursive(t *testing.T) { 717 defer afterTest(t) 718 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 719 w.Header().Set("Content-Encoding", "gzip") 720 w.Write(rgz) 721 })) 722 defer ts.Close() 723 724 c := &Client{Transport: &Transport{}} 725 res, err := c.Get(ts.URL) 726 if err != nil { 727 t.Fatal(err) 728 } 729 body, err := ioutil.ReadAll(res.Body) 730 if err != nil { 731 t.Fatal(err) 732 } 733 if !bytes.Equal(body, rgz) { 734 t.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x", 735 body, rgz) 736 } 737 if g, e := res.Header.Get("Content-Encoding"), ""; g != e { 738 t.Fatalf("Content-Encoding = %q; want %q", g, e) 739 } 740 } 741 742 // tests that persistent goroutine connections shut down when no longer desired. 743 func TestTransportPersistConnLeak(t *testing.T) { 744 defer afterTest(t) 745 gotReqCh := make(chan bool) 746 unblockCh := make(chan bool) 747 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 748 gotReqCh <- true 749 <-unblockCh 750 w.Header().Set("Content-Length", "0") 751 w.WriteHeader(204) 752 })) 753 defer ts.Close() 754 755 tr := &Transport{} 756 c := &Client{Transport: tr} 757 758 n0 := runtime.NumGoroutine() 759 760 const numReq = 25 761 didReqCh := make(chan bool) 762 for i := 0; i < numReq; i++ { 763 go func() { 764 res, err := c.Get(ts.URL) 765 didReqCh <- true 766 if err != nil { 767 t.Errorf("client fetch error: %v", err) 768 return 769 } 770 res.Body.Close() 771 }() 772 } 773 774 // Wait for all goroutines to be stuck in the Handler. 775 for i := 0; i < numReq; i++ { 776 <-gotReqCh 777 } 778 779 nhigh := runtime.NumGoroutine() 780 781 // Tell all handlers to unblock and reply. 782 for i := 0; i < numReq; i++ { 783 unblockCh <- true 784 } 785 786 // Wait for all HTTP clients to be done. 787 for i := 0; i < numReq; i++ { 788 <-didReqCh 789 } 790 791 tr.CloseIdleConnections() 792 time.Sleep(100 * time.Millisecond) 793 runtime.GC() 794 runtime.GC() // even more. 795 nfinal := runtime.NumGoroutine() 796 797 growth := nfinal - n0 798 799 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5. 800 // Previously we were leaking one per numReq. 801 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth) 802 if int(growth) > 5 { 803 t.Error("too many new goroutines") 804 } 805 } 806 807 // golang.org/issue/4531: Transport leaks goroutines when 808 // request.ContentLength is explicitly short 809 func TestTransportPersistConnLeakShortBody(t *testing.T) { 810 defer afterTest(t) 811 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 812 })) 813 defer ts.Close() 814 815 tr := &Transport{} 816 c := &Client{Transport: tr} 817 818 n0 := runtime.NumGoroutine() 819 body := []byte("Hello") 820 for i := 0; i < 20; i++ { 821 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body)) 822 if err != nil { 823 t.Fatal(err) 824 } 825 req.ContentLength = int64(len(body) - 2) // explicitly short 826 _, err = c.Do(req) 827 if err == nil { 828 t.Fatal("Expect an error from writing too long of a body.") 829 } 830 } 831 nhigh := runtime.NumGoroutine() 832 tr.CloseIdleConnections() 833 time.Sleep(400 * time.Millisecond) 834 runtime.GC() 835 nfinal := runtime.NumGoroutine() 836 837 growth := nfinal - n0 838 839 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5. 840 // Previously we were leaking one per numReq. 841 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth) 842 if int(growth) > 5 { 843 t.Error("too many new goroutines") 844 } 845 } 846 847 // This used to crash; http://golang.org/issue/3266 848 func TestTransportIdleConnCrash(t *testing.T) { 849 defer afterTest(t) 850 tr := &Transport{} 851 c := &Client{Transport: tr} 852 853 unblockCh := make(chan bool, 1) 854 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 855 <-unblockCh 856 tr.CloseIdleConnections() 857 })) 858 defer ts.Close() 859 860 didreq := make(chan bool) 861 go func() { 862 res, err := c.Get(ts.URL) 863 if err != nil { 864 t.Error(err) 865 } else { 866 res.Body.Close() // returns idle conn 867 } 868 didreq <- true 869 }() 870 unblockCh <- true 871 <-didreq 872 } 873 874 // Test that the transport doesn't close the TCP connection early, 875 // before the response body has been read. This was a regression 876 // which sadly lacked a triggering test. The large response body made 877 // the old race easier to trigger. 878 func TestIssue3644(t *testing.T) { 879 defer afterTest(t) 880 const numFoos = 5000 881 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 882 w.Header().Set("Connection", "close") 883 for i := 0; i < numFoos; i++ { 884 w.Write([]byte("foo ")) 885 } 886 })) 887 defer ts.Close() 888 tr := &Transport{} 889 c := &Client{Transport: tr} 890 res, err := c.Get(ts.URL) 891 if err != nil { 892 t.Fatal(err) 893 } 894 defer res.Body.Close() 895 bs, err := ioutil.ReadAll(res.Body) 896 if err != nil { 897 t.Fatal(err) 898 } 899 if len(bs) != numFoos*len("foo ") { 900 t.Errorf("unexpected response length") 901 } 902 } 903 904 // Test that a client receives a server's reply, even if the server doesn't read 905 // the entire request body. 906 func TestIssue3595(t *testing.T) { 907 defer afterTest(t) 908 const deniedMsg = "sorry, denied." 909 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 910 Error(w, deniedMsg, StatusUnauthorized) 911 })) 912 defer ts.Close() 913 tr := &Transport{} 914 c := &Client{Transport: tr} 915 res, err := c.Post(ts.URL, "application/octet-stream", neverEnding('a')) 916 if err != nil { 917 t.Errorf("Post: %v", err) 918 return 919 } 920 got, err := ioutil.ReadAll(res.Body) 921 if err != nil { 922 t.Fatalf("Body ReadAll: %v", err) 923 } 924 if !strings.Contains(string(got), deniedMsg) { 925 t.Errorf("Known bug: response %q does not contain %q", got, deniedMsg) 926 } 927 } 928 929 // From http://golang.org/issue/4454 , 930 // "client fails to handle requests with no body and chunked encoding" 931 func TestChunkedNoContent(t *testing.T) { 932 defer afterTest(t) 933 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 934 w.WriteHeader(StatusNoContent) 935 })) 936 defer ts.Close() 937 938 for _, closeBody := range []bool{true, false} { 939 c := &Client{Transport: &Transport{}} 940 const n = 4 941 for i := 1; i <= n; i++ { 942 res, err := c.Get(ts.URL) 943 if err != nil { 944 t.Errorf("closingBody=%v, req %d/%d: %v", closeBody, i, n, err) 945 } else { 946 if closeBody { 947 res.Body.Close() 948 } 949 } 950 } 951 } 952 } 953 954 func TestTransportConcurrency(t *testing.T) { 955 defer afterTest(t) 956 maxProcs, numReqs := 16, 500 957 if testing.Short() { 958 maxProcs, numReqs = 4, 50 959 } 960 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) 961 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 962 fmt.Fprintf(w, "%v", r.FormValue("echo")) 963 })) 964 defer ts.Close() 965 966 var wg sync.WaitGroup 967 wg.Add(numReqs) 968 969 tr := &Transport{ 970 Dial: func(netw, addr string) (c net.Conn, err error) { 971 // Due to the Transport's "socket late 972 // binding" (see idleConnCh in transport.go), 973 // the numReqs HTTP requests below can finish 974 // with a dial still outstanding. So count 975 // our dials as work too so the leak checker 976 // doesn't complain at us. 977 wg.Add(1) 978 defer wg.Done() 979 return net.Dial(netw, addr) 980 }, 981 } 982 defer tr.CloseIdleConnections() 983 c := &Client{Transport: tr} 984 reqs := make(chan string) 985 defer close(reqs) 986 987 for i := 0; i < maxProcs*2; i++ { 988 go func() { 989 for req := range reqs { 990 res, err := c.Get(ts.URL + "/?echo=" + req) 991 if err != nil { 992 t.Errorf("error on req %s: %v", req, err) 993 wg.Done() 994 continue 995 } 996 all, err := ioutil.ReadAll(res.Body) 997 if err != nil { 998 t.Errorf("read error on req %s: %v", req, err) 999 wg.Done() 1000 continue 1001 } 1002 if string(all) != req { 1003 t.Errorf("body of req %s = %q; want %q", req, all, req) 1004 } 1005 res.Body.Close() 1006 wg.Done() 1007 } 1008 }() 1009 } 1010 for i := 0; i < numReqs; i++ { 1011 reqs <- fmt.Sprintf("request-%d", i) 1012 } 1013 wg.Wait() 1014 } 1015 1016 func TestIssue4191_InfiniteGetTimeout(t *testing.T) { 1017 defer afterTest(t) 1018 const debug = false 1019 mux := NewServeMux() 1020 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) { 1021 io.Copy(w, neverEnding('a')) 1022 }) 1023 ts := httptest.NewServer(mux) 1024 timeout := 100 * time.Millisecond 1025 1026 client := &Client{ 1027 Transport: &Transport{ 1028 Dial: func(n, addr string) (net.Conn, error) { 1029 conn, err := net.Dial(n, addr) 1030 if err != nil { 1031 return nil, err 1032 } 1033 conn.SetDeadline(time.Now().Add(timeout)) 1034 if debug { 1035 conn = NewLoggingConn("client", conn) 1036 } 1037 return conn, nil 1038 }, 1039 DisableKeepAlives: true, 1040 }, 1041 } 1042 1043 getFailed := false 1044 nRuns := 5 1045 if testing.Short() { 1046 nRuns = 1 1047 } 1048 for i := 0; i < nRuns; i++ { 1049 if debug { 1050 println("run", i+1, "of", nRuns) 1051 } 1052 sres, err := client.Get(ts.URL + "/get") 1053 if err != nil { 1054 if !getFailed { 1055 // Make the timeout longer, once. 1056 getFailed = true 1057 t.Logf("increasing timeout") 1058 i-- 1059 timeout *= 10 1060 continue 1061 } 1062 t.Errorf("Error issuing GET: %v", err) 1063 break 1064 } 1065 _, err = io.Copy(ioutil.Discard, sres.Body) 1066 if err == nil { 1067 t.Errorf("Unexpected successful copy") 1068 break 1069 } 1070 } 1071 if debug { 1072 println("tests complete; waiting for handlers to finish") 1073 } 1074 ts.Close() 1075 } 1076 1077 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) { 1078 defer afterTest(t) 1079 const debug = false 1080 mux := NewServeMux() 1081 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) { 1082 io.Copy(w, neverEnding('a')) 1083 }) 1084 mux.HandleFunc("/put", func(w ResponseWriter, r *Request) { 1085 defer r.Body.Close() 1086 io.Copy(ioutil.Discard, r.Body) 1087 }) 1088 ts := httptest.NewServer(mux) 1089 timeout := 100 * time.Millisecond 1090 1091 client := &Client{ 1092 Transport: &Transport{ 1093 Dial: func(n, addr string) (net.Conn, error) { 1094 conn, err := net.Dial(n, addr) 1095 if err != nil { 1096 return nil, err 1097 } 1098 conn.SetDeadline(time.Now().Add(timeout)) 1099 if debug { 1100 conn = NewLoggingConn("client", conn) 1101 } 1102 return conn, nil 1103 }, 1104 DisableKeepAlives: true, 1105 }, 1106 } 1107 1108 getFailed := false 1109 nRuns := 5 1110 if testing.Short() { 1111 nRuns = 1 1112 } 1113 for i := 0; i < nRuns; i++ { 1114 if debug { 1115 println("run", i+1, "of", nRuns) 1116 } 1117 sres, err := client.Get(ts.URL + "/get") 1118 if err != nil { 1119 if !getFailed { 1120 // Make the timeout longer, once. 1121 getFailed = true 1122 t.Logf("increasing timeout") 1123 i-- 1124 timeout *= 10 1125 continue 1126 } 1127 t.Errorf("Error issuing GET: %v", err) 1128 break 1129 } 1130 req, _ := NewRequest("PUT", ts.URL+"/put", sres.Body) 1131 _, err = client.Do(req) 1132 if err == nil { 1133 sres.Body.Close() 1134 t.Errorf("Unexpected successful PUT") 1135 break 1136 } 1137 sres.Body.Close() 1138 } 1139 if debug { 1140 println("tests complete; waiting for handlers to finish") 1141 } 1142 ts.Close() 1143 } 1144 1145 func TestTransportResponseHeaderTimeout(t *testing.T) { 1146 defer afterTest(t) 1147 if testing.Short() { 1148 t.Skip("skipping timeout test in -short mode") 1149 } 1150 mux := NewServeMux() 1151 mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {}) 1152 mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) { 1153 time.Sleep(2 * time.Second) 1154 }) 1155 ts := httptest.NewServer(mux) 1156 defer ts.Close() 1157 1158 tr := &Transport{ 1159 ResponseHeaderTimeout: 500 * time.Millisecond, 1160 } 1161 defer tr.CloseIdleConnections() 1162 c := &Client{Transport: tr} 1163 1164 tests := []struct { 1165 path string 1166 want int 1167 wantErr string 1168 }{ 1169 {path: "/fast", want: 200}, 1170 {path: "/slow", wantErr: "timeout awaiting response headers"}, 1171 {path: "/fast", want: 200}, 1172 } 1173 for i, tt := range tests { 1174 res, err := c.Get(ts.URL + tt.path) 1175 if err != nil { 1176 if strings.Contains(err.Error(), tt.wantErr) { 1177 continue 1178 } 1179 t.Errorf("%d. unexpected error: %v", i, err) 1180 continue 1181 } 1182 if tt.wantErr != "" { 1183 t.Errorf("%d. no error. expected error: %v", i, tt.wantErr) 1184 continue 1185 } 1186 if res.StatusCode != tt.want { 1187 t.Errorf("%d for path %q status = %d; want %d", i, tt.path, res.StatusCode, tt.want) 1188 } 1189 } 1190 } 1191 1192 func TestTransportCancelRequest(t *testing.T) { 1193 defer afterTest(t) 1194 if testing.Short() { 1195 t.Skip("skipping test in -short mode") 1196 } 1197 unblockc := make(chan bool) 1198 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1199 fmt.Fprintf(w, "Hello") 1200 w.(Flusher).Flush() // send headers and some body 1201 <-unblockc 1202 })) 1203 defer ts.Close() 1204 defer close(unblockc) 1205 1206 tr := &Transport{} 1207 defer tr.CloseIdleConnections() 1208 c := &Client{Transport: tr} 1209 1210 req, _ := NewRequest("GET", ts.URL, nil) 1211 res, err := c.Do(req) 1212 if err != nil { 1213 t.Fatal(err) 1214 } 1215 go func() { 1216 time.Sleep(1 * time.Second) 1217 tr.CancelRequest(req) 1218 }() 1219 t0 := time.Now() 1220 body, err := ioutil.ReadAll(res.Body) 1221 d := time.Since(t0) 1222 1223 if err == nil { 1224 t.Error("expected an error reading the body") 1225 } 1226 if string(body) != "Hello" { 1227 t.Errorf("Body = %q; want Hello", body) 1228 } 1229 if d < 500*time.Millisecond { 1230 t.Errorf("expected ~1 second delay; got %v", d) 1231 } 1232 // Verify no outstanding requests after readLoop/writeLoop 1233 // goroutines shut down. 1234 for tries := 3; tries > 0; tries-- { 1235 n := tr.NumPendingRequestsForTesting() 1236 if n == 0 { 1237 break 1238 } 1239 time.Sleep(100 * time.Millisecond) 1240 if tries == 1 { 1241 t.Errorf("pending requests = %d; want 0", n) 1242 } 1243 } 1244 } 1245 1246 // golang.org/issue/3672 -- Client can't close HTTP stream 1247 // Calling Close on a Response.Body used to just read until EOF. 1248 // Now it actually closes the TCP connection. 1249 func TestTransportCloseResponseBody(t *testing.T) { 1250 defer afterTest(t) 1251 writeErr := make(chan error, 1) 1252 msg := []byte("young\n") 1253 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1254 for { 1255 _, err := w.Write(msg) 1256 if err != nil { 1257 writeErr <- err 1258 return 1259 } 1260 w.(Flusher).Flush() 1261 } 1262 })) 1263 defer ts.Close() 1264 1265 tr := &Transport{} 1266 defer tr.CloseIdleConnections() 1267 c := &Client{Transport: tr} 1268 1269 req, _ := NewRequest("GET", ts.URL, nil) 1270 defer tr.CancelRequest(req) 1271 1272 res, err := c.Do(req) 1273 if err != nil { 1274 t.Fatal(err) 1275 } 1276 1277 const repeats = 3 1278 buf := make([]byte, len(msg)*repeats) 1279 want := bytes.Repeat(msg, repeats) 1280 1281 _, err = io.ReadFull(res.Body, buf) 1282 if err != nil { 1283 t.Fatal(err) 1284 } 1285 if !bytes.Equal(buf, want) { 1286 t.Errorf("read %q; want %q", buf, want) 1287 } 1288 didClose := make(chan error, 1) 1289 go func() { 1290 didClose <- res.Body.Close() 1291 }() 1292 select { 1293 case err := <-didClose: 1294 if err != nil { 1295 t.Errorf("Close = %v", err) 1296 } 1297 case <-time.After(10 * time.Second): 1298 t.Fatal("too long waiting for close") 1299 } 1300 select { 1301 case err := <-writeErr: 1302 if err == nil { 1303 t.Errorf("expected non-nil write error") 1304 } 1305 case <-time.After(10 * time.Second): 1306 t.Fatal("too long waiting for write error") 1307 } 1308 } 1309 1310 type fooProto struct{} 1311 1312 func (fooProto) RoundTrip(req *Request) (*Response, error) { 1313 res := &Response{ 1314 Status: "200 OK", 1315 StatusCode: 200, 1316 Header: make(Header), 1317 Body: ioutil.NopCloser(strings.NewReader("You wanted " + req.URL.String())), 1318 } 1319 return res, nil 1320 } 1321 1322 func TestTransportAltProto(t *testing.T) { 1323 defer afterTest(t) 1324 tr := &Transport{} 1325 c := &Client{Transport: tr} 1326 tr.RegisterProtocol("foo", fooProto{}) 1327 res, err := c.Get("foo://bar.com/path") 1328 if err != nil { 1329 t.Fatal(err) 1330 } 1331 bodyb, err := ioutil.ReadAll(res.Body) 1332 if err != nil { 1333 t.Fatal(err) 1334 } 1335 body := string(bodyb) 1336 if e := "You wanted foo://bar.com/path"; body != e { 1337 t.Errorf("got response %q, want %q", body, e) 1338 } 1339 } 1340 1341 func TestTransportNoHost(t *testing.T) { 1342 defer afterTest(t) 1343 tr := &Transport{} 1344 _, err := tr.RoundTrip(&Request{ 1345 Header: make(Header), 1346 URL: &url.URL{ 1347 Scheme: "http", 1348 }, 1349 }) 1350 want := "http: no Host in request URL" 1351 if got := fmt.Sprint(err); got != want { 1352 t.Errorf("error = %v; want %q", err, want) 1353 } 1354 } 1355 1356 func TestTransportSocketLateBinding(t *testing.T) { 1357 defer afterTest(t) 1358 1359 mux := NewServeMux() 1360 fooGate := make(chan bool, 1) 1361 mux.HandleFunc("/foo", func(w ResponseWriter, r *Request) { 1362 w.Header().Set("foo-ipport", r.RemoteAddr) 1363 w.(Flusher).Flush() 1364 <-fooGate 1365 }) 1366 mux.HandleFunc("/bar", func(w ResponseWriter, r *Request) { 1367 w.Header().Set("bar-ipport", r.RemoteAddr) 1368 }) 1369 ts := httptest.NewServer(mux) 1370 defer ts.Close() 1371 1372 dialGate := make(chan bool, 1) 1373 tr := &Transport{ 1374 Dial: func(n, addr string) (net.Conn, error) { 1375 <-dialGate 1376 return net.Dial(n, addr) 1377 }, 1378 DisableKeepAlives: false, 1379 } 1380 defer tr.CloseIdleConnections() 1381 c := &Client{ 1382 Transport: tr, 1383 } 1384 1385 dialGate <- true // only allow one dial 1386 fooRes, err := c.Get(ts.URL + "/foo") 1387 if err != nil { 1388 t.Fatal(err) 1389 } 1390 fooAddr := fooRes.Header.Get("foo-ipport") 1391 if fooAddr == "" { 1392 t.Fatal("No addr on /foo request") 1393 } 1394 time.AfterFunc(200*time.Millisecond, func() { 1395 // let the foo response finish so we can use its 1396 // connection for /bar 1397 fooGate <- true 1398 io.Copy(ioutil.Discard, fooRes.Body) 1399 fooRes.Body.Close() 1400 }) 1401 1402 barRes, err := c.Get(ts.URL + "/bar") 1403 if err != nil { 1404 t.Fatal(err) 1405 } 1406 barAddr := barRes.Header.Get("bar-ipport") 1407 if barAddr != fooAddr { 1408 t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr) 1409 } 1410 barRes.Body.Close() 1411 dialGate <- true 1412 } 1413 1414 // Issue 2184 1415 func TestTransportReading100Continue(t *testing.T) { 1416 defer afterTest(t) 1417 1418 const numReqs = 5 1419 reqBody := func(n int) string { return fmt.Sprintf("request body %d", n) } 1420 reqID := func(n int) string { return fmt.Sprintf("REQ-ID-%d", n) } 1421 1422 send100Response := func(w *io.PipeWriter, r *io.PipeReader) { 1423 defer w.Close() 1424 defer r.Close() 1425 br := bufio.NewReader(r) 1426 n := 0 1427 for { 1428 n++ 1429 req, err := ReadRequest(br) 1430 if err == io.EOF { 1431 return 1432 } 1433 if err != nil { 1434 t.Error(err) 1435 return 1436 } 1437 slurp, err := ioutil.ReadAll(req.Body) 1438 if err != nil { 1439 t.Errorf("Server request body slurp: %v", err) 1440 return 1441 } 1442 id := req.Header.Get("Request-Id") 1443 resCode := req.Header.Get("X-Want-Response-Code") 1444 if resCode == "" { 1445 resCode = "100 Continue" 1446 if string(slurp) != reqBody(n) { 1447 t.Errorf("Server got %q, %v; want %q", slurp, err, reqBody(n)) 1448 } 1449 } 1450 body := fmt.Sprintf("Response number %d", n) 1451 v := []byte(strings.Replace(fmt.Sprintf(`HTTP/1.1 %s 1452 Date: Thu, 28 Feb 2013 17:55:41 GMT 1453 1454 HTTP/1.1 200 OK 1455 Content-Type: text/html 1456 Echo-Request-Id: %s 1457 Content-Length: %d 1458 1459 %s`, resCode, id, len(body), body), "\n", "\r\n", -1)) 1460 w.Write(v) 1461 if id == reqID(numReqs) { 1462 return 1463 } 1464 } 1465 1466 } 1467 1468 tr := &Transport{ 1469 Dial: func(n, addr string) (net.Conn, error) { 1470 sr, sw := io.Pipe() // server read/write 1471 cr, cw := io.Pipe() // client read/write 1472 conn := &rwTestConn{ 1473 Reader: cr, 1474 Writer: sw, 1475 closeFunc: func() error { 1476 sw.Close() 1477 cw.Close() 1478 return nil 1479 }, 1480 } 1481 go send100Response(cw, sr) 1482 return conn, nil 1483 }, 1484 DisableKeepAlives: false, 1485 } 1486 defer tr.CloseIdleConnections() 1487 c := &Client{Transport: tr} 1488 1489 testResponse := func(req *Request, name string, wantCode int) { 1490 res, err := c.Do(req) 1491 if err != nil { 1492 t.Fatalf("%s: Do: %v", name, err) 1493 } 1494 if res.StatusCode != wantCode { 1495 t.Fatalf("%s: Response Statuscode=%d; want %d", name, res.StatusCode, wantCode) 1496 } 1497 if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack { 1498 t.Errorf("%s: response id %q != request id %q", name, idBack, id) 1499 } 1500 _, err = ioutil.ReadAll(res.Body) 1501 if err != nil { 1502 t.Fatalf("%s: Slurp error: %v", name, err) 1503 } 1504 } 1505 1506 // Few 100 responses, making sure we're not off-by-one. 1507 for i := 1; i <= numReqs; i++ { 1508 req, _ := NewRequest("POST", "http://dummy.tld/", strings.NewReader(reqBody(i))) 1509 req.Header.Set("Request-Id", reqID(i)) 1510 testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200) 1511 } 1512 1513 // And some other informational 1xx but non-100 responses, to test 1514 // we return them but don't re-use the connection. 1515 for i := 1; i <= numReqs; i++ { 1516 req, _ := NewRequest("POST", "http://other.tld/", strings.NewReader(reqBody(i))) 1517 req.Header.Set("X-Want-Response-Code", "123 Sesame Street") 1518 testResponse(req, fmt.Sprintf("123, %d/%d", i, numReqs), 123) 1519 } 1520 } 1521 1522 type proxyFromEnvTest struct { 1523 req string // URL to fetch; blank means "http://example.com" 1524 env string 1525 noenv string 1526 want string 1527 wanterr error 1528 } 1529 1530 func (t proxyFromEnvTest) String() string { 1531 var buf bytes.Buffer 1532 if t.env != "" { 1533 fmt.Fprintf(&buf, "http_proxy=%q", t.env) 1534 } 1535 if t.noenv != "" { 1536 fmt.Fprintf(&buf, " no_proxy=%q", t.noenv) 1537 } 1538 req := "http://example.com" 1539 if t.req != "" { 1540 req = t.req 1541 } 1542 fmt.Fprintf(&buf, " req=%q", req) 1543 return strings.TrimSpace(buf.String()) 1544 } 1545 1546 var proxyFromEnvTests = []proxyFromEnvTest{ 1547 {env: "127.0.0.1:8080", want: "http://127.0.0.1:8080"}, 1548 {env: "cache.corp.example.com:1234", want: "http://cache.corp.example.com:1234"}, 1549 {env: "cache.corp.example.com", want: "http://cache.corp.example.com"}, 1550 {env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"}, 1551 {env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"}, 1552 {env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"}, 1553 {want: "<nil>"}, 1554 {noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"}, 1555 {noenv: ".example.com", req: "http://example.com/", env: "proxy", want: "<nil>"}, 1556 {noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 1557 {noenv: "example.com", req: "http://foo.example.com/", env: "proxy", want: "<nil>"}, 1558 {noenv: ".foo.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 1559 } 1560 1561 func TestProxyFromEnvironment(t *testing.T) { 1562 os.Setenv("HTTP_PROXY", "") 1563 os.Setenv("http_proxy", "") 1564 os.Setenv("NO_PROXY", "") 1565 os.Setenv("no_proxy", "") 1566 for _, tt := range proxyFromEnvTests { 1567 os.Setenv("HTTP_PROXY", tt.env) 1568 os.Setenv("NO_PROXY", tt.noenv) 1569 reqURL := tt.req 1570 if reqURL == "" { 1571 reqURL = "http://example.com" 1572 } 1573 req, _ := NewRequest("GET", reqURL, nil) 1574 url, err := ProxyFromEnvironment(req) 1575 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e { 1576 t.Errorf("%v: got error = %q, want %q", tt, g, e) 1577 continue 1578 } 1579 if got := fmt.Sprintf("%s", url); got != tt.want { 1580 t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want) 1581 } 1582 } 1583 } 1584 1585 func TestIdleConnChannelLeak(t *testing.T) { 1586 var mu sync.Mutex 1587 var n int 1588 1589 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1590 mu.Lock() 1591 n++ 1592 mu.Unlock() 1593 })) 1594 defer ts.Close() 1595 1596 tr := &Transport{ 1597 Dial: func(netw, addr string) (net.Conn, error) { 1598 return net.Dial(netw, ts.Listener.Addr().String()) 1599 }, 1600 } 1601 defer tr.CloseIdleConnections() 1602 1603 c := &Client{Transport: tr} 1604 1605 // First, without keep-alives. 1606 for _, disableKeep := range []bool{true, false} { 1607 tr.DisableKeepAlives = disableKeep 1608 for i := 0; i < 5; i++ { 1609 _, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i)) 1610 if err != nil { 1611 t.Fatal(err) 1612 } 1613 } 1614 if got := tr.IdleConnChMapSizeForTesting(); got != 0 { 1615 t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got) 1616 } 1617 } 1618 } 1619 1620 // Verify the status quo: that the Client.Post function coerces its 1621 // body into a ReadCloser if it's a Closer, and that the Transport 1622 // then closes it. 1623 func TestTransportClosesRequestBody(t *testing.T) { 1624 defer afterTest(t) 1625 ts := httptest.NewServer(http.HandlerFunc(func(w ResponseWriter, r *Request) { 1626 io.Copy(ioutil.Discard, r.Body) 1627 })) 1628 defer ts.Close() 1629 1630 tr := &Transport{} 1631 defer tr.CloseIdleConnections() 1632 cl := &Client{Transport: tr} 1633 1634 closes := 0 1635 1636 res, err := cl.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")}) 1637 if err != nil { 1638 t.Fatal(err) 1639 } 1640 res.Body.Close() 1641 if closes != 1 { 1642 t.Errorf("closes = %d; want 1", closes) 1643 } 1644 } 1645 1646 type countCloseReader struct { 1647 n *int 1648 io.Reader 1649 } 1650 1651 func (cr countCloseReader) Close() error { 1652 (*cr.n)++ 1653 return nil 1654 } 1655 1656 // rgz is a gzip quine that uncompresses to itself. 1657 var rgz = []byte{ 1658 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 1659 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 1660 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0, 1661 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 1662 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 1663 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60, 1664 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2, 1665 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00, 1666 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 1667 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16, 1668 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05, 1669 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff, 1670 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00, 1671 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 1672 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 1673 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 1674 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 1675 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 1676 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 1677 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 1678 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 1679 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff, 1680 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00, 1681 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 1682 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 1683 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 1684 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 1685 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06, 1686 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00, 1687 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 1688 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 1689 0x00, 0x00, 1690 }