github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/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 "crypto/tls" 15 "errors" 16 "fmt" 17 "io" 18 "io/ioutil" 19 "log" 20 "net" 21 "net/http" 22 . "net/http" 23 "net/http/httptest" 24 "net/url" 25 "os" 26 "runtime" 27 "strconv" 28 "strings" 29 "sync" 30 "testing" 31 "time" 32 ) 33 34 // TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close 35 // and then verify that the final 2 responses get errors back. 36 37 // hostPortHandler writes back the client's "host:port". 38 var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 39 if r.FormValue("close") == "true" { 40 w.Header().Set("Connection", "close") 41 } 42 w.Write([]byte(r.RemoteAddr)) 43 }) 44 45 // testCloseConn is a net.Conn tracked by a testConnSet. 46 type testCloseConn struct { 47 net.Conn 48 set *testConnSet 49 } 50 51 func (c *testCloseConn) Close() error { 52 c.set.remove(c) 53 return c.Conn.Close() 54 } 55 56 // testConnSet tracks a set of TCP connections and whether they've 57 // been closed. 58 type testConnSet struct { 59 t *testing.T 60 mu sync.Mutex // guards closed and list 61 closed map[net.Conn]bool 62 list []net.Conn // in order created 63 } 64 65 func (tcs *testConnSet) insert(c net.Conn) { 66 tcs.mu.Lock() 67 defer tcs.mu.Unlock() 68 tcs.closed[c] = false 69 tcs.list = append(tcs.list, c) 70 } 71 72 func (tcs *testConnSet) remove(c net.Conn) { 73 tcs.mu.Lock() 74 defer tcs.mu.Unlock() 75 tcs.closed[c] = true 76 } 77 78 // some tests use this to manage raw tcp connections for later inspection 79 func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, error)) { 80 connSet := &testConnSet{ 81 t: t, 82 closed: make(map[net.Conn]bool), 83 } 84 dial := func(n, addr string) (net.Conn, error) { 85 c, err := net.Dial(n, addr) 86 if err != nil { 87 return nil, err 88 } 89 tc := &testCloseConn{c, connSet} 90 connSet.insert(tc) 91 return tc, nil 92 } 93 return connSet, dial 94 } 95 96 func (tcs *testConnSet) check(t *testing.T) { 97 tcs.mu.Lock() 98 defer tcs.mu.Unlock() 99 for i := 4; i >= 0; i-- { 100 for i, c := range tcs.list { 101 if tcs.closed[c] { 102 continue 103 } 104 if i != 0 { 105 tcs.mu.Unlock() 106 time.Sleep(50 * time.Millisecond) 107 tcs.mu.Lock() 108 continue 109 } 110 t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list)) 111 } 112 } 113 } 114 115 // Two subsequent requests and verify their response is the same. 116 // The response from the server is our own IP:port 117 func TestTransportKeepAlives(t *testing.T) { 118 defer afterTest(t) 119 ts := httptest.NewServer(hostPortHandler) 120 defer ts.Close() 121 122 for _, disableKeepAlive := range []bool{false, true} { 123 tr := &Transport{DisableKeepAlives: disableKeepAlive} 124 defer tr.CloseIdleConnections() 125 c := &Client{Transport: tr} 126 127 fetch := func(n int) string { 128 res, err := c.Get(ts.URL) 129 if err != nil { 130 t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err) 131 } 132 body, err := ioutil.ReadAll(res.Body) 133 if err != nil { 134 t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err) 135 } 136 return string(body) 137 } 138 139 body1 := fetch(1) 140 body2 := fetch(2) 141 142 bodiesDiffer := body1 != body2 143 if bodiesDiffer != disableKeepAlive { 144 t.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 145 disableKeepAlive, bodiesDiffer, body1, body2) 146 } 147 } 148 } 149 150 func TestTransportConnectionCloseOnResponse(t *testing.T) { 151 defer afterTest(t) 152 ts := httptest.NewServer(hostPortHandler) 153 defer ts.Close() 154 155 connSet, testDial := makeTestDial(t) 156 157 for _, connectionClose := range []bool{false, true} { 158 tr := &Transport{ 159 Dial: testDial, 160 } 161 c := &Client{Transport: tr} 162 163 fetch := func(n int) string { 164 req := new(Request) 165 var err error 166 req.URL, err = url.Parse(ts.URL + fmt.Sprintf("/?close=%v", connectionClose)) 167 if err != nil { 168 t.Fatalf("URL parse error: %v", err) 169 } 170 req.Method = "GET" 171 req.Proto = "HTTP/1.1" 172 req.ProtoMajor = 1 173 req.ProtoMinor = 1 174 175 res, err := c.Do(req) 176 if err != nil { 177 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) 178 } 179 defer res.Body.Close() 180 body, err := ioutil.ReadAll(res.Body) 181 if err != nil { 182 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) 183 } 184 return string(body) 185 } 186 187 body1 := fetch(1) 188 body2 := fetch(2) 189 bodiesDiffer := body1 != body2 190 if bodiesDiffer != connectionClose { 191 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 192 connectionClose, bodiesDiffer, body1, body2) 193 } 194 195 tr.CloseIdleConnections() 196 } 197 198 connSet.check(t) 199 } 200 201 func TestTransportConnectionCloseOnRequest(t *testing.T) { 202 defer afterTest(t) 203 ts := httptest.NewServer(hostPortHandler) 204 defer ts.Close() 205 206 connSet, testDial := makeTestDial(t) 207 208 for _, connectionClose := range []bool{false, true} { 209 tr := &Transport{ 210 Dial: testDial, 211 } 212 c := &Client{Transport: tr} 213 214 fetch := func(n int) string { 215 req := new(Request) 216 var err error 217 req.URL, err = url.Parse(ts.URL) 218 if err != nil { 219 t.Fatalf("URL parse error: %v", err) 220 } 221 req.Method = "GET" 222 req.Proto = "HTTP/1.1" 223 req.ProtoMajor = 1 224 req.ProtoMinor = 1 225 req.Close = connectionClose 226 227 res, err := c.Do(req) 228 if err != nil { 229 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) 230 } 231 body, err := ioutil.ReadAll(res.Body) 232 if err != nil { 233 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) 234 } 235 return string(body) 236 } 237 238 body1 := fetch(1) 239 body2 := fetch(2) 240 bodiesDiffer := body1 != body2 241 if bodiesDiffer != connectionClose { 242 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 243 connectionClose, bodiesDiffer, body1, body2) 244 } 245 246 tr.CloseIdleConnections() 247 } 248 249 connSet.check(t) 250 } 251 252 func TestTransportIdleCacheKeys(t *testing.T) { 253 defer afterTest(t) 254 ts := httptest.NewServer(hostPortHandler) 255 defer ts.Close() 256 257 tr := &Transport{DisableKeepAlives: false} 258 c := &Client{Transport: tr} 259 260 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 261 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) 262 } 263 264 resp, err := c.Get(ts.URL) 265 if err != nil { 266 t.Error(err) 267 } 268 ioutil.ReadAll(resp.Body) 269 270 keys := tr.IdleConnKeysForTesting() 271 if e, g := 1, len(keys); e != g { 272 t.Fatalf("After Get expected %d idle conn cache keys; got %d", e, g) 273 } 274 275 if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e { 276 t.Errorf("Expected idle cache key %q; got %q", e, keys[0]) 277 } 278 279 tr.CloseIdleConnections() 280 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 281 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) 282 } 283 } 284 285 // Tests that the HTTP transport re-uses connections when a client 286 // reads to the end of a response Body without closing it. 287 func TestTransportReadToEndReusesConn(t *testing.T) { 288 defer afterTest(t) 289 const msg = "foobar" 290 291 var addrSeen map[string]int 292 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 293 addrSeen[r.RemoteAddr]++ 294 if r.URL.Path == "/chunked/" { 295 w.WriteHeader(200) 296 w.(http.Flusher).Flush() 297 } else { 298 w.Header().Set("Content-Type", strconv.Itoa(len(msg))) 299 w.WriteHeader(200) 300 } 301 w.Write([]byte(msg)) 302 })) 303 defer ts.Close() 304 305 buf := make([]byte, len(msg)) 306 307 for pi, path := range []string{"/content-length/", "/chunked/"} { 308 wantLen := []int{len(msg), -1}[pi] 309 addrSeen = make(map[string]int) 310 for i := 0; i < 3; i++ { 311 res, err := http.Get(ts.URL + path) 312 if err != nil { 313 t.Errorf("Get %s: %v", path, err) 314 continue 315 } 316 // We want to close this body eventually (before the 317 // defer afterTest at top runs), but not before the 318 // len(addrSeen) check at the bottom of this test, 319 // since Closing this early in the loop would risk 320 // making connections be re-used for the wrong reason. 321 defer res.Body.Close() 322 323 if res.ContentLength != int64(wantLen) { 324 t.Errorf("%s res.ContentLength = %d; want %d", path, res.ContentLength, wantLen) 325 } 326 n, err := res.Body.Read(buf) 327 if n != len(msg) || err != io.EOF { 328 t.Errorf("%s Read = %v, %v; want %d, EOF", path, n, err, len(msg)) 329 } 330 } 331 if len(addrSeen) != 1 { 332 t.Errorf("for %s, server saw %d distinct client addresses; want 1", path, len(addrSeen)) 333 } 334 } 335 } 336 337 func TestTransportMaxPerHostIdleConns(t *testing.T) { 338 defer afterTest(t) 339 resch := make(chan string) 340 gotReq := make(chan bool) 341 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 342 gotReq <- true 343 msg := <-resch 344 _, err := w.Write([]byte(msg)) 345 if err != nil { 346 t.Fatalf("Write: %v", err) 347 } 348 })) 349 defer ts.Close() 350 maxIdleConns := 2 351 tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns} 352 c := &Client{Transport: tr} 353 354 // Start 3 outstanding requests and wait for the server to get them. 355 // Their responses will hang until we write to resch, though. 356 donech := make(chan bool) 357 doReq := func() { 358 resp, err := c.Get(ts.URL) 359 if err != nil { 360 t.Error(err) 361 return 362 } 363 if _, err := ioutil.ReadAll(resp.Body); err != nil { 364 t.Errorf("ReadAll: %v", err) 365 return 366 } 367 donech <- true 368 } 369 go doReq() 370 <-gotReq 371 go doReq() 372 <-gotReq 373 go doReq() 374 <-gotReq 375 376 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 377 t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g) 378 } 379 380 resch <- "res1" 381 <-donech 382 keys := tr.IdleConnKeysForTesting() 383 if e, g := 1, len(keys); e != g { 384 t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g) 385 } 386 cacheKey := "|http|" + ts.Listener.Addr().String() 387 if keys[0] != cacheKey { 388 t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0]) 389 } 390 if e, g := 1, tr.IdleConnCountForTesting(cacheKey); e != g { 391 t.Errorf("after first response, expected %d idle conns; got %d", e, g) 392 } 393 394 resch <- "res2" 395 <-donech 396 if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g { 397 t.Errorf("after second response, expected %d idle conns; got %d", e, g) 398 } 399 400 resch <- "res3" 401 <-donech 402 if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g { 403 t.Errorf("after third response, still expected %d idle conns; got %d", e, g) 404 } 405 } 406 407 func TestTransportServerClosingUnexpectedly(t *testing.T) { 408 defer afterTest(t) 409 ts := httptest.NewServer(hostPortHandler) 410 defer ts.Close() 411 412 tr := &Transport{} 413 c := &Client{Transport: tr} 414 415 fetch := func(n, retries int) string { 416 condFatalf := func(format string, arg ...interface{}) { 417 if retries <= 0 { 418 t.Fatalf(format, arg...) 419 } 420 t.Logf("retrying shortly after expected error: "+format, arg...) 421 time.Sleep(time.Second / time.Duration(retries)) 422 } 423 for retries >= 0 { 424 retries-- 425 res, err := c.Get(ts.URL) 426 if err != nil { 427 condFatalf("error in req #%d, GET: %v", n, err) 428 continue 429 } 430 body, err := ioutil.ReadAll(res.Body) 431 if err != nil { 432 condFatalf("error in req #%d, ReadAll: %v", n, err) 433 continue 434 } 435 res.Body.Close() 436 return string(body) 437 } 438 panic("unreachable") 439 } 440 441 body1 := fetch(1, 0) 442 body2 := fetch(2, 0) 443 444 ts.CloseClientConnections() // surprise! 445 446 // This test has an expected race. Sleeping for 25 ms prevents 447 // it on most fast machines, causing the next fetch() call to 448 // succeed quickly. But if we do get errors, fetch() will retry 5 449 // times with some delays between. 450 time.Sleep(25 * time.Millisecond) 451 452 body3 := fetch(3, 5) 453 454 if body1 != body2 { 455 t.Errorf("expected body1 and body2 to be equal") 456 } 457 if body2 == body3 { 458 t.Errorf("expected body2 and body3 to be different") 459 } 460 } 461 462 // Test for http://golang.org/issue/2616 (appropriate issue number) 463 // This fails pretty reliably with GOMAXPROCS=100 or something high. 464 func TestStressSurpriseServerCloses(t *testing.T) { 465 defer afterTest(t) 466 if testing.Short() { 467 t.Skip("skipping test in short mode") 468 } 469 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 470 w.Header().Set("Content-Length", "5") 471 w.Header().Set("Content-Type", "text/plain") 472 w.Write([]byte("Hello")) 473 w.(Flusher).Flush() 474 conn, buf, _ := w.(Hijacker).Hijack() 475 buf.Flush() 476 conn.Close() 477 })) 478 defer ts.Close() 479 480 tr := &Transport{DisableKeepAlives: false} 481 c := &Client{Transport: tr} 482 483 // Do a bunch of traffic from different goroutines. Send to activityc 484 // after each request completes, regardless of whether it failed. 485 const ( 486 numClients = 50 487 reqsPerClient = 250 488 ) 489 activityc := make(chan bool) 490 for i := 0; i < numClients; i++ { 491 go func() { 492 for i := 0; i < reqsPerClient; i++ { 493 res, err := c.Get(ts.URL) 494 if err == nil { 495 // We expect errors since the server is 496 // hanging up on us after telling us to 497 // send more requests, so we don't 498 // actually care what the error is. 499 // But we want to close the body in cases 500 // where we won the race. 501 res.Body.Close() 502 } 503 activityc <- true 504 } 505 }() 506 } 507 508 // Make sure all the request come back, one way or another. 509 for i := 0; i < numClients*reqsPerClient; i++ { 510 select { 511 case <-activityc: 512 case <-time.After(5 * time.Second): 513 t.Fatalf("presumed deadlock; no HTTP client activity seen in awhile") 514 } 515 } 516 } 517 518 // TestTransportHeadResponses verifies that we deal with Content-Lengths 519 // with no bodies properly 520 func TestTransportHeadResponses(t *testing.T) { 521 defer afterTest(t) 522 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 523 if r.Method != "HEAD" { 524 panic("expected HEAD; got " + r.Method) 525 } 526 w.Header().Set("Content-Length", "123") 527 w.WriteHeader(200) 528 })) 529 defer ts.Close() 530 531 tr := &Transport{DisableKeepAlives: false} 532 c := &Client{Transport: tr} 533 for i := 0; i < 2; i++ { 534 res, err := c.Head(ts.URL) 535 if err != nil { 536 t.Errorf("error on loop %d: %v", i, err) 537 continue 538 } 539 if e, g := "123", res.Header.Get("Content-Length"); e != g { 540 t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g) 541 } 542 if e, g := int64(123), res.ContentLength; e != g { 543 t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g) 544 } 545 if all, err := ioutil.ReadAll(res.Body); err != nil { 546 t.Errorf("loop %d: Body ReadAll: %v", i, err) 547 } else if len(all) != 0 { 548 t.Errorf("Bogus body %q", all) 549 } 550 } 551 } 552 553 // TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding 554 // on responses to HEAD requests. 555 func TestTransportHeadChunkedResponse(t *testing.T) { 556 defer afterTest(t) 557 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 558 if r.Method != "HEAD" { 559 panic("expected HEAD; got " + r.Method) 560 } 561 w.Header().Set("Transfer-Encoding", "chunked") // client should ignore 562 w.Header().Set("x-client-ipport", r.RemoteAddr) 563 w.WriteHeader(200) 564 })) 565 defer ts.Close() 566 567 tr := &Transport{DisableKeepAlives: false} 568 c := &Client{Transport: tr} 569 570 res1, err := c.Head(ts.URL) 571 if err != nil { 572 t.Fatalf("request 1 error: %v", err) 573 } 574 res2, err := c.Head(ts.URL) 575 if err != nil { 576 t.Fatalf("request 2 error: %v", err) 577 } 578 if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 { 579 t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2) 580 } 581 } 582 583 var roundTripTests = []struct { 584 accept string 585 expectAccept string 586 compressed bool 587 }{ 588 // Requests with no accept-encoding header use transparent compression 589 {"", "gzip", false}, 590 // Requests with other accept-encoding should pass through unmodified 591 {"foo", "foo", false}, 592 // Requests with accept-encoding == gzip should be passed through 593 {"gzip", "gzip", true}, 594 } 595 596 // Test that the modification made to the Request by the RoundTripper is cleaned up 597 func TestRoundTripGzip(t *testing.T) { 598 defer afterTest(t) 599 const responseBody = "test response body" 600 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 601 accept := req.Header.Get("Accept-Encoding") 602 if expect := req.FormValue("expect_accept"); accept != expect { 603 t.Errorf("in handler, test %v: Accept-Encoding = %q, want %q", 604 req.FormValue("testnum"), accept, expect) 605 } 606 if accept == "gzip" { 607 rw.Header().Set("Content-Encoding", "gzip") 608 gz := gzip.NewWriter(rw) 609 gz.Write([]byte(responseBody)) 610 gz.Close() 611 } else { 612 rw.Header().Set("Content-Encoding", accept) 613 rw.Write([]byte(responseBody)) 614 } 615 })) 616 defer ts.Close() 617 618 for i, test := range roundTripTests { 619 // Test basic request (no accept-encoding) 620 req, _ := NewRequest("GET", fmt.Sprintf("%s/?testnum=%d&expect_accept=%s", ts.URL, i, test.expectAccept), nil) 621 if test.accept != "" { 622 req.Header.Set("Accept-Encoding", test.accept) 623 } 624 res, err := DefaultTransport.RoundTrip(req) 625 var body []byte 626 if test.compressed { 627 var r *gzip.Reader 628 r, err = gzip.NewReader(res.Body) 629 if err != nil { 630 t.Errorf("%d. gzip NewReader: %v", i, err) 631 continue 632 } 633 body, err = ioutil.ReadAll(r) 634 res.Body.Close() 635 } else { 636 body, err = ioutil.ReadAll(res.Body) 637 } 638 if err != nil { 639 t.Errorf("%d. Error: %q", i, err) 640 continue 641 } 642 if g, e := string(body), responseBody; g != e { 643 t.Errorf("%d. body = %q; want %q", i, g, e) 644 } 645 if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e { 646 t.Errorf("%d. Accept-Encoding = %q; want %q (it was mutated, in violation of RoundTrip contract)", i, g, e) 647 } 648 if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e { 649 t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e) 650 } 651 } 652 653 } 654 655 func TestTransportGzip(t *testing.T) { 656 defer afterTest(t) 657 const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 658 const nRandBytes = 1024 * 1024 659 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 660 if req.Method == "HEAD" { 661 if g := req.Header.Get("Accept-Encoding"); g != "" { 662 t.Errorf("HEAD request sent with Accept-Encoding of %q; want none", g) 663 } 664 return 665 } 666 if g, e := req.Header.Get("Accept-Encoding"), "gzip"; g != e { 667 t.Errorf("Accept-Encoding = %q, want %q", g, e) 668 } 669 rw.Header().Set("Content-Encoding", "gzip") 670 671 var w io.Writer = rw 672 var buf bytes.Buffer 673 if req.FormValue("chunked") == "0" { 674 w = &buf 675 defer io.Copy(rw, &buf) 676 defer func() { 677 rw.Header().Set("Content-Length", strconv.Itoa(buf.Len())) 678 }() 679 } 680 gz := gzip.NewWriter(w) 681 gz.Write([]byte(testString)) 682 if req.FormValue("body") == "large" { 683 io.CopyN(gz, rand.Reader, nRandBytes) 684 } 685 gz.Close() 686 })) 687 defer ts.Close() 688 689 for _, chunked := range []string{"1", "0"} { 690 c := &Client{Transport: &Transport{}} 691 692 // First fetch something large, but only read some of it. 693 res, err := c.Get(ts.URL + "/?body=large&chunked=" + chunked) 694 if err != nil { 695 t.Fatalf("large get: %v", err) 696 } 697 buf := make([]byte, len(testString)) 698 n, err := io.ReadFull(res.Body, buf) 699 if err != nil { 700 t.Fatalf("partial read of large response: size=%d, %v", n, err) 701 } 702 if e, g := testString, string(buf); e != g { 703 t.Errorf("partial read got %q, expected %q", g, e) 704 } 705 res.Body.Close() 706 // Read on the body, even though it's closed 707 n, err = res.Body.Read(buf) 708 if n != 0 || err == nil { 709 t.Errorf("expected error post-closed large Read; got = %d, %v", n, err) 710 } 711 712 // Then something small. 713 res, err = c.Get(ts.URL + "/?chunked=" + chunked) 714 if err != nil { 715 t.Fatal(err) 716 } 717 body, err := ioutil.ReadAll(res.Body) 718 if err != nil { 719 t.Fatal(err) 720 } 721 if g, e := string(body), testString; g != e { 722 t.Fatalf("body = %q; want %q", g, e) 723 } 724 if g, e := res.Header.Get("Content-Encoding"), ""; g != e { 725 t.Fatalf("Content-Encoding = %q; want %q", g, e) 726 } 727 728 // Read on the body after it's been fully read: 729 n, err = res.Body.Read(buf) 730 if n != 0 || err == nil { 731 t.Errorf("expected Read error after exhausted reads; got %d, %v", n, err) 732 } 733 res.Body.Close() 734 n, err = res.Body.Read(buf) 735 if n != 0 || err == nil { 736 t.Errorf("expected Read error after Close; got %d, %v", n, err) 737 } 738 } 739 740 // And a HEAD request too, because they're always weird. 741 c := &Client{Transport: &Transport{}} 742 res, err := c.Head(ts.URL) 743 if err != nil { 744 t.Fatalf("Head: %v", err) 745 } 746 if res.StatusCode != 200 { 747 t.Errorf("Head status=%d; want=200", res.StatusCode) 748 } 749 } 750 751 func TestTransportProxy(t *testing.T) { 752 defer afterTest(t) 753 ch := make(chan string, 1) 754 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 755 ch <- "real server" 756 })) 757 defer ts.Close() 758 proxy := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 759 ch <- "proxy for " + r.URL.String() 760 })) 761 defer proxy.Close() 762 763 pu, err := url.Parse(proxy.URL) 764 if err != nil { 765 t.Fatal(err) 766 } 767 c := &Client{Transport: &Transport{Proxy: ProxyURL(pu)}} 768 c.Head(ts.URL) 769 got := <-ch 770 want := "proxy for " + ts.URL + "/" 771 if got != want { 772 t.Errorf("want %q, got %q", want, got) 773 } 774 } 775 776 // TestTransportGzipRecursive sends a gzip quine and checks that the 777 // client gets the same value back. This is more cute than anything, 778 // but checks that we don't recurse forever, and checks that 779 // Content-Encoding is removed. 780 func TestTransportGzipRecursive(t *testing.T) { 781 defer afterTest(t) 782 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 783 w.Header().Set("Content-Encoding", "gzip") 784 w.Write(rgz) 785 })) 786 defer ts.Close() 787 788 c := &Client{Transport: &Transport{}} 789 res, err := c.Get(ts.URL) 790 if err != nil { 791 t.Fatal(err) 792 } 793 body, err := ioutil.ReadAll(res.Body) 794 if err != nil { 795 t.Fatal(err) 796 } 797 if !bytes.Equal(body, rgz) { 798 t.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x", 799 body, rgz) 800 } 801 if g, e := res.Header.Get("Content-Encoding"), ""; g != e { 802 t.Fatalf("Content-Encoding = %q; want %q", g, e) 803 } 804 } 805 806 // golang.org/issue/7750: request fails when server replies with 807 // a short gzip body 808 func TestTransportGzipShort(t *testing.T) { 809 defer afterTest(t) 810 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 811 w.Header().Set("Content-Encoding", "gzip") 812 w.Write([]byte{0x1f, 0x8b}) 813 })) 814 defer ts.Close() 815 816 tr := &Transport{} 817 defer tr.CloseIdleConnections() 818 c := &Client{Transport: tr} 819 res, err := c.Get(ts.URL) 820 if err != nil { 821 t.Fatal(err) 822 } 823 defer res.Body.Close() 824 _, err = ioutil.ReadAll(res.Body) 825 if err == nil { 826 t.Fatal("Expect an error from reading a body.") 827 } 828 if err != io.ErrUnexpectedEOF { 829 t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err) 830 } 831 } 832 833 // tests that persistent goroutine connections shut down when no longer desired. 834 func TestTransportPersistConnLeak(t *testing.T) { 835 if runtime.GOOS == "plan9" { 836 t.Skip("skipping test; see http://golang.org/issue/7237") 837 } 838 defer afterTest(t) 839 gotReqCh := make(chan bool) 840 unblockCh := make(chan bool) 841 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 842 gotReqCh <- true 843 <-unblockCh 844 w.Header().Set("Content-Length", "0") 845 w.WriteHeader(204) 846 })) 847 defer ts.Close() 848 849 tr := &Transport{} 850 c := &Client{Transport: tr} 851 852 n0 := runtime.NumGoroutine() 853 854 const numReq = 25 855 didReqCh := make(chan bool) 856 for i := 0; i < numReq; i++ { 857 go func() { 858 res, err := c.Get(ts.URL) 859 didReqCh <- true 860 if err != nil { 861 t.Errorf("client fetch error: %v", err) 862 return 863 } 864 res.Body.Close() 865 }() 866 } 867 868 // Wait for all goroutines to be stuck in the Handler. 869 for i := 0; i < numReq; i++ { 870 <-gotReqCh 871 } 872 873 nhigh := runtime.NumGoroutine() 874 875 // Tell all handlers to unblock and reply. 876 for i := 0; i < numReq; i++ { 877 unblockCh <- true 878 } 879 880 // Wait for all HTTP clients to be done. 881 for i := 0; i < numReq; i++ { 882 <-didReqCh 883 } 884 885 tr.CloseIdleConnections() 886 time.Sleep(100 * time.Millisecond) 887 runtime.GC() 888 runtime.GC() // even more. 889 nfinal := runtime.NumGoroutine() 890 891 growth := nfinal - n0 892 893 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5. 894 // Previously we were leaking one per numReq. 895 if int(growth) > 5 { 896 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth) 897 t.Error("too many new goroutines") 898 } 899 } 900 901 // golang.org/issue/4531: Transport leaks goroutines when 902 // request.ContentLength is explicitly short 903 func TestTransportPersistConnLeakShortBody(t *testing.T) { 904 if runtime.GOOS == "plan9" { 905 t.Skip("skipping test; see http://golang.org/issue/7237") 906 } 907 defer afterTest(t) 908 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 909 })) 910 defer ts.Close() 911 912 tr := &Transport{} 913 c := &Client{Transport: tr} 914 915 n0 := runtime.NumGoroutine() 916 body := []byte("Hello") 917 for i := 0; i < 20; i++ { 918 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body)) 919 if err != nil { 920 t.Fatal(err) 921 } 922 req.ContentLength = int64(len(body) - 2) // explicitly short 923 _, err = c.Do(req) 924 if err == nil { 925 t.Fatal("Expect an error from writing too long of a body.") 926 } 927 } 928 nhigh := runtime.NumGoroutine() 929 tr.CloseIdleConnections() 930 time.Sleep(400 * time.Millisecond) 931 runtime.GC() 932 nfinal := runtime.NumGoroutine() 933 934 growth := nfinal - n0 935 936 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5. 937 // Previously we were leaking one per numReq. 938 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth) 939 if int(growth) > 5 { 940 t.Error("too many new goroutines") 941 } 942 } 943 944 // This used to crash; http://golang.org/issue/3266 945 func TestTransportIdleConnCrash(t *testing.T) { 946 defer afterTest(t) 947 tr := &Transport{} 948 c := &Client{Transport: tr} 949 950 unblockCh := make(chan bool, 1) 951 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 952 <-unblockCh 953 tr.CloseIdleConnections() 954 })) 955 defer ts.Close() 956 957 didreq := make(chan bool) 958 go func() { 959 res, err := c.Get(ts.URL) 960 if err != nil { 961 t.Error(err) 962 } else { 963 res.Body.Close() // returns idle conn 964 } 965 didreq <- true 966 }() 967 unblockCh <- true 968 <-didreq 969 } 970 971 // Test that the transport doesn't close the TCP connection early, 972 // before the response body has been read. This was a regression 973 // which sadly lacked a triggering test. The large response body made 974 // the old race easier to trigger. 975 func TestIssue3644(t *testing.T) { 976 defer afterTest(t) 977 const numFoos = 5000 978 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 979 w.Header().Set("Connection", "close") 980 for i := 0; i < numFoos; i++ { 981 w.Write([]byte("foo ")) 982 } 983 })) 984 defer ts.Close() 985 tr := &Transport{} 986 c := &Client{Transport: tr} 987 res, err := c.Get(ts.URL) 988 if err != nil { 989 t.Fatal(err) 990 } 991 defer res.Body.Close() 992 bs, err := ioutil.ReadAll(res.Body) 993 if err != nil { 994 t.Fatal(err) 995 } 996 if len(bs) != numFoos*len("foo ") { 997 t.Errorf("unexpected response length") 998 } 999 } 1000 1001 // Test that a client receives a server's reply, even if the server doesn't read 1002 // the entire request body. 1003 func TestIssue3595(t *testing.T) { 1004 defer afterTest(t) 1005 const deniedMsg = "sorry, denied." 1006 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1007 Error(w, deniedMsg, StatusUnauthorized) 1008 })) 1009 defer ts.Close() 1010 tr := &Transport{} 1011 c := &Client{Transport: tr} 1012 res, err := c.Post(ts.URL, "application/octet-stream", neverEnding('a')) 1013 if err != nil { 1014 t.Errorf("Post: %v", err) 1015 return 1016 } 1017 got, err := ioutil.ReadAll(res.Body) 1018 if err != nil { 1019 t.Fatalf("Body ReadAll: %v", err) 1020 } 1021 if !strings.Contains(string(got), deniedMsg) { 1022 t.Errorf("Known bug: response %q does not contain %q", got, deniedMsg) 1023 } 1024 } 1025 1026 // From http://golang.org/issue/4454 , 1027 // "client fails to handle requests with no body and chunked encoding" 1028 func TestChunkedNoContent(t *testing.T) { 1029 defer afterTest(t) 1030 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1031 w.WriteHeader(StatusNoContent) 1032 })) 1033 defer ts.Close() 1034 1035 for _, closeBody := range []bool{true, false} { 1036 c := &Client{Transport: &Transport{}} 1037 const n = 4 1038 for i := 1; i <= n; i++ { 1039 res, err := c.Get(ts.URL) 1040 if err != nil { 1041 t.Errorf("closingBody=%v, req %d/%d: %v", closeBody, i, n, err) 1042 } else { 1043 if closeBody { 1044 res.Body.Close() 1045 } 1046 } 1047 } 1048 } 1049 } 1050 1051 func TestTransportConcurrency(t *testing.T) { 1052 defer afterTest(t) 1053 maxProcs, numReqs := 16, 500 1054 if testing.Short() { 1055 maxProcs, numReqs = 4, 50 1056 } 1057 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) 1058 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1059 fmt.Fprintf(w, "%v", r.FormValue("echo")) 1060 })) 1061 defer ts.Close() 1062 1063 var wg sync.WaitGroup 1064 wg.Add(numReqs) 1065 1066 tr := &Transport{ 1067 Dial: func(netw, addr string) (c net.Conn, err error) { 1068 // Due to the Transport's "socket late 1069 // binding" (see idleConnCh in transport.go), 1070 // the numReqs HTTP requests below can finish 1071 // with a dial still outstanding. So count 1072 // our dials as work too so the leak checker 1073 // doesn't complain at us. 1074 wg.Add(1) 1075 defer wg.Done() 1076 return net.Dial(netw, addr) 1077 }, 1078 } 1079 defer tr.CloseIdleConnections() 1080 c := &Client{Transport: tr} 1081 reqs := make(chan string) 1082 defer close(reqs) 1083 1084 for i := 0; i < maxProcs*2; i++ { 1085 go func() { 1086 for req := range reqs { 1087 res, err := c.Get(ts.URL + "/?echo=" + req) 1088 if err != nil { 1089 t.Errorf("error on req %s: %v", req, err) 1090 wg.Done() 1091 continue 1092 } 1093 all, err := ioutil.ReadAll(res.Body) 1094 if err != nil { 1095 t.Errorf("read error on req %s: %v", req, err) 1096 wg.Done() 1097 continue 1098 } 1099 if string(all) != req { 1100 t.Errorf("body of req %s = %q; want %q", req, all, req) 1101 } 1102 res.Body.Close() 1103 wg.Done() 1104 } 1105 }() 1106 } 1107 for i := 0; i < numReqs; i++ { 1108 reqs <- fmt.Sprintf("request-%d", i) 1109 } 1110 wg.Wait() 1111 } 1112 1113 func TestIssue4191_InfiniteGetTimeout(t *testing.T) { 1114 if runtime.GOOS == "plan9" { 1115 t.Skip("skipping test; see http://golang.org/issue/7237") 1116 } 1117 defer afterTest(t) 1118 const debug = false 1119 mux := NewServeMux() 1120 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) { 1121 io.Copy(w, neverEnding('a')) 1122 }) 1123 ts := httptest.NewServer(mux) 1124 timeout := 100 * time.Millisecond 1125 1126 client := &Client{ 1127 Transport: &Transport{ 1128 Dial: func(n, addr string) (net.Conn, error) { 1129 conn, err := net.Dial(n, addr) 1130 if err != nil { 1131 return nil, err 1132 } 1133 conn.SetDeadline(time.Now().Add(timeout)) 1134 if debug { 1135 conn = NewLoggingConn("client", conn) 1136 } 1137 return conn, nil 1138 }, 1139 DisableKeepAlives: true, 1140 }, 1141 } 1142 1143 getFailed := false 1144 nRuns := 5 1145 if testing.Short() { 1146 nRuns = 1 1147 } 1148 for i := 0; i < nRuns; i++ { 1149 if debug { 1150 println("run", i+1, "of", nRuns) 1151 } 1152 sres, err := client.Get(ts.URL + "/get") 1153 if err != nil { 1154 if !getFailed { 1155 // Make the timeout longer, once. 1156 getFailed = true 1157 t.Logf("increasing timeout") 1158 i-- 1159 timeout *= 10 1160 continue 1161 } 1162 t.Errorf("Error issuing GET: %v", err) 1163 break 1164 } 1165 _, err = io.Copy(ioutil.Discard, sres.Body) 1166 if err == nil { 1167 t.Errorf("Unexpected successful copy") 1168 break 1169 } 1170 } 1171 if debug { 1172 println("tests complete; waiting for handlers to finish") 1173 } 1174 ts.Close() 1175 } 1176 1177 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) { 1178 if runtime.GOOS == "plan9" { 1179 t.Skip("skipping test; see http://golang.org/issue/7237") 1180 } 1181 defer afterTest(t) 1182 const debug = false 1183 mux := NewServeMux() 1184 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) { 1185 io.Copy(w, neverEnding('a')) 1186 }) 1187 mux.HandleFunc("/put", func(w ResponseWriter, r *Request) { 1188 defer r.Body.Close() 1189 io.Copy(ioutil.Discard, r.Body) 1190 }) 1191 ts := httptest.NewServer(mux) 1192 timeout := 100 * time.Millisecond 1193 1194 client := &Client{ 1195 Transport: &Transport{ 1196 Dial: func(n, addr string) (net.Conn, error) { 1197 conn, err := net.Dial(n, addr) 1198 if err != nil { 1199 return nil, err 1200 } 1201 conn.SetDeadline(time.Now().Add(timeout)) 1202 if debug { 1203 conn = NewLoggingConn("client", conn) 1204 } 1205 return conn, nil 1206 }, 1207 DisableKeepAlives: true, 1208 }, 1209 } 1210 1211 getFailed := false 1212 nRuns := 5 1213 if testing.Short() { 1214 nRuns = 1 1215 } 1216 for i := 0; i < nRuns; i++ { 1217 if debug { 1218 println("run", i+1, "of", nRuns) 1219 } 1220 sres, err := client.Get(ts.URL + "/get") 1221 if err != nil { 1222 if !getFailed { 1223 // Make the timeout longer, once. 1224 getFailed = true 1225 t.Logf("increasing timeout") 1226 i-- 1227 timeout *= 10 1228 continue 1229 } 1230 t.Errorf("Error issuing GET: %v", err) 1231 break 1232 } 1233 req, _ := NewRequest("PUT", ts.URL+"/put", sres.Body) 1234 _, err = client.Do(req) 1235 if err == nil { 1236 sres.Body.Close() 1237 t.Errorf("Unexpected successful PUT") 1238 break 1239 } 1240 sres.Body.Close() 1241 } 1242 if debug { 1243 println("tests complete; waiting for handlers to finish") 1244 } 1245 ts.Close() 1246 } 1247 1248 func TestTransportResponseHeaderTimeout(t *testing.T) { 1249 defer afterTest(t) 1250 if testing.Short() { 1251 t.Skip("skipping timeout test in -short mode") 1252 } 1253 inHandler := make(chan bool, 1) 1254 mux := NewServeMux() 1255 mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) { 1256 inHandler <- true 1257 }) 1258 mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) { 1259 inHandler <- true 1260 time.Sleep(2 * time.Second) 1261 }) 1262 ts := httptest.NewServer(mux) 1263 defer ts.Close() 1264 1265 tr := &Transport{ 1266 ResponseHeaderTimeout: 500 * time.Millisecond, 1267 } 1268 defer tr.CloseIdleConnections() 1269 c := &Client{Transport: tr} 1270 1271 tests := []struct { 1272 path string 1273 want int 1274 wantErr string 1275 }{ 1276 {path: "/fast", want: 200}, 1277 {path: "/slow", wantErr: "timeout awaiting response headers"}, 1278 {path: "/fast", want: 200}, 1279 } 1280 for i, tt := range tests { 1281 res, err := c.Get(ts.URL + tt.path) 1282 select { 1283 case <-inHandler: 1284 case <-time.After(5 * time.Second): 1285 t.Errorf("never entered handler for test index %d, %s", i, tt.path) 1286 continue 1287 } 1288 if err != nil { 1289 uerr, ok := err.(*url.Error) 1290 if !ok { 1291 t.Errorf("error is not an url.Error; got: %#v", err) 1292 continue 1293 } 1294 nerr, ok := uerr.Err.(net.Error) 1295 if !ok { 1296 t.Errorf("error does not satisfy net.Error interface; got: %#v", err) 1297 continue 1298 } 1299 if !nerr.Timeout() { 1300 t.Errorf("want timeout error; got: %q", nerr) 1301 continue 1302 } 1303 if strings.Contains(err.Error(), tt.wantErr) { 1304 continue 1305 } 1306 t.Errorf("%d. unexpected error: %v", i, err) 1307 continue 1308 } 1309 if tt.wantErr != "" { 1310 t.Errorf("%d. no error. expected error: %v", i, tt.wantErr) 1311 continue 1312 } 1313 if res.StatusCode != tt.want { 1314 t.Errorf("%d for path %q status = %d; want %d", i, tt.path, res.StatusCode, tt.want) 1315 } 1316 } 1317 } 1318 1319 func TestTransportCancelRequest(t *testing.T) { 1320 defer afterTest(t) 1321 if testing.Short() { 1322 t.Skip("skipping test in -short mode") 1323 } 1324 unblockc := make(chan bool) 1325 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1326 fmt.Fprintf(w, "Hello") 1327 w.(Flusher).Flush() // send headers and some body 1328 <-unblockc 1329 })) 1330 defer ts.Close() 1331 defer close(unblockc) 1332 1333 tr := &Transport{} 1334 defer tr.CloseIdleConnections() 1335 c := &Client{Transport: tr} 1336 1337 req, _ := NewRequest("GET", ts.URL, nil) 1338 res, err := c.Do(req) 1339 if err != nil { 1340 t.Fatal(err) 1341 } 1342 go func() { 1343 time.Sleep(1 * time.Second) 1344 tr.CancelRequest(req) 1345 }() 1346 t0 := time.Now() 1347 body, err := ioutil.ReadAll(res.Body) 1348 d := time.Since(t0) 1349 1350 if err == nil { 1351 t.Error("expected an error reading the body") 1352 } 1353 if string(body) != "Hello" { 1354 t.Errorf("Body = %q; want Hello", body) 1355 } 1356 if d < 500*time.Millisecond { 1357 t.Errorf("expected ~1 second delay; got %v", d) 1358 } 1359 // Verify no outstanding requests after readLoop/writeLoop 1360 // goroutines shut down. 1361 for tries := 3; tries > 0; tries-- { 1362 n := tr.NumPendingRequestsForTesting() 1363 if n == 0 { 1364 break 1365 } 1366 time.Sleep(100 * time.Millisecond) 1367 if tries == 1 { 1368 t.Errorf("pending requests = %d; want 0", n) 1369 } 1370 } 1371 } 1372 1373 func TestTransportCancelRequestInDial(t *testing.T) { 1374 defer afterTest(t) 1375 if testing.Short() { 1376 t.Skip("skipping test in -short mode") 1377 } 1378 var logbuf bytes.Buffer 1379 eventLog := log.New(&logbuf, "", 0) 1380 1381 unblockDial := make(chan bool) 1382 defer close(unblockDial) 1383 1384 inDial := make(chan bool) 1385 tr := &Transport{ 1386 Dial: func(network, addr string) (net.Conn, error) { 1387 eventLog.Println("dial: blocking") 1388 inDial <- true 1389 <-unblockDial 1390 return nil, errors.New("nope") 1391 }, 1392 } 1393 cl := &Client{Transport: tr} 1394 gotres := make(chan bool) 1395 req, _ := NewRequest("GET", "http://something.no-network.tld/", nil) 1396 go func() { 1397 _, err := cl.Do(req) 1398 eventLog.Printf("Get = %v", err) 1399 gotres <- true 1400 }() 1401 1402 select { 1403 case <-inDial: 1404 case <-time.After(5 * time.Second): 1405 t.Fatal("timeout; never saw blocking dial") 1406 } 1407 1408 eventLog.Printf("canceling") 1409 tr.CancelRequest(req) 1410 1411 select { 1412 case <-gotres: 1413 case <-time.After(5 * time.Second): 1414 panic("hang. events are: " + logbuf.String()) 1415 } 1416 1417 got := logbuf.String() 1418 want := `dial: blocking 1419 canceling 1420 Get = Get http://something.no-network.tld/: net/http: request canceled while waiting for connection 1421 ` 1422 if got != want { 1423 t.Errorf("Got events:\n%s\nWant:\n%s", got, want) 1424 } 1425 } 1426 1427 // golang.org/issue/3672 -- Client can't close HTTP stream 1428 // Calling Close on a Response.Body used to just read until EOF. 1429 // Now it actually closes the TCP connection. 1430 func TestTransportCloseResponseBody(t *testing.T) { 1431 defer afterTest(t) 1432 writeErr := make(chan error, 1) 1433 msg := []byte("young\n") 1434 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1435 for { 1436 _, err := w.Write(msg) 1437 if err != nil { 1438 writeErr <- err 1439 return 1440 } 1441 w.(Flusher).Flush() 1442 } 1443 })) 1444 defer ts.Close() 1445 1446 tr := &Transport{} 1447 defer tr.CloseIdleConnections() 1448 c := &Client{Transport: tr} 1449 1450 req, _ := NewRequest("GET", ts.URL, nil) 1451 defer tr.CancelRequest(req) 1452 1453 res, err := c.Do(req) 1454 if err != nil { 1455 t.Fatal(err) 1456 } 1457 1458 const repeats = 3 1459 buf := make([]byte, len(msg)*repeats) 1460 want := bytes.Repeat(msg, repeats) 1461 1462 _, err = io.ReadFull(res.Body, buf) 1463 if err != nil { 1464 t.Fatal(err) 1465 } 1466 if !bytes.Equal(buf, want) { 1467 t.Fatalf("read %q; want %q", buf, want) 1468 } 1469 didClose := make(chan error, 1) 1470 go func() { 1471 didClose <- res.Body.Close() 1472 }() 1473 select { 1474 case err := <-didClose: 1475 if err != nil { 1476 t.Errorf("Close = %v", err) 1477 } 1478 case <-time.After(10 * time.Second): 1479 t.Fatal("too long waiting for close") 1480 } 1481 select { 1482 case err := <-writeErr: 1483 if err == nil { 1484 t.Errorf("expected non-nil write error") 1485 } 1486 case <-time.After(10 * time.Second): 1487 t.Fatal("too long waiting for write error") 1488 } 1489 } 1490 1491 type fooProto struct{} 1492 1493 func (fooProto) RoundTrip(req *Request) (*Response, error) { 1494 res := &Response{ 1495 Status: "200 OK", 1496 StatusCode: 200, 1497 Header: make(Header), 1498 Body: ioutil.NopCloser(strings.NewReader("You wanted " + req.URL.String())), 1499 } 1500 return res, nil 1501 } 1502 1503 func TestTransportAltProto(t *testing.T) { 1504 defer afterTest(t) 1505 tr := &Transport{} 1506 c := &Client{Transport: tr} 1507 tr.RegisterProtocol("foo", fooProto{}) 1508 res, err := c.Get("foo://bar.com/path") 1509 if err != nil { 1510 t.Fatal(err) 1511 } 1512 bodyb, err := ioutil.ReadAll(res.Body) 1513 if err != nil { 1514 t.Fatal(err) 1515 } 1516 body := string(bodyb) 1517 if e := "You wanted foo://bar.com/path"; body != e { 1518 t.Errorf("got response %q, want %q", body, e) 1519 } 1520 } 1521 1522 func TestTransportNoHost(t *testing.T) { 1523 defer afterTest(t) 1524 tr := &Transport{} 1525 _, err := tr.RoundTrip(&Request{ 1526 Header: make(Header), 1527 URL: &url.URL{ 1528 Scheme: "http", 1529 }, 1530 }) 1531 want := "http: no Host in request URL" 1532 if got := fmt.Sprint(err); got != want { 1533 t.Errorf("error = %v; want %q", err, want) 1534 } 1535 } 1536 1537 func TestTransportSocketLateBinding(t *testing.T) { 1538 defer afterTest(t) 1539 1540 mux := NewServeMux() 1541 fooGate := make(chan bool, 1) 1542 mux.HandleFunc("/foo", func(w ResponseWriter, r *Request) { 1543 w.Header().Set("foo-ipport", r.RemoteAddr) 1544 w.(Flusher).Flush() 1545 <-fooGate 1546 }) 1547 mux.HandleFunc("/bar", func(w ResponseWriter, r *Request) { 1548 w.Header().Set("bar-ipport", r.RemoteAddr) 1549 }) 1550 ts := httptest.NewServer(mux) 1551 defer ts.Close() 1552 1553 dialGate := make(chan bool, 1) 1554 tr := &Transport{ 1555 Dial: func(n, addr string) (net.Conn, error) { 1556 if <-dialGate { 1557 return net.Dial(n, addr) 1558 } 1559 return nil, errors.New("manually closed") 1560 }, 1561 DisableKeepAlives: false, 1562 } 1563 defer tr.CloseIdleConnections() 1564 c := &Client{ 1565 Transport: tr, 1566 } 1567 1568 dialGate <- true // only allow one dial 1569 fooRes, err := c.Get(ts.URL + "/foo") 1570 if err != nil { 1571 t.Fatal(err) 1572 } 1573 fooAddr := fooRes.Header.Get("foo-ipport") 1574 if fooAddr == "" { 1575 t.Fatal("No addr on /foo request") 1576 } 1577 time.AfterFunc(200*time.Millisecond, func() { 1578 // let the foo response finish so we can use its 1579 // connection for /bar 1580 fooGate <- true 1581 io.Copy(ioutil.Discard, fooRes.Body) 1582 fooRes.Body.Close() 1583 }) 1584 1585 barRes, err := c.Get(ts.URL + "/bar") 1586 if err != nil { 1587 t.Fatal(err) 1588 } 1589 barAddr := barRes.Header.Get("bar-ipport") 1590 if barAddr != fooAddr { 1591 t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr) 1592 } 1593 barRes.Body.Close() 1594 dialGate <- false 1595 } 1596 1597 // Issue 2184 1598 func TestTransportReading100Continue(t *testing.T) { 1599 defer afterTest(t) 1600 1601 const numReqs = 5 1602 reqBody := func(n int) string { return fmt.Sprintf("request body %d", n) } 1603 reqID := func(n int) string { return fmt.Sprintf("REQ-ID-%d", n) } 1604 1605 send100Response := func(w *io.PipeWriter, r *io.PipeReader) { 1606 defer w.Close() 1607 defer r.Close() 1608 br := bufio.NewReader(r) 1609 n := 0 1610 for { 1611 n++ 1612 req, err := ReadRequest(br) 1613 if err == io.EOF { 1614 return 1615 } 1616 if err != nil { 1617 t.Error(err) 1618 return 1619 } 1620 slurp, err := ioutil.ReadAll(req.Body) 1621 if err != nil { 1622 t.Errorf("Server request body slurp: %v", err) 1623 return 1624 } 1625 id := req.Header.Get("Request-Id") 1626 resCode := req.Header.Get("X-Want-Response-Code") 1627 if resCode == "" { 1628 resCode = "100 Continue" 1629 if string(slurp) != reqBody(n) { 1630 t.Errorf("Server got %q, %v; want %q", slurp, err, reqBody(n)) 1631 } 1632 } 1633 body := fmt.Sprintf("Response number %d", n) 1634 v := []byte(strings.Replace(fmt.Sprintf(`HTTP/1.1 %s 1635 Date: Thu, 28 Feb 2013 17:55:41 GMT 1636 1637 HTTP/1.1 200 OK 1638 Content-Type: text/html 1639 Echo-Request-Id: %s 1640 Content-Length: %d 1641 1642 %s`, resCode, id, len(body), body), "\n", "\r\n", -1)) 1643 w.Write(v) 1644 if id == reqID(numReqs) { 1645 return 1646 } 1647 } 1648 1649 } 1650 1651 tr := &Transport{ 1652 Dial: func(n, addr string) (net.Conn, error) { 1653 sr, sw := io.Pipe() // server read/write 1654 cr, cw := io.Pipe() // client read/write 1655 conn := &rwTestConn{ 1656 Reader: cr, 1657 Writer: sw, 1658 closeFunc: func() error { 1659 sw.Close() 1660 cw.Close() 1661 return nil 1662 }, 1663 } 1664 go send100Response(cw, sr) 1665 return conn, nil 1666 }, 1667 DisableKeepAlives: false, 1668 } 1669 defer tr.CloseIdleConnections() 1670 c := &Client{Transport: tr} 1671 1672 testResponse := func(req *Request, name string, wantCode int) { 1673 res, err := c.Do(req) 1674 if err != nil { 1675 t.Fatalf("%s: Do: %v", name, err) 1676 } 1677 if res.StatusCode != wantCode { 1678 t.Fatalf("%s: Response Statuscode=%d; want %d", name, res.StatusCode, wantCode) 1679 } 1680 if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack { 1681 t.Errorf("%s: response id %q != request id %q", name, idBack, id) 1682 } 1683 _, err = ioutil.ReadAll(res.Body) 1684 if err != nil { 1685 t.Fatalf("%s: Slurp error: %v", name, err) 1686 } 1687 } 1688 1689 // Few 100 responses, making sure we're not off-by-one. 1690 for i := 1; i <= numReqs; i++ { 1691 req, _ := NewRequest("POST", "http://dummy.tld/", strings.NewReader(reqBody(i))) 1692 req.Header.Set("Request-Id", reqID(i)) 1693 testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200) 1694 } 1695 1696 // And some other informational 1xx but non-100 responses, to test 1697 // we return them but don't re-use the connection. 1698 for i := 1; i <= numReqs; i++ { 1699 req, _ := NewRequest("POST", "http://other.tld/", strings.NewReader(reqBody(i))) 1700 req.Header.Set("X-Want-Response-Code", "123 Sesame Street") 1701 testResponse(req, fmt.Sprintf("123, %d/%d", i, numReqs), 123) 1702 } 1703 } 1704 1705 type proxyFromEnvTest struct { 1706 req string // URL to fetch; blank means "http://example.com" 1707 env string 1708 noenv string 1709 want string 1710 wanterr error 1711 } 1712 1713 func (t proxyFromEnvTest) String() string { 1714 var buf bytes.Buffer 1715 if t.env != "" { 1716 fmt.Fprintf(&buf, "http_proxy=%q", t.env) 1717 } 1718 if t.noenv != "" { 1719 fmt.Fprintf(&buf, " no_proxy=%q", t.noenv) 1720 } 1721 req := "http://example.com" 1722 if t.req != "" { 1723 req = t.req 1724 } 1725 fmt.Fprintf(&buf, " req=%q", req) 1726 return strings.TrimSpace(buf.String()) 1727 } 1728 1729 var proxyFromEnvTests = []proxyFromEnvTest{ 1730 {env: "127.0.0.1:8080", want: "http://127.0.0.1:8080"}, 1731 {env: "cache.corp.example.com:1234", want: "http://cache.corp.example.com:1234"}, 1732 {env: "cache.corp.example.com", want: "http://cache.corp.example.com"}, 1733 {env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"}, 1734 {env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"}, 1735 {env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"}, 1736 {want: "<nil>"}, 1737 {noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"}, 1738 {noenv: ".example.com", req: "http://example.com/", env: "proxy", want: "<nil>"}, 1739 {noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 1740 {noenv: "example.com", req: "http://foo.example.com/", env: "proxy", want: "<nil>"}, 1741 {noenv: ".foo.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 1742 } 1743 1744 func TestProxyFromEnvironment(t *testing.T) { 1745 ResetProxyEnv() 1746 for _, tt := range proxyFromEnvTests { 1747 os.Setenv("HTTP_PROXY", tt.env) 1748 os.Setenv("NO_PROXY", tt.noenv) 1749 ResetCachedEnvironment() 1750 reqURL := tt.req 1751 if reqURL == "" { 1752 reqURL = "http://example.com" 1753 } 1754 req, _ := NewRequest("GET", reqURL, nil) 1755 url, err := ProxyFromEnvironment(req) 1756 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e { 1757 t.Errorf("%v: got error = %q, want %q", tt, g, e) 1758 continue 1759 } 1760 if got := fmt.Sprintf("%s", url); got != tt.want { 1761 t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want) 1762 } 1763 } 1764 } 1765 1766 func TestIdleConnChannelLeak(t *testing.T) { 1767 var mu sync.Mutex 1768 var n int 1769 1770 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1771 mu.Lock() 1772 n++ 1773 mu.Unlock() 1774 })) 1775 defer ts.Close() 1776 1777 tr := &Transport{ 1778 Dial: func(netw, addr string) (net.Conn, error) { 1779 return net.Dial(netw, ts.Listener.Addr().String()) 1780 }, 1781 } 1782 defer tr.CloseIdleConnections() 1783 1784 c := &Client{Transport: tr} 1785 1786 // First, without keep-alives. 1787 for _, disableKeep := range []bool{true, false} { 1788 tr.DisableKeepAlives = disableKeep 1789 for i := 0; i < 5; i++ { 1790 _, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i)) 1791 if err != nil { 1792 t.Fatal(err) 1793 } 1794 } 1795 if got := tr.IdleConnChMapSizeForTesting(); got != 0 { 1796 t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got) 1797 } 1798 } 1799 } 1800 1801 // Verify the status quo: that the Client.Post function coerces its 1802 // body into a ReadCloser if it's a Closer, and that the Transport 1803 // then closes it. 1804 func TestTransportClosesRequestBody(t *testing.T) { 1805 defer afterTest(t) 1806 ts := httptest.NewServer(http.HandlerFunc(func(w ResponseWriter, r *Request) { 1807 io.Copy(ioutil.Discard, r.Body) 1808 })) 1809 defer ts.Close() 1810 1811 tr := &Transport{} 1812 defer tr.CloseIdleConnections() 1813 cl := &Client{Transport: tr} 1814 1815 closes := 0 1816 1817 res, err := cl.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")}) 1818 if err != nil { 1819 t.Fatal(err) 1820 } 1821 res.Body.Close() 1822 if closes != 1 { 1823 t.Errorf("closes = %d; want 1", closes) 1824 } 1825 } 1826 1827 func TestTransportTLSHandshakeTimeout(t *testing.T) { 1828 defer afterTest(t) 1829 if testing.Short() { 1830 t.Skip("skipping in short mode") 1831 } 1832 ln := newLocalListener(t) 1833 defer ln.Close() 1834 testdonec := make(chan struct{}) 1835 defer close(testdonec) 1836 1837 go func() { 1838 c, err := ln.Accept() 1839 if err != nil { 1840 t.Error(err) 1841 return 1842 } 1843 <-testdonec 1844 c.Close() 1845 }() 1846 1847 getdonec := make(chan struct{}) 1848 go func() { 1849 defer close(getdonec) 1850 tr := &Transport{ 1851 Dial: func(_, _ string) (net.Conn, error) { 1852 return net.Dial("tcp", ln.Addr().String()) 1853 }, 1854 TLSHandshakeTimeout: 250 * time.Millisecond, 1855 } 1856 cl := &Client{Transport: tr} 1857 _, err := cl.Get("https://dummy.tld/") 1858 if err == nil { 1859 t.Error("expected error") 1860 return 1861 } 1862 ue, ok := err.(*url.Error) 1863 if !ok { 1864 t.Errorf("expected url.Error; got %#v", err) 1865 return 1866 } 1867 ne, ok := ue.Err.(net.Error) 1868 if !ok { 1869 t.Errorf("expected net.Error; got %#v", err) 1870 return 1871 } 1872 if !ne.Timeout() { 1873 t.Errorf("expected timeout error; got %v", err) 1874 } 1875 if !strings.Contains(err.Error(), "handshake timeout") { 1876 t.Errorf("expected 'handshake timeout' in error; got %v", err) 1877 } 1878 }() 1879 select { 1880 case <-getdonec: 1881 case <-time.After(5 * time.Second): 1882 t.Error("test timeout; TLS handshake hung?") 1883 } 1884 } 1885 1886 // Trying to repro golang.org/issue/3514 1887 func TestTLSServerClosesConnection(t *testing.T) { 1888 defer afterTest(t) 1889 if runtime.GOOS == "windows" { 1890 t.Skip("skipping flaky test on Windows; golang.org/issue/7634") 1891 } 1892 closedc := make(chan bool, 1) 1893 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1894 if strings.Contains(r.URL.Path, "/keep-alive-then-die") { 1895 conn, _, _ := w.(Hijacker).Hijack() 1896 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) 1897 conn.Close() 1898 closedc <- true 1899 return 1900 } 1901 fmt.Fprintf(w, "hello") 1902 })) 1903 defer ts.Close() 1904 tr := &Transport{ 1905 TLSClientConfig: &tls.Config{ 1906 InsecureSkipVerify: true, 1907 }, 1908 } 1909 defer tr.CloseIdleConnections() 1910 client := &Client{Transport: tr} 1911 1912 var nSuccess = 0 1913 var errs []error 1914 const trials = 20 1915 for i := 0; i < trials; i++ { 1916 tr.CloseIdleConnections() 1917 res, err := client.Get(ts.URL + "/keep-alive-then-die") 1918 if err != nil { 1919 t.Fatal(err) 1920 } 1921 <-closedc 1922 slurp, err := ioutil.ReadAll(res.Body) 1923 if err != nil { 1924 t.Fatal(err) 1925 } 1926 if string(slurp) != "foo" { 1927 t.Errorf("Got %q, want foo", slurp) 1928 } 1929 1930 // Now try again and see if we successfully 1931 // pick a new connection. 1932 res, err = client.Get(ts.URL + "/") 1933 if err != nil { 1934 errs = append(errs, err) 1935 continue 1936 } 1937 slurp, err = ioutil.ReadAll(res.Body) 1938 if err != nil { 1939 errs = append(errs, err) 1940 continue 1941 } 1942 nSuccess++ 1943 } 1944 if nSuccess > 0 { 1945 t.Logf("successes = %d of %d", nSuccess, trials) 1946 } else { 1947 t.Errorf("All runs failed:") 1948 } 1949 for _, err := range errs { 1950 t.Logf(" err: %v", err) 1951 } 1952 } 1953 1954 // byteFromChanReader is an io.Reader that reads a single byte at a 1955 // time from the channel. When the channel is closed, the reader 1956 // returns io.EOF. 1957 type byteFromChanReader chan byte 1958 1959 func (c byteFromChanReader) Read(p []byte) (n int, err error) { 1960 if len(p) == 0 { 1961 return 1962 } 1963 b, ok := <-c 1964 if !ok { 1965 return 0, io.EOF 1966 } 1967 p[0] = b 1968 return 1, nil 1969 } 1970 1971 // Verifies that the Transport doesn't reuse a connection in the case 1972 // where the server replies before the request has been fully 1973 // written. We still honor that reply (see TestIssue3595), but don't 1974 // send future requests on the connection because it's then in a 1975 // questionable state. 1976 // golang.org/issue/7569 1977 func TestTransportNoReuseAfterEarlyResponse(t *testing.T) { 1978 defer afterTest(t) 1979 var sconn struct { 1980 sync.Mutex 1981 c net.Conn 1982 } 1983 var getOkay bool 1984 closeConn := func() { 1985 sconn.Lock() 1986 defer sconn.Unlock() 1987 if sconn.c != nil { 1988 sconn.c.Close() 1989 sconn.c = nil 1990 if !getOkay { 1991 t.Logf("Closed server connection") 1992 } 1993 } 1994 } 1995 defer closeConn() 1996 1997 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1998 if r.Method == "GET" { 1999 io.WriteString(w, "bar") 2000 return 2001 } 2002 conn, _, _ := w.(Hijacker).Hijack() 2003 sconn.Lock() 2004 sconn.c = conn 2005 sconn.Unlock() 2006 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive 2007 go io.Copy(ioutil.Discard, conn) 2008 })) 2009 defer ts.Close() 2010 tr := &Transport{} 2011 defer tr.CloseIdleConnections() 2012 client := &Client{Transport: tr} 2013 2014 const bodySize = 256 << 10 2015 finalBit := make(byteFromChanReader, 1) 2016 req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit)) 2017 req.ContentLength = bodySize 2018 res, err := client.Do(req) 2019 if err := wantBody(res, err, "foo"); err != nil { 2020 t.Errorf("POST response: %v", err) 2021 } 2022 donec := make(chan bool) 2023 go func() { 2024 defer close(donec) 2025 res, err = client.Get(ts.URL) 2026 if err := wantBody(res, err, "bar"); err != nil { 2027 t.Errorf("GET response: %v", err) 2028 return 2029 } 2030 getOkay = true // suppress test noise 2031 }() 2032 time.AfterFunc(5*time.Second, closeConn) 2033 select { 2034 case <-donec: 2035 finalBit <- 'x' // unblock the writeloop of the first Post 2036 close(finalBit) 2037 case <-time.After(7 * time.Second): 2038 t.Fatal("timeout waiting for GET request to finish") 2039 } 2040 } 2041 2042 type errorReader struct { 2043 err error 2044 } 2045 2046 func (e errorReader) Read(p []byte) (int, error) { return 0, e.err } 2047 2048 type closerFunc func() error 2049 2050 func (f closerFunc) Close() error { return f() } 2051 2052 // Issue 6981 2053 func TestTransportClosesBodyOnError(t *testing.T) { 2054 if runtime.GOOS == "plan9" { 2055 t.Skip("skipping test; see http://golang.org/issue/7782") 2056 } 2057 defer afterTest(t) 2058 readBody := make(chan error, 1) 2059 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2060 _, err := ioutil.ReadAll(r.Body) 2061 readBody <- err 2062 })) 2063 defer ts.Close() 2064 fakeErr := errors.New("fake error") 2065 didClose := make(chan bool, 1) 2066 req, _ := NewRequest("POST", ts.URL, struct { 2067 io.Reader 2068 io.Closer 2069 }{ 2070 io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}), 2071 closerFunc(func() error { 2072 select { 2073 case didClose <- true: 2074 default: 2075 } 2076 return nil 2077 }), 2078 }) 2079 res, err := DefaultClient.Do(req) 2080 if res != nil { 2081 defer res.Body.Close() 2082 } 2083 if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) { 2084 t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error()) 2085 } 2086 select { 2087 case err := <-readBody: 2088 if err == nil { 2089 t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'") 2090 } 2091 case <-time.After(5 * time.Second): 2092 t.Error("timeout waiting for server handler to complete") 2093 } 2094 select { 2095 case <-didClose: 2096 default: 2097 t.Errorf("didn't see Body.Close") 2098 } 2099 } 2100 2101 func wantBody(res *http.Response, err error, want string) error { 2102 if err != nil { 2103 return err 2104 } 2105 slurp, err := ioutil.ReadAll(res.Body) 2106 if err != nil { 2107 return fmt.Errorf("error reading body: %v", err) 2108 } 2109 if string(slurp) != want { 2110 return fmt.Errorf("body = %q; want %q", slurp, want) 2111 } 2112 if err := res.Body.Close(); err != nil { 2113 return fmt.Errorf("body Close = %v", err) 2114 } 2115 return nil 2116 } 2117 2118 func newLocalListener(t *testing.T) net.Listener { 2119 ln, err := net.Listen("tcp", "127.0.0.1:0") 2120 if err != nil { 2121 ln, err = net.Listen("tcp6", "[::1]:0") 2122 } 2123 if err != nil { 2124 t.Fatal(err) 2125 } 2126 return ln 2127 } 2128 2129 type countCloseReader struct { 2130 n *int 2131 io.Reader 2132 } 2133 2134 func (cr countCloseReader) Close() error { 2135 (*cr.n)++ 2136 return nil 2137 } 2138 2139 // rgz is a gzip quine that uncompresses to itself. 2140 var rgz = []byte{ 2141 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 2142 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 2143 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0, 2144 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 2145 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 2146 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60, 2147 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2, 2148 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00, 2149 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 2150 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16, 2151 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05, 2152 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff, 2153 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00, 2154 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 2155 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 2156 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 2157 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 2158 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 2159 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 2160 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 2161 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 2162 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff, 2163 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00, 2164 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 2165 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 2166 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 2167 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 2168 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06, 2169 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00, 2170 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 2171 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 2172 0x00, 0x00, 2173 }