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