github.com/useflyent/fhttp@v0.0.0-20211004035111-333f430cfbbf/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 // More tests are in clientserver_test.go (for things testing both client & server for both 8 // HTTP/1 and HTTP/2). This 9 10 package http_test 11 12 import ( 13 "bufio" 14 "bytes" 15 "compress/gzip" 16 "context" 17 "crypto/rand" 18 "crypto/tls" 19 "crypto/x509" 20 "encoding/binary" 21 "errors" 22 "fmt" 23 "go/token" 24 "io" 25 "log" 26 mrand "math/rand" 27 "net" 28 "net/textproto" 29 "net/url" 30 "os" 31 "reflect" 32 "runtime" 33 "strconv" 34 "strings" 35 "sync" 36 "sync/atomic" 37 "testing" 38 "testing/iotest" 39 "time" 40 41 . "github.com/useflyent/fhttp" 42 "github.com/useflyent/fhttp/httptest" 43 "github.com/useflyent/fhttp/httptrace" 44 "github.com/useflyent/fhttp/httputil" 45 "github.com/useflyent/fhttp/internal" 46 "github.com/useflyent/fhttp/internal/nettrace" 47 48 "golang.org/x/net/http/httpguts" 49 ) 50 51 // TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close 52 // and then verify that the final 2 responses get errors back. 53 54 // hostPortHandler writes back the client's "host:port". 55 var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 56 if r.FormValue("close") == "true" { 57 w.Header().Set("Connection", "close") 58 } 59 w.Header().Set("X-Saw-Close", fmt.Sprint(r.Close)) 60 w.Write([]byte(r.RemoteAddr)) 61 }) 62 63 // testCloseConn is a net.Conn tracked by a testConnSet. 64 type testCloseConn struct { 65 net.Conn 66 set *testConnSet 67 } 68 69 func (c *testCloseConn) Close() error { 70 c.set.remove(c) 71 return c.Conn.Close() 72 } 73 74 // testConnSet tracks a set of TCP connections and whether they've 75 // been closed. 76 type testConnSet struct { 77 t *testing.T 78 mu sync.Mutex // guards closed and list 79 closed map[net.Conn]bool 80 list []net.Conn // in order created 81 } 82 83 func (tcs *testConnSet) insert(c net.Conn) { 84 tcs.mu.Lock() 85 defer tcs.mu.Unlock() 86 tcs.closed[c] = false 87 tcs.list = append(tcs.list, c) 88 } 89 90 func (tcs *testConnSet) remove(c net.Conn) { 91 tcs.mu.Lock() 92 defer tcs.mu.Unlock() 93 tcs.closed[c] = true 94 } 95 96 // some tests use this to manage raw tcp connections for later inspection 97 func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, error)) { 98 connSet := &testConnSet{ 99 t: t, 100 closed: make(map[net.Conn]bool), 101 } 102 dial := func(n, addr string) (net.Conn, error) { 103 c, err := net.Dial(n, addr) 104 if err != nil { 105 return nil, err 106 } 107 tc := &testCloseConn{c, connSet} 108 connSet.insert(tc) 109 return tc, nil 110 } 111 return connSet, dial 112 } 113 114 func (tcs *testConnSet) check(t *testing.T) { 115 tcs.mu.Lock() 116 defer tcs.mu.Unlock() 117 for i := 4; i >= 0; i-- { 118 for i, c := range tcs.list { 119 if tcs.closed[c] { 120 continue 121 } 122 if i != 0 { 123 tcs.mu.Unlock() 124 time.Sleep(50 * time.Millisecond) 125 tcs.mu.Lock() 126 continue 127 } 128 t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list)) 129 } 130 } 131 } 132 133 func TestReuseRequest(t *testing.T) { 134 defer afterTest(t) 135 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 136 w.Write([]byte("{}")) 137 })) 138 defer ts.Close() 139 140 c := ts.Client() 141 req, _ := NewRequest("GET", ts.URL, nil) 142 res, err := c.Do(req) 143 if err != nil { 144 t.Fatal(err) 145 } 146 err = res.Body.Close() 147 if err != nil { 148 t.Fatal(err) 149 } 150 151 res, err = c.Do(req) 152 if err != nil { 153 t.Fatal(err) 154 } 155 err = res.Body.Close() 156 if err != nil { 157 t.Fatal(err) 158 } 159 } 160 161 // Two subsequent requests and verify their response is the same. 162 // The response from the server is our own IP:port 163 func TestTransportKeepAlives(t *testing.T) { 164 defer afterTest(t) 165 ts := httptest.NewServer(hostPortHandler) 166 defer ts.Close() 167 168 c := ts.Client() 169 for _, disableKeepAlive := range []bool{false, true} { 170 c.Transport.(*Transport).DisableKeepAlives = disableKeepAlive 171 fetch := func(n int) string { 172 res, err := c.Get(ts.URL) 173 if err != nil { 174 t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err) 175 } 176 body, err := io.ReadAll(res.Body) 177 if err != nil { 178 t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err) 179 } 180 return string(body) 181 } 182 183 body1 := fetch(1) 184 body2 := fetch(2) 185 186 bodiesDiffer := body1 != body2 187 if bodiesDiffer != disableKeepAlive { 188 t.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 189 disableKeepAlive, bodiesDiffer, body1, body2) 190 } 191 } 192 } 193 194 func TestTransportConnectionCloseOnResponse(t *testing.T) { 195 defer afterTest(t) 196 ts := httptest.NewServer(hostPortHandler) 197 defer ts.Close() 198 199 connSet, testDial := makeTestDial(t) 200 201 c := ts.Client() 202 tr := c.Transport.(*Transport) 203 tr.Dial = testDial 204 205 for _, connectionClose := range []bool{false, true} { 206 fetch := func(n int) string { 207 req := new(Request) 208 var err error 209 req.URL, err = url.Parse(ts.URL + fmt.Sprintf("/?close=%v", connectionClose)) 210 if err != nil { 211 t.Fatalf("URL parse error: %v", err) 212 } 213 req.Method = "GET" 214 req.Proto = "HTTP/1.1" 215 req.ProtoMajor = 1 216 req.ProtoMinor = 1 217 218 res, err := c.Do(req) 219 if err != nil { 220 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) 221 } 222 defer res.Body.Close() 223 body, err := io.ReadAll(res.Body) 224 if err != nil { 225 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) 226 } 227 return string(body) 228 } 229 230 body1 := fetch(1) 231 body2 := fetch(2) 232 bodiesDiffer := body1 != body2 233 if bodiesDiffer != connectionClose { 234 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 235 connectionClose, bodiesDiffer, body1, body2) 236 } 237 238 tr.CloseIdleConnections() 239 } 240 241 connSet.check(t) 242 } 243 244 func TestTransportConnectionCloseOnRequest(t *testing.T) { 245 defer afterTest(t) 246 ts := httptest.NewServer(hostPortHandler) 247 defer ts.Close() 248 249 connSet, testDial := makeTestDial(t) 250 251 c := ts.Client() 252 tr := c.Transport.(*Transport) 253 tr.Dial = testDial 254 for _, connectionClose := range []bool{false, true} { 255 fetch := func(n int) string { 256 req := new(Request) 257 var err error 258 req.URL, err = url.Parse(ts.URL) 259 if err != nil { 260 t.Fatalf("URL parse error: %v", err) 261 } 262 req.Method = "GET" 263 req.Proto = "HTTP/1.1" 264 req.ProtoMajor = 1 265 req.ProtoMinor = 1 266 req.Close = connectionClose 267 268 res, err := c.Do(req) 269 if err != nil { 270 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) 271 } 272 if got, want := res.Header.Get("X-Saw-Close"), fmt.Sprint(connectionClose); got != want { 273 t.Errorf("For connectionClose = %v; handler's X-Saw-Close was %v; want %v", 274 connectionClose, got, !connectionClose) 275 } 276 body, err := io.ReadAll(res.Body) 277 if err != nil { 278 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) 279 } 280 return string(body) 281 } 282 283 body1 := fetch(1) 284 body2 := fetch(2) 285 bodiesDiffer := body1 != body2 286 if bodiesDiffer != connectionClose { 287 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", 288 connectionClose, bodiesDiffer, body1, body2) 289 } 290 291 tr.CloseIdleConnections() 292 } 293 294 connSet.check(t) 295 } 296 297 // if the Transport's DisableKeepAlives is set, all requests should 298 // send Connection: close. 299 // HTTP/1-only (Connection: close doesn't exist in h2) 300 func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) { 301 defer afterTest(t) 302 ts := httptest.NewServer(hostPortHandler) 303 defer ts.Close() 304 305 c := ts.Client() 306 c.Transport.(*Transport).DisableKeepAlives = true 307 308 res, err := c.Get(ts.URL) 309 if err != nil { 310 t.Fatal(err) 311 } 312 res.Body.Close() 313 if res.Header.Get("X-Saw-Close") != "true" { 314 t.Errorf("handler didn't see Connection: close ") 315 } 316 } 317 318 // Test that Transport only sends one "Connection: close", regardless of 319 // how "close" was indicated. 320 func TestTransportRespectRequestWantsClose(t *testing.T) { 321 tests := []struct { 322 disableKeepAlives bool 323 close bool 324 }{ 325 {disableKeepAlives: false, close: false}, 326 {disableKeepAlives: false, close: true}, 327 {disableKeepAlives: true, close: false}, 328 {disableKeepAlives: true, close: true}, 329 } 330 331 for _, tc := range tests { 332 t.Run(fmt.Sprintf("DisableKeepAlive=%v,RequestClose=%v", tc.disableKeepAlives, tc.close), 333 func(t *testing.T) { 334 defer afterTest(t) 335 ts := httptest.NewServer(hostPortHandler) 336 defer ts.Close() 337 338 c := ts.Client() 339 c.Transport.(*Transport).DisableKeepAlives = tc.disableKeepAlives 340 req, err := NewRequest("GET", ts.URL, nil) 341 if err != nil { 342 t.Fatal(err) 343 } 344 count := 0 345 trace := &httptrace.ClientTrace{ 346 WroteHeaderField: func(key string, field []string) { 347 if key != "Connection" { 348 return 349 } 350 if httpguts.HeaderValuesContainsToken(field, "close") { 351 count += 1 352 } 353 }, 354 } 355 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) 356 req.Close = tc.close 357 res, err := c.Do(req) 358 if err != nil { 359 t.Fatal(err) 360 } 361 defer res.Body.Close() 362 if want := tc.disableKeepAlives || tc.close; count > 1 || (count == 1) != want { 363 t.Errorf("expecting want:%v, got 'Connection: close':%d", want, count) 364 } 365 }) 366 } 367 368 } 369 370 func TestTransportIdleCacheKeys(t *testing.T) { 371 defer afterTest(t) 372 ts := httptest.NewServer(hostPortHandler) 373 defer ts.Close() 374 c := ts.Client() 375 tr := c.Transport.(*Transport) 376 377 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 378 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) 379 } 380 381 resp, err := c.Get(ts.URL) 382 if err != nil { 383 t.Error(err) 384 } 385 io.ReadAll(resp.Body) 386 387 keys := tr.IdleConnKeysForTesting() 388 if e, g := 1, len(keys); e != g { 389 t.Fatalf("After Get expected %d idle conn cache keys; got %d", e, g) 390 } 391 392 if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e { 393 t.Errorf("Expected idle cache Key %q; got %q", e, keys[0]) 394 } 395 396 tr.CloseIdleConnections() 397 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 398 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) 399 } 400 } 401 402 // Tests that the HTTP transport re-uses connections when a client 403 // reads to the end of a response Body without closing it. 404 func TestTransportReadToEndReusesConn(t *testing.T) { 405 defer afterTest(t) 406 const msg = "foobar" 407 408 var addrSeen map[string]int 409 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 410 addrSeen[r.RemoteAddr]++ 411 if r.URL.Path == "/chunked/" { 412 w.WriteHeader(200) 413 w.(Flusher).Flush() 414 } else { 415 w.Header().Set("Content-Length", strconv.Itoa(len(msg))) 416 w.WriteHeader(200) 417 } 418 w.Write([]byte(msg)) 419 })) 420 defer ts.Close() 421 422 buf := make([]byte, len(msg)) 423 424 for pi, path := range []string{"/content-length/", "/chunked/"} { 425 wantLen := []int{len(msg), -1}[pi] 426 addrSeen = make(map[string]int) 427 for i := 0; i < 3; i++ { 428 res, err := Get(ts.URL + path) 429 if err != nil { 430 t.Errorf("Get %s: %v", path, err) 431 continue 432 } 433 // We want to close this body eventually (before the 434 // defer afterTest at top runs), but not before the 435 // len(addrSeen) check at the bottom of this test, 436 // since Closing this early in the loop would risk 437 // making connections be re-used for the wrong reason. 438 defer res.Body.Close() 439 440 if res.ContentLength != int64(wantLen) { 441 t.Errorf("%s res.ContentLength = %d; want %d", path, res.ContentLength, wantLen) 442 } 443 n, err := res.Body.Read(buf) 444 if n != len(msg) || err != io.EOF { 445 t.Errorf("%s Read = %v, %v; want %d, EOF", path, n, err, len(msg)) 446 } 447 } 448 if len(addrSeen) != 1 { 449 t.Errorf("for %s, server saw %d distinct client addresses; want 1", path, len(addrSeen)) 450 } 451 } 452 } 453 454 func TestTransportMaxPerHostIdleConns(t *testing.T) { 455 defer afterTest(t) 456 stop := make(chan struct{}) // stop marks the exit of main Test goroutine 457 defer close(stop) 458 459 resch := make(chan string) 460 gotReq := make(chan bool) 461 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 462 gotReq <- true 463 var msg string 464 select { 465 case <-stop: 466 return 467 case msg = <-resch: 468 } 469 _, err := w.Write([]byte(msg)) 470 if err != nil { 471 t.Errorf("Write: %v", err) 472 return 473 } 474 })) 475 defer ts.Close() 476 477 c := ts.Client() 478 tr := c.Transport.(*Transport) 479 maxIdleConnsPerHost := 2 480 tr.MaxIdleConnsPerHost = maxIdleConnsPerHost 481 482 // Start 3 outstanding requests and wait for the server to get them. 483 // Their responses will hang until we write to resch, though. 484 donech := make(chan bool) 485 doReq := func() { 486 defer func() { 487 select { 488 case <-stop: 489 return 490 case donech <- t.Failed(): 491 } 492 }() 493 resp, err := c.Get(ts.URL) 494 if err != nil { 495 t.Error(err) 496 return 497 } 498 if _, err := io.ReadAll(resp.Body); err != nil { 499 t.Errorf("ReadAll: %v", err) 500 return 501 } 502 } 503 go doReq() 504 <-gotReq 505 go doReq() 506 <-gotReq 507 go doReq() 508 <-gotReq 509 510 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g { 511 t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g) 512 } 513 514 resch <- "res1" 515 <-donech 516 keys := tr.IdleConnKeysForTesting() 517 if e, g := 1, len(keys); e != g { 518 t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g) 519 } 520 addr := ts.Listener.Addr().String() 521 cacheKey := "|http|" + addr 522 if keys[0] != cacheKey { 523 t.Fatalf("Expected idle cache Key %q; got %q", cacheKey, keys[0]) 524 } 525 if e, g := 1, tr.IdleConnCountForTesting("http", addr); e != g { 526 t.Errorf("after first response, expected %d idle conns; got %d", e, g) 527 } 528 529 resch <- "res2" 530 <-donech 531 if g, w := tr.IdleConnCountForTesting("http", addr), 2; g != w { 532 t.Errorf("after second response, idle conns = %d; want %d", g, w) 533 } 534 535 resch <- "res3" 536 <-donech 537 if g, w := tr.IdleConnCountForTesting("http", addr), maxIdleConnsPerHost; g != w { 538 t.Errorf("after third response, idle conns = %d; want %d", g, w) 539 } 540 } 541 542 func TestTransportMaxConnsPerHostIncludeDialInProgress(t *testing.T) { 543 defer afterTest(t) 544 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 545 _, err := w.Write([]byte("foo")) 546 if err != nil { 547 t.Fatalf("Write: %v", err) 548 } 549 })) 550 defer ts.Close() 551 c := ts.Client() 552 tr := c.Transport.(*Transport) 553 dialStarted := make(chan struct{}) 554 stallDial := make(chan struct{}) 555 tr.Dial = func(network, addr string) (net.Conn, error) { 556 dialStarted <- struct{}{} 557 <-stallDial 558 return net.Dial(network, addr) 559 } 560 561 tr.DisableKeepAlives = true 562 tr.MaxConnsPerHost = 1 563 564 preDial := make(chan struct{}) 565 reqComplete := make(chan struct{}) 566 doReq := func(reqId string) { 567 req, _ := NewRequest("GET", ts.URL, nil) 568 trace := &httptrace.ClientTrace{ 569 GetConn: func(hostPort string) { 570 preDial <- struct{}{} 571 }, 572 } 573 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) 574 resp, err := tr.RoundTrip(req) 575 if err != nil { 576 t.Errorf("unexpected error for request %s: %v", reqId, err) 577 } 578 _, err = io.ReadAll(resp.Body) 579 if err != nil { 580 t.Errorf("unexpected error for request %s: %v", reqId, err) 581 } 582 reqComplete <- struct{}{} 583 } 584 // get req1 to dial-in-progress 585 go doReq("req1") 586 <-preDial 587 <-dialStarted 588 589 // get req2 to waiting on conns per host to go down below max 590 go doReq("req2") 591 <-preDial 592 select { 593 case <-dialStarted: 594 t.Error("req2 dial started while req1 dial in progress") 595 return 596 default: 597 } 598 599 // let req1 complete 600 stallDial <- struct{}{} 601 <-reqComplete 602 603 // let req2 complete 604 <-dialStarted 605 stallDial <- struct{}{} 606 <-reqComplete 607 } 608 609 func TestTransportMaxConnsPerHost(t *testing.T) { 610 defer afterTest(t) 611 CondSkipHTTP2(t) 612 613 h := HandlerFunc(func(w ResponseWriter, r *Request) { 614 _, err := w.Write([]byte("foo")) 615 if err != nil { 616 t.Fatalf("Write: %v", err) 617 } 618 }) 619 620 testMaxConns := func(scheme string, ts *httptest.Server) { 621 defer ts.Close() 622 623 c := ts.Client() 624 tr := c.Transport.(*Transport) 625 tr.MaxConnsPerHost = 1 626 if err := ExportHttp2ConfigureTransport(tr); err != nil { 627 t.Fatalf("ExportHttp2ConfigureTransport: %v", err) 628 } 629 630 connCh := make(chan net.Conn, 1) 631 var dialCnt, gotConnCnt, tlsHandshakeCnt int32 632 tr.Dial = func(network, addr string) (net.Conn, error) { 633 atomic.AddInt32(&dialCnt, 1) 634 c, err := net.Dial(network, addr) 635 connCh <- c 636 return c, err 637 } 638 639 doReq := func() { 640 trace := &httptrace.ClientTrace{ 641 GotConn: func(connInfo httptrace.GotConnInfo) { 642 if !connInfo.Reused { 643 atomic.AddInt32(&gotConnCnt, 1) 644 } 645 }, 646 TLSHandshakeStart: func() { 647 atomic.AddInt32(&tlsHandshakeCnt, 1) 648 }, 649 } 650 req, _ := NewRequest("GET", ts.URL, nil) 651 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) 652 653 resp, err := c.Do(req) 654 if err != nil { 655 t.Fatalf("request failed: %v", err) 656 } 657 defer resp.Body.Close() 658 _, err = io.ReadAll(resp.Body) 659 if err != nil { 660 t.Fatalf("read body failed: %v", err) 661 } 662 } 663 664 wg := sync.WaitGroup{} 665 for i := 0; i < 10; i++ { 666 wg.Add(1) 667 go func() { 668 defer wg.Done() 669 doReq() 670 }() 671 } 672 wg.Wait() 673 674 expected := int32(tr.MaxConnsPerHost) 675 if dialCnt != expected { 676 t.Errorf("round 1: too many dials (%s): %d != %d", scheme, dialCnt, expected) 677 } 678 if gotConnCnt != expected { 679 t.Errorf("round 1: too many get connections (%s): %d != %d", scheme, gotConnCnt, expected) 680 } 681 if ts.TLS != nil && tlsHandshakeCnt != expected { 682 t.Errorf("round 1: too many tls handshakes (%s): %d != %d", scheme, tlsHandshakeCnt, expected) 683 } 684 685 if t.Failed() { 686 t.FailNow() 687 } 688 689 (<-connCh).Close() 690 tr.CloseIdleConnections() 691 692 doReq() 693 expected++ 694 if dialCnt != expected { 695 t.Errorf("round 2: too many dials (%s): %d", scheme, dialCnt) 696 } 697 if gotConnCnt != expected { 698 t.Errorf("round 2: too many get connections (%s): %d != %d", scheme, gotConnCnt, expected) 699 } 700 if ts.TLS != nil && tlsHandshakeCnt != expected { 701 t.Errorf("round 2: too many tls handshakes (%s): %d != %d", scheme, tlsHandshakeCnt, expected) 702 } 703 } 704 705 testMaxConns("http", httptest.NewServer(h)) 706 testMaxConns("https", httptest.NewTLSServer(h)) 707 708 ts := httptest.NewUnstartedServer(h) 709 ts.TLS = &tls.Config{NextProtos: []string{"h2"}} 710 ts.StartTLS() 711 testMaxConns("http2", ts) 712 } 713 714 func TestTransportRemovesDeadIdleConnections(t *testing.T) { 715 setParallel(t) 716 defer afterTest(t) 717 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 718 io.WriteString(w, r.RemoteAddr) 719 })) 720 defer ts.Close() 721 722 c := ts.Client() 723 tr := c.Transport.(*Transport) 724 725 doReq := func(name string) string { 726 // Do a POST instead of a GET to prevent the Transport's 727 // idempotent request retry logic from kicking in... 728 res, err := c.Post(ts.URL, "", nil) 729 if err != nil { 730 t.Fatalf("%s: %v", name, err) 731 } 732 if res.StatusCode != 200 { 733 t.Fatalf("%s: %v", name, res.Status) 734 } 735 defer res.Body.Close() 736 slurp, err := io.ReadAll(res.Body) 737 if err != nil { 738 t.Fatalf("%s: %v", name, err) 739 } 740 return string(slurp) 741 } 742 743 first := doReq("first") 744 keys1 := tr.IdleConnKeysForTesting() 745 746 ts.CloseClientConnections() 747 748 var keys2 []string 749 if !waitCondition(3*time.Second, 50*time.Millisecond, func() bool { 750 keys2 = tr.IdleConnKeysForTesting() 751 return len(keys2) == 0 752 }) { 753 t.Fatalf("Transport didn't notice idle connection's death.\nbefore: %q\n after: %q\n", keys1, keys2) 754 } 755 756 second := doReq("second") 757 if first == second { 758 t.Errorf("expected a different connection between requests. got %q both times", first) 759 } 760 } 761 762 // Test that the Transport notices when a server hangs up on its 763 // unexpectedly (a keep-alive connection is closed). 764 func TestTransportServerClosingUnexpectedly(t *testing.T) { 765 setParallel(t) 766 defer afterTest(t) 767 ts := httptest.NewServer(hostPortHandler) 768 defer ts.Close() 769 c := ts.Client() 770 771 fetch := func(n, retries int) string { 772 condFatalf := func(format string, arg ...interface{}) { 773 if retries <= 0 { 774 t.Fatalf(format, arg...) 775 } 776 t.Logf("retrying shortly after expected error: "+format, arg...) 777 time.Sleep(time.Second / time.Duration(retries)) 778 } 779 for retries >= 0 { 780 retries-- 781 res, err := c.Get(ts.URL) 782 if err != nil { 783 condFatalf("error in req #%d, GET: %v", n, err) 784 continue 785 } 786 body, err := io.ReadAll(res.Body) 787 if err != nil { 788 condFatalf("error in req #%d, ReadAll: %v", n, err) 789 continue 790 } 791 res.Body.Close() 792 return string(body) 793 } 794 panic("unreachable") 795 } 796 797 body1 := fetch(1, 0) 798 body2 := fetch(2, 0) 799 800 // Close all the idle connections in a way that's similar to 801 // the server hanging up on us. We don't use 802 // httptest.Server.CloseClientConnections because it's 803 // best-effort and stops blocking after 5 seconds. On a loaded 804 // machine running many tests concurrently it's possible for 805 // that method to be async and cause the body3 fetch below to 806 // run on an old connection. This function is synchronous. 807 ExportCloseTransportConnsAbruptly(c.Transport.(*Transport)) 808 809 body3 := fetch(3, 5) 810 811 if body1 != body2 { 812 t.Errorf("expected body1 and body2 to be equal") 813 } 814 if body2 == body3 { 815 t.Errorf("expected body2 and body3 to be different") 816 } 817 } 818 819 // Test for https://golang.org/issue/2616 (appropriate issue number) 820 // This fails pretty reliably with GOMAXPROCS=100 or something high. 821 func TestStressSurpriseServerCloses(t *testing.T) { 822 defer afterTest(t) 823 if testing.Short() { 824 t.Skip("skipping test in short mode") 825 } 826 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 827 w.Header().Set("Content-Length", "5") 828 w.Header().Set("Content-Type", "text/plain") 829 w.Write([]byte("Hello")) 830 w.(Flusher).Flush() 831 conn, buf, _ := w.(Hijacker).Hijack() 832 buf.Flush() 833 conn.Close() 834 })) 835 defer ts.Close() 836 c := ts.Client() 837 838 // Do a bunch of traffic from different goroutines. Send to activityc 839 // after each request completes, regardless of whether it failed. 840 // If these are too high, OS X exhausts its ephemeral ports 841 // and hangs waiting for them to transition TCP states. That's 842 // not what we want to test. TODO(bradfitz): use an io.Pipe 843 // dialer for this test instead? 844 const ( 845 numClients = 20 846 reqsPerClient = 25 847 ) 848 activityc := make(chan bool) 849 for i := 0; i < numClients; i++ { 850 go func() { 851 for i := 0; i < reqsPerClient; i++ { 852 res, err := c.Get(ts.URL) 853 if err == nil { 854 // We expect errors since the server is 855 // hanging up on us after telling us to 856 // send more requests, so we don't 857 // actually care what the error is. 858 // But we want to close the body in cases 859 // where we won the race. 860 res.Body.Close() 861 } 862 if !<-activityc { // Receives false when close(activityc) is executed 863 return 864 } 865 } 866 }() 867 } 868 869 // Make sure all the request come back, one way or another. 870 for i := 0; i < numClients*reqsPerClient; i++ { 871 select { 872 case activityc <- true: 873 case <-time.After(5 * time.Second): 874 close(activityc) 875 t.Fatalf("presumed deadlock; no HTTP client activity seen in awhile") 876 } 877 } 878 } 879 880 // TestTransportHeadResponses verifies that we deal with Content-Lengths 881 // with no bodies properly 882 func TestTransportHeadResponses(t *testing.T) { 883 defer afterTest(t) 884 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 885 if r.Method != "HEAD" { 886 panic("expected HEAD; got " + r.Method) 887 } 888 w.Header().Set("Content-Length", "123") 889 w.WriteHeader(200) 890 })) 891 defer ts.Close() 892 c := ts.Client() 893 894 for i := 0; i < 2; i++ { 895 res, err := c.Head(ts.URL) 896 if err != nil { 897 t.Errorf("error on loop %d: %v", i, err) 898 continue 899 } 900 if e, g := "123", res.Header.Get("Content-Length"); e != g { 901 t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g) 902 } 903 if e, g := int64(123), res.ContentLength; e != g { 904 t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g) 905 } 906 if all, err := io.ReadAll(res.Body); err != nil { 907 t.Errorf("loop %d: Body ReadAll: %v", i, err) 908 } else if len(all) != 0 { 909 t.Errorf("Bogus body %q", all) 910 } 911 } 912 } 913 914 // TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding 915 // on responses to HEAD requests. 916 func TestTransportHeadChunkedResponse(t *testing.T) { 917 defer afterTest(t) 918 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 919 if r.Method != "HEAD" { 920 panic("expected HEAD; got " + r.Method) 921 } 922 w.Header().Set("Transfer-Encoding", "chunked") // client should ignore 923 w.Header().Set("x-client-ipport", r.RemoteAddr) 924 w.WriteHeader(200) 925 })) 926 defer ts.Close() 927 c := ts.Client() 928 929 // Ensure that we wait for the readLoop to complete before 930 // calling Head again 931 didRead := make(chan bool) 932 SetReadLoopBeforeNextReadHook(func() { didRead <- true }) 933 defer SetReadLoopBeforeNextReadHook(nil) 934 935 res1, err := c.Head(ts.URL) 936 <-didRead 937 938 if err != nil { 939 t.Fatalf("request 1 error: %v", err) 940 } 941 942 res2, err := c.Head(ts.URL) 943 <-didRead 944 945 if err != nil { 946 t.Fatalf("request 2 error: %v", err) 947 } 948 if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 { 949 t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2) 950 } 951 } 952 953 var roundTripTests = []struct { 954 accept string 955 expectAccept string 956 compressed bool 957 }{ 958 // Requests with no accept-encoding header use transparent compression 959 {"", "gzip", false}, 960 // Requests with other accept-encoding should pass through unmodified 961 {"foo", "foo", false}, 962 // Requests with accept-encoding == gzip should be passed through 963 {"gzip", "gzip", true}, 964 } 965 966 // Test that the modification made to the Request by the RoundTripper is cleaned up 967 func TestRoundTripGzip(t *testing.T) { 968 setParallel(t) 969 defer afterTest(t) 970 const responseBody = "test response body" 971 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 972 accept := req.Header.Get("Accept-Encoding") 973 if expect := req.FormValue("expect_accept"); accept != expect { 974 t.Errorf("in handler, test %v: Accept-Encoding = %q, want %q", 975 req.FormValue("testnum"), accept, expect) 976 } 977 if accept == "gzip" { 978 rw.Header().Set("Content-Encoding", "gzip") 979 gz := gzip.NewWriter(rw) 980 gz.Write([]byte(responseBody)) 981 gz.Close() 982 } else { 983 rw.Header().Set("Content-Encoding", accept) 984 rw.Write([]byte(responseBody)) 985 } 986 })) 987 defer ts.Close() 988 tr := ts.Client().Transport.(*Transport) 989 990 for i, test := range roundTripTests { 991 // Test basic request (no accept-encoding) 992 req, _ := NewRequest("GET", fmt.Sprintf("%s/?testnum=%d&expect_accept=%s", ts.URL, i, test.expectAccept), nil) 993 if test.accept != "" { 994 req.Header.Set("Accept-Encoding", test.accept) 995 } 996 res, err := tr.RoundTrip(req) 997 if err != nil { 998 t.Errorf("%d. RoundTrip: %v", i, err) 999 continue 1000 } 1001 var body []byte 1002 if test.compressed { 1003 var r *gzip.Reader 1004 r, err = gzip.NewReader(res.Body) 1005 if err != nil { 1006 t.Errorf("%d. gzip NewReader: %v", i, err) 1007 continue 1008 } 1009 body, err = io.ReadAll(r) 1010 res.Body.Close() 1011 } else { 1012 body, err = io.ReadAll(res.Body) 1013 } 1014 if err != nil { 1015 t.Errorf("%d. Error: %q", i, err) 1016 continue 1017 } 1018 if g, e := string(body), responseBody; g != e { 1019 t.Errorf("%d. body = %q; want %q", i, g, e) 1020 } 1021 if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e { 1022 t.Errorf("%d. Accept-Encoding = %q; want %q (it was mutated, in violation of RoundTrip contract)", i, g, e) 1023 } 1024 if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e { 1025 t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e) 1026 } 1027 } 1028 1029 } 1030 1031 func TestTransportGzip(t *testing.T) { 1032 setParallel(t) 1033 defer afterTest(t) 1034 const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 1035 const nRandBytes = 1024 * 1024 1036 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 1037 if req.Method == "HEAD" { 1038 if g := req.Header.Get("Accept-Encoding"); g != "" { 1039 t.Errorf("HEAD request sent with Accept-Encoding of %q; want none", g) 1040 } 1041 return 1042 } 1043 if g, e := req.Header.Get("Accept-Encoding"), "gzip"; g != e { 1044 t.Errorf("Accept-Encoding = %q, want %q", g, e) 1045 } 1046 rw.Header().Set("Content-Encoding", "gzip") 1047 1048 var w io.Writer = rw 1049 var buf bytes.Buffer 1050 if req.FormValue("chunked") == "0" { 1051 w = &buf 1052 defer io.Copy(rw, &buf) 1053 defer func() { 1054 rw.Header().Set("Content-Length", strconv.Itoa(buf.Len())) 1055 }() 1056 } 1057 gz := gzip.NewWriter(w) 1058 gz.Write([]byte(testString)) 1059 if req.FormValue("body") == "large" { 1060 io.CopyN(gz, rand.Reader, nRandBytes) 1061 } 1062 gz.Close() 1063 })) 1064 defer ts.Close() 1065 c := ts.Client() 1066 1067 for _, chunked := range []string{"1", "0"} { 1068 // First fetch something large, but only read some of it. 1069 res, err := c.Get(ts.URL + "/?body=large&chunked=" + chunked) 1070 if err != nil { 1071 t.Fatalf("large get: %v", err) 1072 } 1073 buf := make([]byte, len(testString)) 1074 n, err := io.ReadFull(res.Body, buf) 1075 if err != nil { 1076 t.Fatalf("partial read of large response: size=%d, %v", n, err) 1077 } 1078 if e, g := testString, string(buf); e != g { 1079 t.Errorf("partial read got %q, expected %q", g, e) 1080 } 1081 res.Body.Close() 1082 // Read on the body, even though it's closed 1083 n, err = res.Body.Read(buf) 1084 if n != 0 || err == nil { 1085 t.Errorf("expected error post-closed large Read; got = %d, %v", n, err) 1086 } 1087 1088 // Then something small. 1089 res, err = c.Get(ts.URL + "/?chunked=" + chunked) 1090 if err != nil { 1091 t.Fatal(err) 1092 } 1093 body, err := io.ReadAll(res.Body) 1094 if err != nil { 1095 t.Fatal(err) 1096 } 1097 if g, e := string(body), testString; g != e { 1098 t.Fatalf("body = %q; want %q", g, e) 1099 } 1100 if g, e := res.Header.Get("Content-Encoding"), ""; g != e { 1101 t.Fatalf("Content-Encoding = %q; want %q", g, e) 1102 } 1103 1104 // Read on the body after it's been fully read: 1105 n, err = res.Body.Read(buf) 1106 if n != 0 || err == nil { 1107 t.Errorf("expected Read error after exhausted reads; got %d, %v", n, err) 1108 } 1109 res.Body.Close() 1110 n, err = res.Body.Read(buf) 1111 if n != 0 || err == nil { 1112 t.Errorf("expected Read error after Close; got %d, %v", n, err) 1113 } 1114 } 1115 1116 // And a HEAD request too, because they're always weird. 1117 res, err := c.Head(ts.URL) 1118 if err != nil { 1119 t.Fatalf("Head: %v", err) 1120 } 1121 if res.StatusCode != 200 { 1122 t.Errorf("Head status=%d; want=200", res.StatusCode) 1123 } 1124 } 1125 1126 // If a request has Expect:100-continue header, the request blocks sending body until the first response. 1127 // Premature consumption of the request body should not be occurred. 1128 func TestTransportExpect100Continue(t *testing.T) { 1129 setParallel(t) 1130 defer afterTest(t) 1131 1132 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 1133 switch req.URL.Path { 1134 case "/100": 1135 // This endpoint implicitly responds 100 Continue and reads body. 1136 if _, err := io.Copy(io.Discard, req.Body); err != nil { 1137 t.Error("Failed to read Body", err) 1138 } 1139 rw.WriteHeader(StatusOK) 1140 case "/200": 1141 // Go 1.5 adds Connection: close header if the client expect 1142 // continue but not entire request body is consumed. 1143 rw.WriteHeader(StatusOK) 1144 case "/500": 1145 rw.WriteHeader(StatusInternalServerError) 1146 case "/keepalive": 1147 // This hijacked endpoint responds error without Connection:close. 1148 _, bufrw, err := rw.(Hijacker).Hijack() 1149 if err != nil { 1150 log.Fatal(err) 1151 } 1152 bufrw.WriteString("HTTP/1.1 500 Internal Server Error\r\n") 1153 bufrw.WriteString("Content-Length: 0\r\n\r\n") 1154 bufrw.Flush() 1155 case "/timeout": 1156 // This endpoint tries to read body without 100 (Continue) response. 1157 // After ExpectContinueTimeout, the reading will be started. 1158 conn, bufrw, err := rw.(Hijacker).Hijack() 1159 if err != nil { 1160 log.Fatal(err) 1161 } 1162 if _, err := io.CopyN(io.Discard, bufrw, req.ContentLength); err != nil { 1163 t.Error("Failed to read Body", err) 1164 } 1165 bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n") 1166 bufrw.Flush() 1167 conn.Close() 1168 } 1169 1170 })) 1171 defer ts.Close() 1172 1173 tests := []struct { 1174 path string 1175 body []byte 1176 sent int 1177 status int 1178 }{ 1179 {path: "/100", body: []byte("hello"), sent: 5, status: 200}, // Got 100 followed by 200, entire body is sent. 1180 {path: "/200", body: []byte("hello"), sent: 0, status: 200}, // Got 200 without 100. body isn't sent. 1181 {path: "/500", body: []byte("hello"), sent: 0, status: 500}, // Got 500 without 100. body isn't sent. 1182 {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Although without Connection:close, body isn't sent. 1183 {path: "/timeout", body: []byte("hello"), sent: 5, status: 200}, // Timeout exceeded and entire body is sent. 1184 } 1185 1186 c := ts.Client() 1187 for i, v := range tests { 1188 tr := &Transport{ 1189 ExpectContinueTimeout: 2 * time.Second, 1190 } 1191 defer tr.CloseIdleConnections() 1192 c.Transport = tr 1193 body := bytes.NewReader(v.body) 1194 req, err := NewRequest("PUT", ts.URL+v.path, body) 1195 if err != nil { 1196 t.Fatal(err) 1197 } 1198 req.Header.Set("Expect", "100-continue") 1199 req.ContentLength = int64(len(v.body)) 1200 1201 resp, err := c.Do(req) 1202 if err != nil { 1203 t.Fatal(err) 1204 } 1205 resp.Body.Close() 1206 1207 sent := len(v.body) - body.Len() 1208 if v.status != resp.StatusCode { 1209 t.Errorf("test %d: status code should be %d but got %d. (%s)", i, v.status, resp.StatusCode, v.path) 1210 } 1211 if v.sent != sent { 1212 t.Errorf("test %d: sent body should be %d but sent %d. (%s)", i, v.sent, sent, v.path) 1213 } 1214 } 1215 } 1216 1217 func TestSOCKS5Proxy(t *testing.T) { 1218 defer afterTest(t) 1219 ch := make(chan string, 1) 1220 l := newLocalListener(t) 1221 defer l.Close() 1222 defer close(ch) 1223 proxy := func(t *testing.T) { 1224 s, err := l.Accept() 1225 if err != nil { 1226 t.Errorf("socks5 proxy Accept(): %v", err) 1227 return 1228 } 1229 defer s.Close() 1230 var buf [22]byte 1231 if _, err := io.ReadFull(s, buf[:3]); err != nil { 1232 t.Errorf("socks5 proxy initial read: %v", err) 1233 return 1234 } 1235 if want := []byte{5, 1, 0}; !bytes.Equal(buf[:3], want) { 1236 t.Errorf("socks5 proxy initial read: got %v, want %v", buf[:3], want) 1237 return 1238 } 1239 if _, err := s.Write([]byte{5, 0}); err != nil { 1240 t.Errorf("socks5 proxy initial write: %v", err) 1241 return 1242 } 1243 if _, err := io.ReadFull(s, buf[:4]); err != nil { 1244 t.Errorf("socks5 proxy second read: %v", err) 1245 return 1246 } 1247 if want := []byte{5, 1, 0}; !bytes.Equal(buf[:3], want) { 1248 t.Errorf("socks5 proxy second read: got %v, want %v", buf[:3], want) 1249 return 1250 } 1251 var ipLen int 1252 switch buf[3] { 1253 case 1: 1254 ipLen = net.IPv4len 1255 case 4: 1256 ipLen = net.IPv6len 1257 default: 1258 t.Errorf("socks5 proxy second read: unexpected address type %v", buf[4]) 1259 return 1260 } 1261 if _, err := io.ReadFull(s, buf[4:ipLen+6]); err != nil { 1262 t.Errorf("socks5 proxy address read: %v", err) 1263 return 1264 } 1265 ip := net.IP(buf[4 : ipLen+4]) 1266 port := binary.BigEndian.Uint16(buf[ipLen+4 : ipLen+6]) 1267 copy(buf[:3], []byte{5, 0, 0}) 1268 if _, err := s.Write(buf[:ipLen+6]); err != nil { 1269 t.Errorf("socks5 proxy connect write: %v", err) 1270 return 1271 } 1272 ch <- fmt.Sprintf("proxy for %s:%d", ip, port) 1273 1274 // Implement proxying. 1275 targetHost := net.JoinHostPort(ip.String(), strconv.Itoa(int(port))) 1276 targetConn, err := net.Dial("tcp", targetHost) 1277 if err != nil { 1278 t.Errorf("net.Dial failed") 1279 return 1280 } 1281 go io.Copy(targetConn, s) 1282 io.Copy(s, targetConn) // Wait for the client to close the socket. 1283 targetConn.Close() 1284 } 1285 1286 pu, err := url.Parse("socks5://" + l.Addr().String()) 1287 if err != nil { 1288 t.Fatal(err) 1289 } 1290 1291 sentinelHeader := "X-Sentinel" 1292 sentinelValue := "12345" 1293 h := HandlerFunc(func(w ResponseWriter, r *Request) { 1294 w.Header().Set(sentinelHeader, sentinelValue) 1295 }) 1296 for _, useTLS := range []bool{false, true} { 1297 t.Run(fmt.Sprintf("useTLS=%v", useTLS), func(t *testing.T) { 1298 var ts *httptest.Server 1299 if useTLS { 1300 ts = httptest.NewTLSServer(h) 1301 } else { 1302 ts = httptest.NewServer(h) 1303 } 1304 go proxy(t) 1305 c := ts.Client() 1306 c.Transport.(*Transport).Proxy = ProxyURL(pu) 1307 r, err := c.Head(ts.URL) 1308 if err != nil { 1309 t.Fatal(err) 1310 } 1311 if r.Header.Get(sentinelHeader) != sentinelValue { 1312 t.Errorf("Failed to retrieve sentinel value") 1313 } 1314 var got string 1315 select { 1316 case got = <-ch: 1317 case <-time.After(5 * time.Second): 1318 t.Fatal("timeout connecting to socks5 proxy") 1319 } 1320 ts.Close() 1321 tsu, err := url.Parse(ts.URL) 1322 if err != nil { 1323 t.Fatal(err) 1324 } 1325 want := "proxy for " + tsu.Host 1326 if got != want { 1327 t.Errorf("got %q, want %q", got, want) 1328 } 1329 }) 1330 } 1331 } 1332 1333 func TestTransportProxy(t *testing.T) { 1334 defer afterTest(t) 1335 testCases := []struct{ httpsSite, httpsProxy bool }{ 1336 {false, false}, 1337 {false, true}, 1338 {true, false}, 1339 {true, true}, 1340 } 1341 for _, testCase := range testCases { 1342 httpsSite := testCase.httpsSite 1343 httpsProxy := testCase.httpsProxy 1344 t.Run(fmt.Sprintf("httpsSite=%v, httpsProxy=%v", httpsSite, httpsProxy), func(t *testing.T) { 1345 siteCh := make(chan *Request, 1) 1346 h1 := HandlerFunc(func(w ResponseWriter, r *Request) { 1347 siteCh <- r 1348 }) 1349 proxyCh := make(chan *Request, 1) 1350 h2 := HandlerFunc(func(w ResponseWriter, r *Request) { 1351 proxyCh <- r 1352 // Implement an entire CONNECT proxy 1353 if r.Method == "CONNECT" { 1354 hijacker, ok := w.(Hijacker) 1355 if !ok { 1356 t.Errorf("hijack not allowed") 1357 return 1358 } 1359 clientConn, _, err := hijacker.Hijack() 1360 if err != nil { 1361 t.Errorf("hijacking failed") 1362 return 1363 } 1364 res := &Response{ 1365 StatusCode: StatusOK, 1366 Proto: "HTTP/1.1", 1367 ProtoMajor: 1, 1368 ProtoMinor: 1, 1369 Header: make(Header), 1370 } 1371 1372 targetConn, err := net.Dial("tcp", r.URL.Host) 1373 if err != nil { 1374 t.Errorf("net.Dial(%q) failed: %v", r.URL.Host, err) 1375 return 1376 } 1377 1378 if err := res.Write(clientConn); err != nil { 1379 t.Errorf("Writing 200 OK failed: %v", err) 1380 return 1381 } 1382 1383 go io.Copy(targetConn, clientConn) 1384 go func() { 1385 io.Copy(clientConn, targetConn) 1386 targetConn.Close() 1387 }() 1388 } 1389 }) 1390 var ts *httptest.Server 1391 if httpsSite { 1392 ts = httptest.NewTLSServer(h1) 1393 } else { 1394 ts = httptest.NewServer(h1) 1395 } 1396 var proxy *httptest.Server 1397 if httpsProxy { 1398 proxy = httptest.NewTLSServer(h2) 1399 } else { 1400 proxy = httptest.NewServer(h2) 1401 } 1402 1403 pu, err := url.Parse(proxy.URL) 1404 if err != nil { 1405 t.Fatal(err) 1406 } 1407 1408 // If neither server is HTTPS or both are, then c may be derived from either. 1409 // If only one server is HTTPS, c must be derived from that server in order 1410 // to ensure that it is configured to use the fake root CA from testcert.go. 1411 c := proxy.Client() 1412 if httpsSite { 1413 c = ts.Client() 1414 } 1415 1416 c.Transport.(*Transport).Proxy = ProxyURL(pu) 1417 if _, err := c.Head(ts.URL); err != nil { 1418 t.Error(err) 1419 } 1420 var got *Request 1421 select { 1422 case got = <-proxyCh: 1423 case <-time.After(5 * time.Second): 1424 t.Fatal("timeout connecting to http proxy") 1425 } 1426 c.Transport.(*Transport).CloseIdleConnections() 1427 ts.Close() 1428 proxy.Close() 1429 if httpsSite { 1430 // First message should be a CONNECT, asking for a socket to the real server, 1431 if got.Method != "CONNECT" { 1432 t.Errorf("Wrong method for secure proxying: %q", got.Method) 1433 } 1434 gotHost := got.URL.Host 1435 pu, err := url.Parse(ts.URL) 1436 if err != nil { 1437 t.Fatal("Invalid site URL") 1438 } 1439 if wantHost := pu.Host; gotHost != wantHost { 1440 t.Errorf("Got CONNECT host %q, want %q", gotHost, wantHost) 1441 } 1442 1443 // The next message on the channel should be from the site's server. 1444 next := <-siteCh 1445 if next.Method != "HEAD" { 1446 t.Errorf("Wrong method at destination: %s", next.Method) 1447 } 1448 if nextURL := next.URL.String(); nextURL != "/" { 1449 t.Errorf("Wrong URL at destination: %s", nextURL) 1450 } 1451 } else { 1452 if got.Method != "HEAD" { 1453 t.Errorf("Wrong method for destination: %q", got.Method) 1454 } 1455 gotURL := got.URL.String() 1456 wantURL := ts.URL + "/" 1457 if gotURL != wantURL { 1458 t.Errorf("Got URL %q, want %q", gotURL, wantURL) 1459 } 1460 } 1461 }) 1462 } 1463 } 1464 1465 // Issue 28012: verify that the Transport closes its TCP connection to http proxies 1466 // when they're slow to reply to HTTPS CONNECT responses. 1467 func TestTransportProxyHTTPSConnectLeak(t *testing.T) { 1468 setParallel(t) 1469 defer afterTest(t) 1470 1471 ctx, cancel := context.WithCancel(context.Background()) 1472 defer cancel() 1473 1474 ln := newLocalListener(t) 1475 defer ln.Close() 1476 listenerDone := make(chan struct{}) 1477 go func() { 1478 defer close(listenerDone) 1479 c, err := ln.Accept() 1480 if err != nil { 1481 t.Errorf("Accept: %v", err) 1482 return 1483 } 1484 defer c.Close() 1485 // Read the CONNECT request 1486 br := bufio.NewReader(c) 1487 cr, err := ReadRequest(br) 1488 if err != nil { 1489 t.Errorf("proxy server failed to read CONNECT request") 1490 return 1491 } 1492 if cr.Method != "CONNECT" { 1493 t.Errorf("unexpected method %q", cr.Method) 1494 return 1495 } 1496 1497 // Now hang and never write a response; instead, cancel the request and wait 1498 // for the client to close. 1499 // (Prior to Issue 28012 being fixed, we never closed.) 1500 cancel() 1501 var buf [1]byte 1502 _, err = br.Read(buf[:]) 1503 if err != io.EOF { 1504 t.Errorf("proxy server Read err = %v; want EOF", err) 1505 } 1506 return 1507 }() 1508 1509 c := &Client{ 1510 Transport: &Transport{ 1511 Proxy: func(*Request) (*url.URL, error) { 1512 return url.Parse("http://" + ln.Addr().String()) 1513 }, 1514 }, 1515 } 1516 req, err := NewRequestWithContext(ctx, "GET", "https://golang.fake.tld/", nil) 1517 if err != nil { 1518 t.Fatal(err) 1519 } 1520 _, err = c.Do(req) 1521 if err == nil { 1522 t.Errorf("unexpected Get success") 1523 } 1524 1525 // Wait unconditionally for the listener goroutine to exit: this should never 1526 // hang, so if it does we want a full goroutine dump — and that's exactly what 1527 // the testing package will give us when the test run times out. 1528 <-listenerDone 1529 } 1530 1531 // Issue 16997: test transport dial preserves typed errors 1532 func TestTransportDialPreservesNetOpProxyError(t *testing.T) { 1533 defer afterTest(t) 1534 1535 var errDial = errors.New("some dial error") 1536 1537 tr := &Transport{ 1538 Proxy: func(*Request) (*url.URL, error) { 1539 return url.Parse("http://proxy.fake.tld/") 1540 }, 1541 Dial: func(string, string) (net.Conn, error) { 1542 return nil, errDial 1543 }, 1544 } 1545 defer tr.CloseIdleConnections() 1546 1547 c := &Client{Transport: tr} 1548 req, _ := NewRequest("GET", "http://fake.tld", nil) 1549 res, err := c.Do(req) 1550 if err == nil { 1551 res.Body.Close() 1552 t.Fatal("wanted a non-nil error") 1553 } 1554 1555 uerr, ok := err.(*url.Error) 1556 if !ok { 1557 t.Fatalf("got %T, want *url.Error", err) 1558 } 1559 oe, ok := uerr.Err.(*net.OpError) 1560 if !ok { 1561 t.Fatalf("url.Error.Err = %T; want *net.OpError", uerr.Err) 1562 } 1563 want := &net.OpError{ 1564 Op: "proxyconnect", 1565 Net: "tcp", 1566 Err: errDial, // original error, unwrapped. 1567 } 1568 if !reflect.DeepEqual(oe, want) { 1569 t.Errorf("Got error %#v; want %#v", oe, want) 1570 } 1571 } 1572 1573 // Issue 36431: calls to RoundTrip should not mutate t.ProxyConnectHeader. 1574 // 1575 // (A bug caused dialConn to instead write the per-request Proxy-Authorization 1576 // header through to the shared Header instance, introducing a data race.) 1577 func TestTransportProxyDialDoesNotMutateProxyConnectHeader(t *testing.T) { 1578 setParallel(t) 1579 defer afterTest(t) 1580 1581 proxy := httptest.NewTLSServer(NotFoundHandler()) 1582 defer proxy.Close() 1583 c := proxy.Client() 1584 1585 tr := c.Transport.(*Transport) 1586 tr.Proxy = func(*Request) (*url.URL, error) { 1587 u, _ := url.Parse(proxy.URL) 1588 u.User = url.UserPassword("aladdin", "opensesame") 1589 return u, nil 1590 } 1591 h := tr.ProxyConnectHeader 1592 if h == nil { 1593 h = make(Header) 1594 } 1595 tr.ProxyConnectHeader = h.Clone() 1596 1597 req, err := NewRequest("GET", "https://golang.fake.tld/", nil) 1598 if err != nil { 1599 t.Fatal(err) 1600 } 1601 _, err = c.Do(req) 1602 if err == nil { 1603 t.Errorf("unexpected Get success") 1604 } 1605 1606 if !reflect.DeepEqual(tr.ProxyConnectHeader, h) { 1607 t.Errorf("tr.ProxyConnectHeader = %v; want %v", tr.ProxyConnectHeader, h) 1608 } 1609 } 1610 1611 // TestTransportGzipRecursive sends a gzip quine and checks that the 1612 // client gets the same value back. This is more cute than anything, 1613 // but checks that we don't recurse forever, and checks that 1614 // Content-Encoding is removed. 1615 func TestTransportGzipRecursive(t *testing.T) { 1616 defer afterTest(t) 1617 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1618 w.Header().Set("Content-Encoding", "gzip") 1619 w.Write(rgz) 1620 })) 1621 defer ts.Close() 1622 1623 c := ts.Client() 1624 res, err := c.Get(ts.URL) 1625 if err != nil { 1626 t.Fatal(err) 1627 } 1628 body, err := io.ReadAll(res.Body) 1629 if err != nil { 1630 t.Fatal(err) 1631 } 1632 if !bytes.Equal(body, rgz) { 1633 t.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x", 1634 body, rgz) 1635 } 1636 if g, e := res.Header.Get("Content-Encoding"), ""; g != e { 1637 t.Fatalf("Content-Encoding = %q; want %q", g, e) 1638 } 1639 } 1640 1641 // golang.org/issue/7750: request fails when server replies with 1642 // a short gzip body 1643 func TestTransportGzipShort(t *testing.T) { 1644 defer afterTest(t) 1645 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1646 w.Header().Set("Content-Encoding", "gzip") 1647 w.Write([]byte{0x1f, 0x8b}) 1648 })) 1649 defer ts.Close() 1650 1651 c := ts.Client() 1652 res, err := c.Get(ts.URL) 1653 if err != nil { 1654 t.Fatal(err) 1655 } 1656 defer res.Body.Close() 1657 _, err = io.ReadAll(res.Body) 1658 if err == nil { 1659 t.Fatal("Expect an error from reading a body.") 1660 } 1661 if err != io.ErrUnexpectedEOF { 1662 t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err) 1663 } 1664 } 1665 1666 // Wait until number of goroutines is no greater than nmax, or time out. 1667 func waitNumGoroutine(nmax int) int { 1668 nfinal := runtime.NumGoroutine() 1669 for ntries := 10; ntries > 0 && nfinal > nmax; ntries-- { 1670 time.Sleep(50 * time.Millisecond) 1671 runtime.GC() 1672 nfinal = runtime.NumGoroutine() 1673 } 1674 return nfinal 1675 } 1676 1677 // tests that persistent goroutine connections shut down when no longer desired. 1678 func TestTransportPersistConnLeak(t *testing.T) { 1679 // Not parallel: counts goroutines 1680 defer afterTest(t) 1681 1682 const numReq = 25 1683 gotReqCh := make(chan bool, numReq) 1684 unblockCh := make(chan bool, numReq) 1685 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1686 gotReqCh <- true 1687 <-unblockCh 1688 w.Header().Set("Content-Length", "0") 1689 w.WriteHeader(204) 1690 })) 1691 defer ts.Close() 1692 c := ts.Client() 1693 tr := c.Transport.(*Transport) 1694 1695 n0 := runtime.NumGoroutine() 1696 1697 didReqCh := make(chan bool, numReq) 1698 failed := make(chan bool, numReq) 1699 for i := 0; i < numReq; i++ { 1700 go func() { 1701 res, err := c.Get(ts.URL) 1702 didReqCh <- true 1703 if err != nil { 1704 t.Logf("client fetch error: %v", err) 1705 failed <- true 1706 return 1707 } 1708 res.Body.Close() 1709 }() 1710 } 1711 1712 // Wait for all goroutines to be stuck in the Handler. 1713 for i := 0; i < numReq; i++ { 1714 select { 1715 case <-gotReqCh: 1716 // ok 1717 case <-failed: 1718 // Not great but not what we are testing: 1719 // sometimes an overloaded system will fail to make all the connections. 1720 } 1721 } 1722 1723 nhigh := runtime.NumGoroutine() 1724 1725 // Tell all handlers to unblock and reply. 1726 close(unblockCh) 1727 1728 // Wait for all HTTP clients to be done. 1729 for i := 0; i < numReq; i++ { 1730 <-didReqCh 1731 } 1732 1733 tr.CloseIdleConnections() 1734 nfinal := waitNumGoroutine(n0 + 5) 1735 1736 growth := nfinal - n0 1737 1738 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5. 1739 // Previously we were leaking one per numReq. 1740 if int(growth) > 5 { 1741 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth) 1742 t.Error("too many new goroutines") 1743 } 1744 } 1745 1746 // golang.org/issue/4531: Transport leaks goroutines when 1747 // request.ContentLength is explicitly short 1748 func TestTransportPersistConnLeakShortBody(t *testing.T) { 1749 // Not parallel: measures goroutines. 1750 defer afterTest(t) 1751 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1752 })) 1753 defer ts.Close() 1754 c := ts.Client() 1755 tr := c.Transport.(*Transport) 1756 1757 n0 := runtime.NumGoroutine() 1758 body := []byte("Hello") 1759 for i := 0; i < 20; i++ { 1760 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body)) 1761 if err != nil { 1762 t.Fatal(err) 1763 } 1764 req.ContentLength = int64(len(body) - 2) // explicitly short 1765 _, err = c.Do(req) 1766 if err == nil { 1767 t.Fatal("Expect an error from writing too long of a body.") 1768 } 1769 } 1770 nhigh := runtime.NumGoroutine() 1771 tr.CloseIdleConnections() 1772 nfinal := waitNumGoroutine(n0 + 5) 1773 1774 growth := nfinal - n0 1775 1776 // We expect 0 or 1 extra goroutine, empirically. Allow up to 5. 1777 // Previously we were leaking one per numReq. 1778 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth) 1779 if int(growth) > 5 { 1780 t.Error("too many new goroutines") 1781 } 1782 } 1783 1784 // A countedConn is a net.Conn that decrements an atomic counter when finalized. 1785 type countedConn struct { 1786 net.Conn 1787 } 1788 1789 // A countingDialer dials connections and counts the number that remain reachable. 1790 type countingDialer struct { 1791 dialer net.Dialer 1792 mu sync.Mutex 1793 total, live int64 1794 } 1795 1796 func (d *countingDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { 1797 conn, err := d.dialer.DialContext(ctx, network, address) 1798 if err != nil { 1799 return nil, err 1800 } 1801 1802 counted := new(countedConn) 1803 counted.Conn = conn 1804 1805 d.mu.Lock() 1806 defer d.mu.Unlock() 1807 d.total++ 1808 d.live++ 1809 1810 runtime.SetFinalizer(counted, d.decrement) 1811 return counted, nil 1812 } 1813 1814 func (d *countingDialer) decrement(*countedConn) { 1815 d.mu.Lock() 1816 defer d.mu.Unlock() 1817 d.live-- 1818 } 1819 1820 func (d *countingDialer) Read() (total, live int64) { 1821 d.mu.Lock() 1822 defer d.mu.Unlock() 1823 return d.total, d.live 1824 } 1825 1826 func TestTransportPersistConnLeakNeverIdle(t *testing.T) { 1827 defer afterTest(t) 1828 1829 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1830 // Close every connection so that it cannot be kept alive. 1831 conn, _, err := w.(Hijacker).Hijack() 1832 if err != nil { 1833 t.Errorf("Hijack failed unexpectedly: %v", err) 1834 return 1835 } 1836 conn.Close() 1837 })) 1838 defer ts.Close() 1839 1840 var d countingDialer 1841 c := ts.Client() 1842 c.Transport.(*Transport).DialContext = d.DialContext 1843 1844 body := []byte("Hello") 1845 for i := 0; ; i++ { 1846 total, live := d.Read() 1847 if live < total { 1848 break 1849 } 1850 if i >= 1<<12 { 1851 t.Fatalf("Count of live client net.Conns (%d) not lower than total (%d) after %d Do / GC iterations.", live, total, i) 1852 } 1853 1854 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body)) 1855 if err != nil { 1856 t.Fatal(err) 1857 } 1858 _, err = c.Do(req) 1859 if err == nil { 1860 t.Fatal("expected broken connection") 1861 } 1862 1863 runtime.GC() 1864 } 1865 } 1866 1867 type countedContext struct { 1868 context.Context 1869 } 1870 1871 type contextCounter struct { 1872 mu sync.Mutex 1873 live int64 1874 } 1875 1876 func (cc *contextCounter) Track(ctx context.Context) context.Context { 1877 counted := new(countedContext) 1878 counted.Context = ctx 1879 cc.mu.Lock() 1880 defer cc.mu.Unlock() 1881 cc.live++ 1882 runtime.SetFinalizer(counted, cc.decrement) 1883 return counted 1884 } 1885 1886 func (cc *contextCounter) decrement(*countedContext) { 1887 cc.mu.Lock() 1888 defer cc.mu.Unlock() 1889 cc.live-- 1890 } 1891 1892 func (cc *contextCounter) Read() (live int64) { 1893 cc.mu.Lock() 1894 defer cc.mu.Unlock() 1895 return cc.live 1896 } 1897 1898 func TestTransportPersistConnContextLeakMaxConnsPerHost(t *testing.T) { 1899 defer afterTest(t) 1900 1901 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1902 runtime.Gosched() 1903 w.WriteHeader(StatusOK) 1904 })) 1905 defer ts.Close() 1906 1907 c := ts.Client() 1908 c.Transport.(*Transport).MaxConnsPerHost = 1 1909 1910 ctx := context.Background() 1911 body := []byte("Hello") 1912 doPosts := func(cc *contextCounter) { 1913 var wg sync.WaitGroup 1914 for n := 64; n > 0; n-- { 1915 wg.Add(1) 1916 go func() { 1917 defer wg.Done() 1918 1919 ctx := cc.Track(ctx) 1920 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body)) 1921 if err != nil { 1922 t.Error(err) 1923 } 1924 1925 _, err = c.Do(req.WithContext(ctx)) 1926 if err != nil { 1927 t.Errorf("Do failed with error: %v", err) 1928 } 1929 }() 1930 } 1931 wg.Wait() 1932 } 1933 1934 var initialCC contextCounter 1935 doPosts(&initialCC) 1936 1937 // flushCC exists only to put pressure on the GC to finalize the initialCC 1938 // contexts: the flushCC allocations should eventually displace the initialCC 1939 // allocations. 1940 var flushCC contextCounter 1941 for i := 0; ; i++ { 1942 live := initialCC.Read() 1943 if live == 0 { 1944 break 1945 } 1946 if i >= 100 { 1947 t.Fatalf("%d Contexts still not finalized after %d GC cycles.", live, i) 1948 } 1949 doPosts(&flushCC) 1950 runtime.GC() 1951 } 1952 } 1953 1954 // This used to crash; https://golang.org/issue/3266 1955 func TestTransportIdleConnCrash(t *testing.T) { 1956 defer afterTest(t) 1957 var tr *Transport 1958 1959 unblockCh := make(chan bool, 1) 1960 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1961 <-unblockCh 1962 tr.CloseIdleConnections() 1963 })) 1964 defer ts.Close() 1965 c := ts.Client() 1966 tr = c.Transport.(*Transport) 1967 1968 didreq := make(chan bool) 1969 go func() { 1970 res, err := c.Get(ts.URL) 1971 if err != nil { 1972 t.Error(err) 1973 } else { 1974 res.Body.Close() // returns idle conn 1975 } 1976 didreq <- true 1977 }() 1978 unblockCh <- true 1979 <-didreq 1980 } 1981 1982 // Test that the transport doesn't close the TCP connection early, 1983 // before the response body has been read. This was a regression 1984 // which sadly lacked a triggering test. The large response body made 1985 // the old race easier to trigger. 1986 func TestIssue3644(t *testing.T) { 1987 defer afterTest(t) 1988 const numFoos = 5000 1989 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1990 w.Header().Set("Connection", "close") 1991 for i := 0; i < numFoos; i++ { 1992 w.Write([]byte("foo ")) 1993 } 1994 })) 1995 defer ts.Close() 1996 c := ts.Client() 1997 res, err := c.Get(ts.URL) 1998 if err != nil { 1999 t.Fatal(err) 2000 } 2001 defer res.Body.Close() 2002 bs, err := io.ReadAll(res.Body) 2003 if err != nil { 2004 t.Fatal(err) 2005 } 2006 if len(bs) != numFoos*len("foo ") { 2007 t.Errorf("unexpected response length") 2008 } 2009 } 2010 2011 // Test that a client receives a server's reply, even if the server doesn't read 2012 // the entire request body. 2013 func TestIssue3595(t *testing.T) { 2014 setParallel(t) 2015 defer afterTest(t) 2016 const deniedMsg = "sorry, denied." 2017 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2018 Error(w, deniedMsg, StatusUnauthorized) 2019 })) 2020 defer ts.Close() 2021 c := ts.Client() 2022 res, err := c.Post(ts.URL, "application/octet-stream", neverEnding('a')) 2023 if err != nil { 2024 t.Errorf("Post: %v", err) 2025 return 2026 } 2027 got, err := io.ReadAll(res.Body) 2028 if err != nil { 2029 t.Fatalf("Body ReadAll: %v", err) 2030 } 2031 if !strings.Contains(string(got), deniedMsg) { 2032 t.Errorf("Known bug: response %q does not contain %q", got, deniedMsg) 2033 } 2034 } 2035 2036 // From https://golang.org/issue/4454 , 2037 // "client fails to handle requests with no body and chunked encoding" 2038 func TestChunkedNoContent(t *testing.T) { 2039 defer afterTest(t) 2040 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2041 w.WriteHeader(StatusNoContent) 2042 })) 2043 defer ts.Close() 2044 2045 c := ts.Client() 2046 for _, closeBody := range []bool{true, false} { 2047 const n = 4 2048 for i := 1; i <= n; i++ { 2049 res, err := c.Get(ts.URL) 2050 if err != nil { 2051 t.Errorf("closingBody=%v, req %d/%d: %v", closeBody, i, n, err) 2052 } else { 2053 if closeBody { 2054 res.Body.Close() 2055 } 2056 } 2057 } 2058 } 2059 } 2060 2061 func TestTransportConcurrency(t *testing.T) { 2062 // Not parallel: uses global test hooks. 2063 defer afterTest(t) 2064 maxProcs, numReqs := 16, 500 2065 if testing.Short() { 2066 maxProcs, numReqs = 4, 50 2067 } 2068 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) 2069 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2070 fmt.Fprintf(w, "%v", r.FormValue("echo")) 2071 })) 2072 defer ts.Close() 2073 2074 var wg sync.WaitGroup 2075 wg.Add(numReqs) 2076 2077 // Due to the Transport's "socket late binding" (see 2078 // idleConnCh in transport.go), the numReqs HTTP requests 2079 // below can finish with a dial still outstanding. To keep 2080 // the leak checker happy, keep track of pending dials and 2081 // wait for them to finish (and be closed or returned to the 2082 // idle pool) before we close idle connections. 2083 SetPendingDialHooks(func() { wg.Add(1) }, wg.Done) 2084 defer SetPendingDialHooks(nil, nil) 2085 2086 c := ts.Client() 2087 reqs := make(chan string) 2088 defer close(reqs) 2089 2090 for i := 0; i < maxProcs*2; i++ { 2091 go func() { 2092 for req := range reqs { 2093 res, err := c.Get(ts.URL + "/?echo=" + req) 2094 if err != nil { 2095 t.Errorf("error on req %s: %v", req, err) 2096 wg.Done() 2097 continue 2098 } 2099 all, err := io.ReadAll(res.Body) 2100 if err != nil { 2101 t.Errorf("read error on req %s: %v", req, err) 2102 wg.Done() 2103 continue 2104 } 2105 if string(all) != req { 2106 t.Errorf("body of req %s = %q; want %q", req, all, req) 2107 } 2108 res.Body.Close() 2109 wg.Done() 2110 } 2111 }() 2112 } 2113 for i := 0; i < numReqs; i++ { 2114 reqs <- fmt.Sprintf("request-%d", i) 2115 } 2116 wg.Wait() 2117 } 2118 2119 func TestIssue4191_InfiniteGetTimeout(t *testing.T) { 2120 setParallel(t) 2121 defer afterTest(t) 2122 const debug = false 2123 mux := NewServeMux() 2124 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) { 2125 io.Copy(w, neverEnding('a')) 2126 }) 2127 ts := httptest.NewServer(mux) 2128 defer ts.Close() 2129 timeout := 100 * time.Millisecond 2130 2131 c := ts.Client() 2132 c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) { 2133 conn, err := net.Dial(n, addr) 2134 if err != nil { 2135 return nil, err 2136 } 2137 conn.SetDeadline(time.Now().Add(timeout)) 2138 if debug { 2139 conn = NewLoggingConn("client", conn) 2140 } 2141 return conn, nil 2142 } 2143 2144 getFailed := false 2145 nRuns := 5 2146 if testing.Short() { 2147 nRuns = 1 2148 } 2149 for i := 0; i < nRuns; i++ { 2150 if debug { 2151 println("run", i+1, "of", nRuns) 2152 } 2153 sres, err := c.Get(ts.URL + "/get") 2154 if err != nil { 2155 if !getFailed { 2156 // Make the timeout longer, once. 2157 getFailed = true 2158 t.Logf("increasing timeout") 2159 i-- 2160 timeout *= 10 2161 continue 2162 } 2163 t.Errorf("Error issuing GET: %v", err) 2164 break 2165 } 2166 _, err = io.Copy(io.Discard, sres.Body) 2167 if err == nil { 2168 t.Errorf("Unexpected successful copy") 2169 break 2170 } 2171 } 2172 if debug { 2173 println("tests complete; waiting for handlers to finish") 2174 } 2175 } 2176 2177 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) { 2178 setParallel(t) 2179 defer afterTest(t) 2180 const debug = false 2181 mux := NewServeMux() 2182 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) { 2183 io.Copy(w, neverEnding('a')) 2184 }) 2185 mux.HandleFunc("/put", func(w ResponseWriter, r *Request) { 2186 defer r.Body.Close() 2187 io.Copy(io.Discard, r.Body) 2188 }) 2189 ts := httptest.NewServer(mux) 2190 timeout := 100 * time.Millisecond 2191 2192 c := ts.Client() 2193 c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) { 2194 conn, err := net.Dial(n, addr) 2195 if err != nil { 2196 return nil, err 2197 } 2198 conn.SetDeadline(time.Now().Add(timeout)) 2199 if debug { 2200 conn = NewLoggingConn("client", conn) 2201 } 2202 return conn, nil 2203 } 2204 2205 getFailed := false 2206 nRuns := 5 2207 if testing.Short() { 2208 nRuns = 1 2209 } 2210 for i := 0; i < nRuns; i++ { 2211 if debug { 2212 println("run", i+1, "of", nRuns) 2213 } 2214 sres, err := c.Get(ts.URL + "/get") 2215 if err != nil { 2216 if !getFailed { 2217 // Make the timeout longer, once. 2218 getFailed = true 2219 t.Logf("increasing timeout") 2220 i-- 2221 timeout *= 10 2222 continue 2223 } 2224 t.Errorf("Error issuing GET: %v", err) 2225 break 2226 } 2227 req, _ := NewRequest("PUT", ts.URL+"/put", sres.Body) 2228 _, err = c.Do(req) 2229 if err == nil { 2230 sres.Body.Close() 2231 t.Errorf("Unexpected successful PUT") 2232 break 2233 } 2234 sres.Body.Close() 2235 } 2236 if debug { 2237 println("tests complete; waiting for handlers to finish") 2238 } 2239 ts.Close() 2240 } 2241 2242 func TestTransportResponseHeaderTimeout(t *testing.T) { 2243 setParallel(t) 2244 defer afterTest(t) 2245 if testing.Short() { 2246 t.Skip("skipping timeout test in -short mode") 2247 } 2248 inHandler := make(chan bool, 1) 2249 mux := NewServeMux() 2250 mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) { 2251 inHandler <- true 2252 }) 2253 mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) { 2254 inHandler <- true 2255 time.Sleep(2 * time.Second) 2256 }) 2257 ts := httptest.NewServer(mux) 2258 defer ts.Close() 2259 2260 c := ts.Client() 2261 c.Transport.(*Transport).ResponseHeaderTimeout = 500 * time.Millisecond 2262 2263 tests := []struct { 2264 path string 2265 want int 2266 wantErr string 2267 }{ 2268 {path: "/fast", want: 200}, 2269 {path: "/slow", wantErr: "timeout awaiting response headers"}, 2270 {path: "/fast", want: 200}, 2271 } 2272 for i, tt := range tests { 2273 req, _ := NewRequest("GET", ts.URL+tt.path, nil) 2274 req = req.WithT(t) 2275 res, err := c.Do(req) 2276 select { 2277 case <-inHandler: 2278 case <-time.After(5 * time.Second): 2279 t.Errorf("never entered handler for test index %d, %s", i, tt.path) 2280 continue 2281 } 2282 if err != nil { 2283 uerr, ok := err.(*url.Error) 2284 if !ok { 2285 t.Errorf("error is not an url.Error; got: %#v", err) 2286 continue 2287 } 2288 nerr, ok := uerr.Err.(net.Error) 2289 if !ok { 2290 t.Errorf("error does not satisfy net.Error interface; got: %#v", err) 2291 continue 2292 } 2293 if !nerr.Timeout() { 2294 t.Errorf("want timeout error; got: %q", nerr) 2295 continue 2296 } 2297 if strings.Contains(err.Error(), tt.wantErr) { 2298 continue 2299 } 2300 t.Errorf("%d. unexpected error: %v", i, err) 2301 continue 2302 } 2303 if tt.wantErr != "" { 2304 t.Errorf("%d. no error. expected error: %v", i, tt.wantErr) 2305 continue 2306 } 2307 if res.StatusCode != tt.want { 2308 t.Errorf("%d for path %q status = %d; want %d", i, tt.path, res.StatusCode, tt.want) 2309 } 2310 } 2311 } 2312 2313 func TestTransportCancelRequest(t *testing.T) { 2314 setParallel(t) 2315 defer afterTest(t) 2316 if testing.Short() { 2317 t.Skip("skipping test in -short mode") 2318 } 2319 unblockc := make(chan bool) 2320 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2321 fmt.Fprintf(w, "Hello") 2322 w.(Flusher).Flush() // send headers and some body 2323 <-unblockc 2324 })) 2325 defer ts.Close() 2326 defer close(unblockc) 2327 2328 c := ts.Client() 2329 tr := c.Transport.(*Transport) 2330 2331 req, _ := NewRequest("GET", ts.URL, nil) 2332 res, err := c.Do(req) 2333 if err != nil { 2334 t.Fatal(err) 2335 } 2336 go func() { 2337 time.Sleep(1 * time.Second) 2338 tr.CancelRequest(req) 2339 }() 2340 t0 := time.Now() 2341 body, err := io.ReadAll(res.Body) 2342 d := time.Since(t0) 2343 2344 if err != ExportErrRequestCanceled { 2345 t.Errorf("Body.Read error = %v; want errRequestCanceled", err) 2346 } 2347 if string(body) != "Hello" { 2348 t.Errorf("Body = %q; want Hello", body) 2349 } 2350 if d < 500*time.Millisecond { 2351 t.Errorf("expected ~1 second delay; got %v", d) 2352 } 2353 // Verify no outstanding requests after readLoop/writeLoop 2354 // goroutines shut down. 2355 for tries := 5; tries > 0; tries-- { 2356 n := tr.NumPendingRequestsForTesting() 2357 if n == 0 { 2358 break 2359 } 2360 time.Sleep(100 * time.Millisecond) 2361 if tries == 1 { 2362 t.Errorf("pending requests = %d; want 0", n) 2363 } 2364 } 2365 } 2366 2367 func testTransportCancelRequestInDo(t *testing.T, body io.Reader) { 2368 setParallel(t) 2369 defer afterTest(t) 2370 if testing.Short() { 2371 t.Skip("skipping test in -short mode") 2372 } 2373 unblockc := make(chan bool) 2374 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2375 <-unblockc 2376 })) 2377 defer ts.Close() 2378 defer close(unblockc) 2379 2380 c := ts.Client() 2381 tr := c.Transport.(*Transport) 2382 2383 donec := make(chan bool) 2384 req, _ := NewRequest("GET", ts.URL, body) 2385 go func() { 2386 defer close(donec) 2387 c.Do(req) 2388 }() 2389 start := time.Now() 2390 timeout := 10 * time.Second 2391 for time.Since(start) < timeout { 2392 time.Sleep(100 * time.Millisecond) 2393 tr.CancelRequest(req) 2394 select { 2395 case <-donec: 2396 return 2397 default: 2398 } 2399 } 2400 t.Errorf("Do of canceled request has not returned after %v", timeout) 2401 } 2402 2403 func TestTransportCancelRequestInDo(t *testing.T) { 2404 testTransportCancelRequestInDo(t, nil) 2405 } 2406 2407 func TestTransportCancelRequestWithBodyInDo(t *testing.T) { 2408 testTransportCancelRequestInDo(t, bytes.NewBuffer([]byte{0})) 2409 } 2410 2411 func TestTransportCancelRequestInDial(t *testing.T) { 2412 defer afterTest(t) 2413 if testing.Short() { 2414 t.Skip("skipping test in -short mode") 2415 } 2416 var logbuf bytes.Buffer 2417 eventLog := log.New(&logbuf, "", 0) 2418 2419 unblockDial := make(chan bool) 2420 defer close(unblockDial) 2421 2422 inDial := make(chan bool) 2423 tr := &Transport{ 2424 Dial: func(network, addr string) (net.Conn, error) { 2425 eventLog.Println("dial: blocking") 2426 if !<-inDial { 2427 return nil, errors.New("main Test goroutine exited") 2428 } 2429 <-unblockDial 2430 return nil, errors.New("nope") 2431 }, 2432 } 2433 cl := &Client{Transport: tr} 2434 gotres := make(chan bool) 2435 req, _ := NewRequest("GET", "http://something.no-network.tld/", nil) 2436 go func() { 2437 _, err := cl.Do(req) 2438 eventLog.Printf("Get = %v", err) 2439 gotres <- true 2440 }() 2441 2442 select { 2443 case inDial <- true: 2444 case <-time.After(5 * time.Second): 2445 close(inDial) 2446 t.Fatal("timeout; never saw blocking dial") 2447 } 2448 2449 eventLog.Printf("canceling") 2450 tr.CancelRequest(req) 2451 tr.CancelRequest(req) // used to panic on second call 2452 2453 select { 2454 case <-gotres: 2455 case <-time.After(5 * time.Second): 2456 panic("hang. events are: " + logbuf.String()) 2457 } 2458 2459 got := logbuf.String() 2460 want := `dial: blocking 2461 canceling 2462 Get = Get "http://something.no-network.tld/": net/http: request canceled while waiting for connection 2463 ` 2464 if got != want { 2465 t.Errorf("Got events:\n%s\nWant:\n%s", got, want) 2466 } 2467 } 2468 2469 func TestCancelRequestWithChannel(t *testing.T) { 2470 setParallel(t) 2471 defer afterTest(t) 2472 if testing.Short() { 2473 t.Skip("skipping test in -short mode") 2474 } 2475 unblockc := make(chan bool) 2476 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2477 fmt.Fprintf(w, "Hello") 2478 w.(Flusher).Flush() // send headers and some body 2479 <-unblockc 2480 })) 2481 defer ts.Close() 2482 defer close(unblockc) 2483 2484 c := ts.Client() 2485 tr := c.Transport.(*Transport) 2486 2487 req, _ := NewRequest("GET", ts.URL, nil) 2488 ch := make(chan struct{}) 2489 req.Cancel = ch 2490 2491 res, err := c.Do(req) 2492 if err != nil { 2493 t.Fatal(err) 2494 } 2495 go func() { 2496 time.Sleep(1 * time.Second) 2497 close(ch) 2498 }() 2499 t0 := time.Now() 2500 body, err := io.ReadAll(res.Body) 2501 d := time.Since(t0) 2502 2503 if err != ExportErrRequestCanceled { 2504 t.Errorf("Body.Read error = %v; want errRequestCanceled", err) 2505 } 2506 if string(body) != "Hello" { 2507 t.Errorf("Body = %q; want Hello", body) 2508 } 2509 if d < 500*time.Millisecond { 2510 t.Errorf("expected ~1 second delay; got %v", d) 2511 } 2512 // Verify no outstanding requests after readLoop/writeLoop 2513 // goroutines shut down. 2514 for tries := 5; tries > 0; tries-- { 2515 n := tr.NumPendingRequestsForTesting() 2516 if n == 0 { 2517 break 2518 } 2519 time.Sleep(100 * time.Millisecond) 2520 if tries == 1 { 2521 t.Errorf("pending requests = %d; want 0", n) 2522 } 2523 } 2524 } 2525 2526 func TestCancelRequestWithChannelBeforeDo_Cancel(t *testing.T) { 2527 testCancelRequestWithChannelBeforeDo(t, false) 2528 } 2529 func TestCancelRequestWithChannelBeforeDo_Context(t *testing.T) { 2530 testCancelRequestWithChannelBeforeDo(t, true) 2531 } 2532 func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) { 2533 setParallel(t) 2534 defer afterTest(t) 2535 unblockc := make(chan bool) 2536 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2537 <-unblockc 2538 })) 2539 defer ts.Close() 2540 defer close(unblockc) 2541 2542 c := ts.Client() 2543 2544 req, _ := NewRequest("GET", ts.URL, nil) 2545 if withCtx { 2546 ctx, cancel := context.WithCancel(context.Background()) 2547 cancel() 2548 req = req.WithContext(ctx) 2549 } else { 2550 ch := make(chan struct{}) 2551 req.Cancel = ch 2552 close(ch) 2553 } 2554 2555 _, err := c.Do(req) 2556 if ue, ok := err.(*url.Error); ok { 2557 err = ue.Err 2558 } 2559 if withCtx { 2560 if err != context.Canceled { 2561 t.Errorf("Do error = %v; want %v", err, context.Canceled) 2562 } 2563 } else { 2564 if err == nil || !strings.Contains(err.Error(), "canceled") { 2565 t.Errorf("Do error = %v; want cancellation", err) 2566 } 2567 } 2568 } 2569 2570 // Issue 11020. The returned error message should be errRequestCanceled 2571 func TestTransportCancelBeforeResponseHeaders(t *testing.T) { 2572 defer afterTest(t) 2573 2574 serverConnCh := make(chan net.Conn, 1) 2575 tr := &Transport{ 2576 Dial: func(network, addr string) (net.Conn, error) { 2577 cc, sc := net.Pipe() 2578 serverConnCh <- sc 2579 return cc, nil 2580 }, 2581 } 2582 defer tr.CloseIdleConnections() 2583 errc := make(chan error, 1) 2584 req, _ := NewRequest("GET", "http://example.com/", nil) 2585 go func() { 2586 _, err := tr.RoundTrip(req) 2587 errc <- err 2588 }() 2589 2590 sc := <-serverConnCh 2591 verb := make([]byte, 3) 2592 if _, err := io.ReadFull(sc, verb); err != nil { 2593 t.Errorf("Error reading HTTP verb from server: %v", err) 2594 } 2595 if string(verb) != "GET" { 2596 t.Errorf("server received %q; want GET", verb) 2597 } 2598 defer sc.Close() 2599 2600 tr.CancelRequest(req) 2601 2602 err := <-errc 2603 if err == nil { 2604 t.Fatalf("unexpected success from RoundTrip") 2605 } 2606 if err != ExportErrRequestCanceled { 2607 t.Errorf("RoundTrip error = %v; want ExportErrRequestCanceled", err) 2608 } 2609 } 2610 2611 // golang.org/issue/3672 -- Client can't close HTTP stream 2612 // Calling Close on a Response.Body used to just read until EOF. 2613 // Now it actually closes the TCP connection. 2614 func TestTransportCloseResponseBody(t *testing.T) { 2615 defer afterTest(t) 2616 writeErr := make(chan error, 1) 2617 msg := []byte("young\n") 2618 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 2619 for { 2620 _, err := w.Write(msg) 2621 if err != nil { 2622 writeErr <- err 2623 return 2624 } 2625 w.(Flusher).Flush() 2626 } 2627 })) 2628 defer ts.Close() 2629 2630 c := ts.Client() 2631 tr := c.Transport.(*Transport) 2632 2633 req, _ := NewRequest("GET", ts.URL, nil) 2634 defer tr.CancelRequest(req) 2635 2636 res, err := c.Do(req) 2637 if err != nil { 2638 t.Fatal(err) 2639 } 2640 2641 const repeats = 3 2642 buf := make([]byte, len(msg)*repeats) 2643 want := bytes.Repeat(msg, repeats) 2644 2645 _, err = io.ReadFull(res.Body, buf) 2646 if err != nil { 2647 t.Fatal(err) 2648 } 2649 if !bytes.Equal(buf, want) { 2650 t.Fatalf("read %q; want %q", buf, want) 2651 } 2652 didClose := make(chan error, 1) 2653 go func() { 2654 didClose <- res.Body.Close() 2655 }() 2656 select { 2657 case err := <-didClose: 2658 if err != nil { 2659 t.Errorf("Close = %v", err) 2660 } 2661 case <-time.After(10 * time.Second): 2662 t.Fatal("too long waiting for close") 2663 } 2664 select { 2665 case err := <-writeErr: 2666 if err == nil { 2667 t.Errorf("expected non-nil write error") 2668 } 2669 case <-time.After(10 * time.Second): 2670 t.Fatal("too long waiting for write error") 2671 } 2672 } 2673 2674 type fooProto struct{} 2675 2676 func (fooProto) RoundTrip(req *Request) (*Response, error) { 2677 res := &Response{ 2678 Status: "200 OK", 2679 StatusCode: 200, 2680 Header: make(Header), 2681 Body: io.NopCloser(strings.NewReader("You wanted " + req.URL.String())), 2682 } 2683 return res, nil 2684 } 2685 2686 func TestTransportAltProto(t *testing.T) { 2687 defer afterTest(t) 2688 tr := &Transport{} 2689 c := &Client{Transport: tr} 2690 tr.RegisterProtocol("foo", fooProto{}) 2691 res, err := c.Get("foo://bar.com/path") 2692 if err != nil { 2693 t.Fatal(err) 2694 } 2695 bodyb, err := io.ReadAll(res.Body) 2696 if err != nil { 2697 t.Fatal(err) 2698 } 2699 body := string(bodyb) 2700 if e := "You wanted foo://bar.com/path"; body != e { 2701 t.Errorf("got response %q, want %q", body, e) 2702 } 2703 } 2704 2705 func TestTransportNoHost(t *testing.T) { 2706 defer afterTest(t) 2707 tr := &Transport{} 2708 _, err := tr.RoundTrip(&Request{ 2709 Header: make(Header), 2710 URL: &url.URL{ 2711 Scheme: "http", 2712 }, 2713 }) 2714 want := "http: no Host in request URL" 2715 if got := fmt.Sprint(err); got != want { 2716 t.Errorf("error = %v; want %q", err, want) 2717 } 2718 } 2719 2720 // Issue 13311 2721 func TestTransportEmptyMethod(t *testing.T) { 2722 req, _ := NewRequest("GET", "http://foo.com/", nil) 2723 req.Method = "" // docs say "For client requests an empty string means GET" 2724 got, err := httputil.DumpRequestOut(req, false) // DumpRequestOut uses Transport 2725 if err != nil { 2726 t.Fatal(err) 2727 } 2728 if !strings.Contains(string(got), "GET ") { 2729 t.Fatalf("expected substring 'GET '; got: %s", got) 2730 } 2731 } 2732 2733 func TestTransportSocketLateBinding(t *testing.T) { 2734 setParallel(t) 2735 defer afterTest(t) 2736 2737 mux := NewServeMux() 2738 fooGate := make(chan bool, 1) 2739 mux.HandleFunc("/foo", func(w ResponseWriter, r *Request) { 2740 w.Header().Set("foo-ipport", r.RemoteAddr) 2741 w.(Flusher).Flush() 2742 <-fooGate 2743 }) 2744 mux.HandleFunc("/bar", func(w ResponseWriter, r *Request) { 2745 w.Header().Set("bar-ipport", r.RemoteAddr) 2746 }) 2747 ts := httptest.NewServer(mux) 2748 defer ts.Close() 2749 2750 dialGate := make(chan bool, 1) 2751 c := ts.Client() 2752 c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) { 2753 if <-dialGate { 2754 return net.Dial(n, addr) 2755 } 2756 return nil, errors.New("manually closed") 2757 } 2758 2759 dialGate <- true // only allow one dial 2760 fooRes, err := c.Get(ts.URL + "/foo") 2761 if err != nil { 2762 t.Fatal(err) 2763 } 2764 fooAddr := fooRes.Header.Get("foo-ipport") 2765 if fooAddr == "" { 2766 t.Fatal("No addr on /foo request") 2767 } 2768 time.AfterFunc(200*time.Millisecond, func() { 2769 // let the foo response finish so we can use its 2770 // connection for /bar 2771 fooGate <- true 2772 io.Copy(io.Discard, fooRes.Body) 2773 fooRes.Body.Close() 2774 }) 2775 2776 barRes, err := c.Get(ts.URL + "/bar") 2777 if err != nil { 2778 t.Fatal(err) 2779 } 2780 barAddr := barRes.Header.Get("bar-ipport") 2781 if barAddr != fooAddr { 2782 t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr) 2783 } 2784 barRes.Body.Close() 2785 dialGate <- false 2786 } 2787 2788 // Issue 2184 2789 func TestTransportReading100Continue(t *testing.T) { 2790 defer afterTest(t) 2791 2792 const numReqs = 5 2793 reqBody := func(n int) string { return fmt.Sprintf("request body %d", n) } 2794 reqID := func(n int) string { return fmt.Sprintf("REQ-ID-%d", n) } 2795 2796 send100Response := func(w *io.PipeWriter, r *io.PipeReader) { 2797 defer w.Close() 2798 defer r.Close() 2799 br := bufio.NewReader(r) 2800 n := 0 2801 for { 2802 n++ 2803 req, err := ReadRequest(br) 2804 if err == io.EOF { 2805 return 2806 } 2807 if err != nil { 2808 t.Error(err) 2809 return 2810 } 2811 slurp, err := io.ReadAll(req.Body) 2812 if err != nil { 2813 t.Errorf("Server request body slurp: %v", err) 2814 return 2815 } 2816 id := req.Header.Get("Request-Id") 2817 resCode := req.Header.Get("X-Want-Response-Code") 2818 if resCode == "" { 2819 resCode = "100 Continue" 2820 if string(slurp) != reqBody(n) { 2821 t.Errorf("Server got %q, %v; want %q", slurp, err, reqBody(n)) 2822 } 2823 } 2824 body := fmt.Sprintf("Response number %d", n) 2825 v := []byte(strings.Replace(fmt.Sprintf(`HTTP/1.1 %s 2826 Date: Thu, 28 Feb 2013 17:55:41 GMT 2827 2828 HTTP/1.1 200 OK 2829 Content-Type: text/html 2830 Echo-Request-Id: %s 2831 Content-Length: %d 2832 2833 %s`, resCode, id, len(body), body), "\n", "\r\n", -1)) 2834 w.Write(v) 2835 if id == reqID(numReqs) { 2836 return 2837 } 2838 } 2839 2840 } 2841 2842 tr := &Transport{ 2843 Dial: func(n, addr string) (net.Conn, error) { 2844 sr, sw := io.Pipe() // server read/write 2845 cr, cw := io.Pipe() // client read/write 2846 conn := &rwTestConn{ 2847 Reader: cr, 2848 Writer: sw, 2849 closeFunc: func() error { 2850 sw.Close() 2851 cw.Close() 2852 return nil 2853 }, 2854 } 2855 go send100Response(cw, sr) 2856 return conn, nil 2857 }, 2858 DisableKeepAlives: false, 2859 } 2860 defer tr.CloseIdleConnections() 2861 c := &Client{Transport: tr} 2862 2863 testResponse := func(req *Request, name string, wantCode int) { 2864 t.Helper() 2865 res, err := c.Do(req) 2866 if err != nil { 2867 t.Fatalf("%s: Do: %v", name, err) 2868 } 2869 if res.StatusCode != wantCode { 2870 t.Fatalf("%s: Response Statuscode=%d; want %d", name, res.StatusCode, wantCode) 2871 } 2872 if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack { 2873 t.Errorf("%s: response id %q != request id %q", name, idBack, id) 2874 } 2875 _, err = io.ReadAll(res.Body) 2876 if err != nil { 2877 t.Fatalf("%s: Slurp error: %v", name, err) 2878 } 2879 } 2880 2881 // Few 100 responses, making sure we're not off-by-one. 2882 for i := 1; i <= numReqs; i++ { 2883 req, _ := NewRequest("POST", "http://dummy.tld/", strings.NewReader(reqBody(i))) 2884 req.Header.Set("Request-Id", reqID(i)) 2885 testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200) 2886 } 2887 } 2888 2889 // Issue 17739: the HTTP client must ignore any unknown 1xx 2890 // informational responses before the actual response. 2891 func TestTransportIgnore1xxResponses(t *testing.T) { 2892 setParallel(t) 2893 defer afterTest(t) 2894 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 2895 conn, buf, _ := w.(Hijacker).Hijack() 2896 buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\nFoo: bar\r\n\r\nHTTP/1.1 200 OK\r\nBar: baz\r\nContent-Length: 5\r\n\r\nHello")) 2897 buf.Flush() 2898 conn.Close() 2899 })) 2900 defer cst.close() 2901 cst.tr.DisableKeepAlives = true // prevent log spam; our test server is hanging up anyway 2902 2903 var got bytes.Buffer 2904 2905 req, _ := NewRequest("GET", cst.ts.URL, nil) 2906 req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ 2907 Got1xxResponse: func(code int, header textproto.MIMEHeader) error { 2908 fmt.Fprintf(&got, "1xx: code=%v, header=%v\n", code, header) 2909 return nil 2910 }, 2911 })) 2912 res, err := cst.c.Do(req) 2913 if err != nil { 2914 t.Fatal(err) 2915 } 2916 defer res.Body.Close() 2917 2918 res.Write(&got) 2919 want := "1xx: code=123, header=map[Foo:[bar]]\nHTTP/1.1 200 OK\r\nContent-Length: 5\r\nBar: baz\r\n\r\nHello" 2920 if got.String() != want { 2921 t.Errorf(" got: %q\nwant: %q\n", got.Bytes(), want) 2922 } 2923 } 2924 2925 func TestTransportLimits1xxResponses(t *testing.T) { 2926 setParallel(t) 2927 defer afterTest(t) 2928 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 2929 conn, buf, _ := w.(Hijacker).Hijack() 2930 for i := 0; i < 10; i++ { 2931 buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\n\r\n")) 2932 } 2933 buf.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n")) 2934 buf.Flush() 2935 conn.Close() 2936 })) 2937 defer cst.close() 2938 cst.tr.DisableKeepAlives = true // prevent log spam; our test server is hanging up anyway 2939 2940 res, err := cst.c.Get(cst.ts.URL) 2941 if res != nil { 2942 defer res.Body.Close() 2943 } 2944 got := fmt.Sprint(err) 2945 wantSub := "too many 1xx informational responses" 2946 if !strings.Contains(got, wantSub) { 2947 t.Errorf("Get error = %v; want substring %q", err, wantSub) 2948 } 2949 } 2950 2951 // Issue 26161: the HTTP client must treat 101 responses 2952 // as the final response. 2953 func TestTransportTreat101Terminal(t *testing.T) { 2954 setParallel(t) 2955 defer afterTest(t) 2956 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 2957 conn, buf, _ := w.(Hijacker).Hijack() 2958 buf.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n\r\n")) 2959 buf.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n")) 2960 buf.Flush() 2961 conn.Close() 2962 })) 2963 defer cst.close() 2964 res, err := cst.c.Get(cst.ts.URL) 2965 if err != nil { 2966 t.Fatal(err) 2967 } 2968 defer res.Body.Close() 2969 if res.StatusCode != StatusSwitchingProtocols { 2970 t.Errorf("StatusCode = %v; want 101 Switching Protocols", res.StatusCode) 2971 } 2972 } 2973 2974 type proxyFromEnvTest struct { 2975 req string // URL to fetch; blank means "http://example.com" 2976 2977 env string // HTTP_PROXY 2978 httpsenv string // HTTPS_PROXY 2979 noenv string // NO_PROXY 2980 reqmeth string // REQUEST_METHOD 2981 2982 want string 2983 wanterr error 2984 } 2985 2986 func (t proxyFromEnvTest) String() string { 2987 var buf bytes.Buffer 2988 space := func() { 2989 if buf.Len() > 0 { 2990 buf.WriteByte(' ') 2991 } 2992 } 2993 if t.env != "" { 2994 fmt.Fprintf(&buf, "http_proxy=%q", t.env) 2995 } 2996 if t.httpsenv != "" { 2997 space() 2998 fmt.Fprintf(&buf, "https_proxy=%q", t.httpsenv) 2999 } 3000 if t.noenv != "" { 3001 space() 3002 fmt.Fprintf(&buf, "no_proxy=%q", t.noenv) 3003 } 3004 if t.reqmeth != "" { 3005 space() 3006 fmt.Fprintf(&buf, "request_method=%q", t.reqmeth) 3007 } 3008 req := "http://example.com" 3009 if t.req != "" { 3010 req = t.req 3011 } 3012 space() 3013 fmt.Fprintf(&buf, "req=%q", req) 3014 return strings.TrimSpace(buf.String()) 3015 } 3016 3017 var proxyFromEnvTests = []proxyFromEnvTest{ 3018 {env: "127.0.0.1:8080", want: "http://127.0.0.1:8080"}, 3019 {env: "cache.corp.example.com:1234", want: "http://cache.corp.example.com:1234"}, 3020 {env: "cache.corp.example.com", want: "http://cache.corp.example.com"}, 3021 {env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"}, 3022 {env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"}, 3023 {env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"}, 3024 {env: "socks5://127.0.0.1", want: "socks5://127.0.0.1"}, 3025 3026 // Don't use secure for http 3027 {req: "http://insecure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://http.proxy.tld"}, 3028 // Use secure for https. 3029 {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://secure.proxy.tld"}, 3030 {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "https://secure.proxy.tld", want: "https://secure.proxy.tld"}, 3031 3032 // Issue 16405: don't use HTTP_PROXY in a CGI environment, 3033 // where HTTP_PROXY can be attacker-controlled. 3034 {env: "http://10.1.2.3:8080", reqmeth: "POST", 3035 want: "<nil>", 3036 wanterr: errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")}, 3037 3038 {want: "<nil>"}, 3039 3040 {noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"}, 3041 {noenv: ".example.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 3042 {noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 3043 {noenv: "example.com", req: "http://foo.example.com/", env: "proxy", want: "<nil>"}, 3044 {noenv: ".foo.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, 3045 } 3046 3047 func testProxyForRequest(t *testing.T, tt proxyFromEnvTest, proxyForRequest func(req *Request) (*url.URL, error)) { 3048 t.Helper() 3049 reqURL := tt.req 3050 if reqURL == "" { 3051 reqURL = "http://example.com" 3052 } 3053 req, _ := NewRequest("GET", reqURL, nil) 3054 url, err := proxyForRequest(req) 3055 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e { 3056 t.Errorf("%v: got error = %q, want %q", tt, g, e) 3057 return 3058 } 3059 if got := fmt.Sprintf("%s", url); got != tt.want { 3060 t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want) 3061 } 3062 } 3063 3064 func TestProxyFromEnvironment(t *testing.T) { 3065 ResetProxyEnv() 3066 defer ResetProxyEnv() 3067 for _, tt := range proxyFromEnvTests { 3068 testProxyForRequest(t, tt, func(req *Request) (*url.URL, error) { 3069 os.Setenv("HTTP_PROXY", tt.env) 3070 os.Setenv("HTTPS_PROXY", tt.httpsenv) 3071 os.Setenv("NO_PROXY", tt.noenv) 3072 os.Setenv("REQUEST_METHOD", tt.reqmeth) 3073 ResetCachedEnvironment() 3074 return ProxyFromEnvironment(req) 3075 }) 3076 } 3077 } 3078 3079 func TestProxyFromEnvironmentLowerCase(t *testing.T) { 3080 ResetProxyEnv() 3081 defer ResetProxyEnv() 3082 for _, tt := range proxyFromEnvTests { 3083 testProxyForRequest(t, tt, func(req *Request) (*url.URL, error) { 3084 os.Setenv("http_proxy", tt.env) 3085 os.Setenv("https_proxy", tt.httpsenv) 3086 os.Setenv("no_proxy", tt.noenv) 3087 os.Setenv("REQUEST_METHOD", tt.reqmeth) 3088 ResetCachedEnvironment() 3089 return ProxyFromEnvironment(req) 3090 }) 3091 } 3092 } 3093 3094 func TestIdleConnChannelLeak(t *testing.T) { 3095 // Not parallel: uses global test hooks. 3096 var mu sync.Mutex 3097 var n int 3098 3099 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3100 mu.Lock() 3101 n++ 3102 mu.Unlock() 3103 })) 3104 defer ts.Close() 3105 3106 const nReqs = 5 3107 didRead := make(chan bool, nReqs) 3108 SetReadLoopBeforeNextReadHook(func() { didRead <- true }) 3109 defer SetReadLoopBeforeNextReadHook(nil) 3110 3111 c := ts.Client() 3112 tr := c.Transport.(*Transport) 3113 tr.Dial = func(netw, addr string) (net.Conn, error) { 3114 return net.Dial(netw, ts.Listener.Addr().String()) 3115 } 3116 3117 // First, without keep-alives. 3118 for _, disableKeep := range []bool{true, false} { 3119 tr.DisableKeepAlives = disableKeep 3120 for i := 0; i < nReqs; i++ { 3121 _, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i)) 3122 if err != nil { 3123 t.Fatal(err) 3124 } 3125 // Note: no res.Body.Close is needed here, since the 3126 // response Content-Length is zero. Perhaps the test 3127 // should be more explicit and use a HEAD, but tests 3128 // elsewhere guarantee that zero byte responses generate 3129 // a "Content-Length: 0" instead of chunking. 3130 } 3131 3132 // At this point, each of the 5 Transport.readLoop goroutines 3133 // are scheduling noting that there are no response bodies (see 3134 // earlier comment), and are then calling putIdleConn, which 3135 // decrements this count. Usually that happens quickly, which is 3136 // why this test has seemed to work for ages. But it's still 3137 // racey: we have wait for them to finish first. See Issue 10427 3138 for i := 0; i < nReqs; i++ { 3139 <-didRead 3140 } 3141 3142 if got := tr.IdleConnWaitMapSizeForTesting(); got != 0 { 3143 t.Fatalf("for DisableKeepAlives = %v, map size = %d; want 0", disableKeep, got) 3144 } 3145 } 3146 } 3147 3148 // Verify the status quo: that the Client.Post function coerces its 3149 // body into a ReadCloser if it's a Closer, and that the Transport 3150 // then closes it. 3151 func TestTransportClosesRequestBody(t *testing.T) { 3152 defer afterTest(t) 3153 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3154 io.Copy(io.Discard, r.Body) 3155 })) 3156 defer ts.Close() 3157 3158 c := ts.Client() 3159 3160 closes := 0 3161 3162 res, err := c.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")}) 3163 if err != nil { 3164 t.Fatal(err) 3165 } 3166 res.Body.Close() 3167 if closes != 1 { 3168 t.Errorf("closes = %d; want 1", closes) 3169 } 3170 } 3171 3172 func TestTransportTLSHandshakeTimeout(t *testing.T) { 3173 defer afterTest(t) 3174 if testing.Short() { 3175 t.Skip("skipping in short mode") 3176 } 3177 ln := newLocalListener(t) 3178 defer ln.Close() 3179 testdonec := make(chan struct{}) 3180 defer close(testdonec) 3181 3182 go func() { 3183 c, err := ln.Accept() 3184 if err != nil { 3185 t.Error(err) 3186 return 3187 } 3188 <-testdonec 3189 c.Close() 3190 }() 3191 3192 getdonec := make(chan struct{}) 3193 go func() { 3194 defer close(getdonec) 3195 tr := &Transport{ 3196 Dial: func(_, _ string) (net.Conn, error) { 3197 return net.Dial("tcp", ln.Addr().String()) 3198 }, 3199 TLSHandshakeTimeout: 250 * time.Millisecond, 3200 } 3201 cl := &Client{Transport: tr} 3202 _, err := cl.Get("https://dummy.tld/") 3203 if err == nil { 3204 t.Error("expected error") 3205 return 3206 } 3207 ue, ok := err.(*url.Error) 3208 if !ok { 3209 t.Errorf("expected url.Error; got %#v", err) 3210 return 3211 } 3212 ne, ok := ue.Err.(net.Error) 3213 if !ok { 3214 t.Errorf("expected net.Error; got %#v", err) 3215 return 3216 } 3217 if !ne.Timeout() { 3218 t.Errorf("expected timeout error; got %v", err) 3219 } 3220 if !strings.Contains(err.Error(), "handshake timeout") { 3221 t.Errorf("expected 'handshake timeout' in error; got %v", err) 3222 } 3223 }() 3224 select { 3225 case <-getdonec: 3226 case <-time.After(5 * time.Second): 3227 t.Error("test timeout; TLS handshake hung?") 3228 } 3229 } 3230 3231 // Trying to repro golang.org/issue/3514 3232 func TestTLSServerClosesConnection(t *testing.T) { 3233 defer afterTest(t) 3234 3235 closedc := make(chan bool, 1) 3236 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3237 if strings.Contains(r.URL.Path, "/keep-alive-then-die") { 3238 conn, _, _ := w.(Hijacker).Hijack() 3239 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) 3240 conn.Close() 3241 closedc <- true 3242 return 3243 } 3244 fmt.Fprintf(w, "hello") 3245 })) 3246 defer ts.Close() 3247 3248 c := ts.Client() 3249 tr := c.Transport.(*Transport) 3250 3251 var nSuccess = 0 3252 var errs []error 3253 const trials = 20 3254 for i := 0; i < trials; i++ { 3255 tr.CloseIdleConnections() 3256 res, err := c.Get(ts.URL + "/keep-alive-then-die") 3257 if err != nil { 3258 t.Fatal(err) 3259 } 3260 <-closedc 3261 slurp, err := io.ReadAll(res.Body) 3262 if err != nil { 3263 t.Fatal(err) 3264 } 3265 if string(slurp) != "foo" { 3266 t.Errorf("Got %q, want foo", slurp) 3267 } 3268 3269 // Now try again and see if we successfully 3270 // pick a new connection. 3271 res, err = c.Get(ts.URL + "/") 3272 if err != nil { 3273 errs = append(errs, err) 3274 continue 3275 } 3276 slurp, err = io.ReadAll(res.Body) 3277 if err != nil { 3278 errs = append(errs, err) 3279 continue 3280 } 3281 nSuccess++ 3282 } 3283 if nSuccess > 0 { 3284 t.Logf("successes = %d of %d", nSuccess, trials) 3285 } else { 3286 t.Errorf("All runs failed:") 3287 } 3288 for _, err := range errs { 3289 t.Logf(" err: %v", err) 3290 } 3291 } 3292 3293 // byteFromChanReader is an io.Reader that reads a single byte at a 3294 // time from the channel. When the channel is closed, the reader 3295 // returns io.EOF. 3296 type byteFromChanReader chan byte 3297 3298 func (c byteFromChanReader) Read(p []byte) (n int, err error) { 3299 if len(p) == 0 { 3300 return 3301 } 3302 b, ok := <-c 3303 if !ok { 3304 return 0, io.EOF 3305 } 3306 p[0] = b 3307 return 1, nil 3308 } 3309 3310 // Verifies that the Transport doesn't reuse a connection in the case 3311 // where the server replies before the request has been fully 3312 // written. We still honor that reply (see TestIssue3595), but don't 3313 // send future requests on the connection because it's then in a 3314 // questionable state. 3315 // golang.org/issue/7569 3316 func TestTransportNoReuseAfterEarlyResponse(t *testing.T) { 3317 setParallel(t) 3318 defer afterTest(t) 3319 var sconn struct { 3320 sync.Mutex 3321 c net.Conn 3322 } 3323 var getOkay bool 3324 closeConn := func() { 3325 sconn.Lock() 3326 defer sconn.Unlock() 3327 if sconn.c != nil { 3328 sconn.c.Close() 3329 sconn.c = nil 3330 if !getOkay { 3331 t.Logf("Closed server connection") 3332 } 3333 } 3334 } 3335 defer closeConn() 3336 3337 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3338 if r.Method == "GET" { 3339 io.WriteString(w, "bar") 3340 return 3341 } 3342 conn, _, _ := w.(Hijacker).Hijack() 3343 sconn.Lock() 3344 sconn.c = conn 3345 sconn.Unlock() 3346 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive 3347 go io.Copy(io.Discard, conn) 3348 })) 3349 defer ts.Close() 3350 c := ts.Client() 3351 3352 const bodySize = 256 << 10 3353 finalBit := make(byteFromChanReader, 1) 3354 req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit)) 3355 req.ContentLength = bodySize 3356 res, err := c.Do(req) 3357 if err := wantBody(res, err, "foo"); err != nil { 3358 t.Errorf("POST response: %v", err) 3359 } 3360 donec := make(chan bool) 3361 go func() { 3362 defer close(donec) 3363 res, err = c.Get(ts.URL) 3364 if err := wantBody(res, err, "bar"); err != nil { 3365 t.Errorf("GET response: %v", err) 3366 return 3367 } 3368 getOkay = true // suppress test noise 3369 }() 3370 time.AfterFunc(5*time.Second, closeConn) 3371 select { 3372 case <-donec: 3373 finalBit <- 'x' // unblock the writeloop of the first Post 3374 close(finalBit) 3375 case <-time.After(7 * time.Second): 3376 t.Fatal("timeout waiting for GET request to finish") 3377 } 3378 } 3379 3380 // Tests that we don't leak Transport persistConn.readLoop goroutines 3381 // when a server hangs up immediately after saying it would keep-alive. 3382 func TestTransportIssue10457(t *testing.T) { 3383 defer afterTest(t) // used to fail in goroutine leak check 3384 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3385 // Send a response with no body, keep-alive 3386 // (implicit), and then lie and immediately close the 3387 // connection. This forces the Transport's readLoop to 3388 // immediately Peek an io.EOF and get to the point 3389 // that used to hang. 3390 conn, _, _ := w.(Hijacker).Hijack() 3391 conn.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n")) // keep-alive 3392 conn.Close() 3393 })) 3394 defer ts.Close() 3395 c := ts.Client() 3396 3397 res, err := c.Get(ts.URL) 3398 if err != nil { 3399 t.Fatalf("Get: %v", err) 3400 } 3401 defer res.Body.Close() 3402 3403 // Just a sanity check that we at least get the response. The real 3404 // test here is that the "defer afterTest" above doesn't find any 3405 // leaked goroutines. 3406 if got, want := res.Header.Get("Foo"), "Bar"; got != want { 3407 t.Errorf("Foo header = %q; want %q", got, want) 3408 } 3409 } 3410 3411 type closerFunc func() error 3412 3413 func (f closerFunc) Close() error { return f() } 3414 3415 type writerFuncConn struct { 3416 net.Conn 3417 write func(p []byte) (n int, err error) 3418 } 3419 3420 func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) } 3421 3422 // Issues 4677, 18241, and 17844. If we try to reuse a connection that the 3423 // server is in the process of closing, we may end up successfully writing out 3424 // our request (or a portion of our request) only to find a connection error 3425 // when we try to read from (or finish writing to) the socket. 3426 // 3427 // NOTE: we resend a request only if: 3428 // - we reused a keep-alive connection 3429 // - we haven't yet received any header data 3430 // - either we wrote no bytes to the server, or the request is idempotent 3431 // This automatically prevents an infinite resend loop because we'll run out of 3432 // the cached keep-alive connections eventually. 3433 func TestRetryRequestsOnError(t *testing.T) { 3434 newRequest := func(method, urlStr string, body io.Reader) *Request { 3435 req, err := NewRequest(method, urlStr, body) 3436 if err != nil { 3437 t.Fatal(err) 3438 } 3439 return req 3440 } 3441 3442 testCases := []struct { 3443 name string 3444 failureN int 3445 failureErr error 3446 // Note that we can't just re-use the Request object across calls to c.Do 3447 // because we need to rewind Body between calls. (GetBody is only used to 3448 // rewind Body on failure and redirects, not just because it's done.) 3449 req func() *Request 3450 reqString string 3451 }{ 3452 { 3453 name: "IdempotentNoBodySomeWritten", 3454 // Believe that we've written some bytes to the server, so we know we're 3455 // not just in the "retry when no bytes sent" case". 3456 failureN: 1, 3457 // Use the specific error that shouldRetryRequest looks for with idempotent requests. 3458 failureErr: ExportErrServerClosedIdle, 3459 req: func() *Request { 3460 return newRequest("GET", "http://fake.golang", nil) 3461 }, 3462 reqString: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`, 3463 }, 3464 { 3465 name: "IdempotentGetBodySomeWritten", 3466 // Believe that we've written some bytes to the server, so we know we're 3467 // not just in the "retry when no bytes sent" case". 3468 failureN: 1, 3469 // Use the specific error that shouldRetryRequest looks for with idempotent requests. 3470 failureErr: ExportErrServerClosedIdle, 3471 req: func() *Request { 3472 return newRequest("GET", "http://fake.golang", strings.NewReader("foo\n")) 3473 }, 3474 reqString: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`, 3475 }, 3476 { 3477 name: "NothingWrittenNoBody", 3478 // It's Key that we return 0 here -- that's what enables Transport to know 3479 // that nothing was written, even though this is a non-idempotent request. 3480 failureN: 0, 3481 failureErr: errors.New("second write fails"), 3482 req: func() *Request { 3483 return newRequest("DELETE", "http://fake.golang", nil) 3484 }, 3485 reqString: `DELETE / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`, 3486 }, 3487 { 3488 name: "NothingWrittenGetBody", 3489 // It's Key that we return 0 here -- that's what enables Transport to know 3490 // that nothing was written, even though this is a non-idempotent request. 3491 failureN: 0, 3492 failureErr: errors.New("second write fails"), 3493 // Note that NewRequest will set up GetBody for strings.Reader, which is 3494 // required for the retry to occur 3495 req: func() *Request { 3496 return newRequest("POST", "http://fake.golang", strings.NewReader("foo\n")) 3497 }, 3498 reqString: `POST / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`, 3499 }, 3500 } 3501 3502 for _, tc := range testCases { 3503 t.Run(tc.name, func(t *testing.T) { 3504 defer afterTest(t) 3505 3506 var ( 3507 mu sync.Mutex 3508 logbuf bytes.Buffer 3509 ) 3510 logf := func(format string, args ...interface{}) { 3511 mu.Lock() 3512 defer mu.Unlock() 3513 fmt.Fprintf(&logbuf, format, args...) 3514 logbuf.WriteByte('\n') 3515 } 3516 3517 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3518 logf("Handler") 3519 w.Header().Set("X-Status", "ok") 3520 })) 3521 defer ts.Close() 3522 3523 var writeNumAtomic int32 3524 c := ts.Client() 3525 c.Transport.(*Transport).Dial = func(network, addr string) (net.Conn, error) { 3526 logf("Dial") 3527 c, err := net.Dial(network, ts.Listener.Addr().String()) 3528 if err != nil { 3529 logf("Dial error: %v", err) 3530 return nil, err 3531 } 3532 return &writerFuncConn{ 3533 Conn: c, 3534 write: func(p []byte) (n int, err error) { 3535 if atomic.AddInt32(&writeNumAtomic, 1) == 2 { 3536 logf("intentional write failure") 3537 return tc.failureN, tc.failureErr 3538 } 3539 logf("Write(%q)", p) 3540 return c.Write(p) 3541 }, 3542 }, nil 3543 } 3544 3545 SetRoundTripRetried(func() { 3546 logf("Retried.") 3547 }) 3548 defer SetRoundTripRetried(nil) 3549 3550 for i := 0; i < 3; i++ { 3551 t0 := time.Now() 3552 req := tc.req() 3553 res, err := c.Do(req) 3554 if err != nil { 3555 if time.Since(t0) < MaxWriteWaitBeforeConnReuse/2 { 3556 mu.Lock() 3557 got := logbuf.String() 3558 mu.Unlock() 3559 t.Fatalf("i=%d: Do = %v; log:\n%s", i, err, got) 3560 } 3561 t.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", MaxWriteWaitBeforeConnReuse) 3562 } 3563 res.Body.Close() 3564 if res.Request != req { 3565 t.Errorf("Response.Request != original request; want identical Request") 3566 } 3567 } 3568 3569 mu.Lock() 3570 got := logbuf.String() 3571 mu.Unlock() 3572 want := fmt.Sprintf(`Dial 3573 Write("%s") 3574 Handler 3575 intentional write failure 3576 Retried. 3577 Dial 3578 Write("%s") 3579 Handler 3580 Write("%s") 3581 Handler 3582 `, tc.reqString, tc.reqString, tc.reqString) 3583 if got != want { 3584 t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want) 3585 } 3586 }) 3587 } 3588 } 3589 3590 // Issue 6981 3591 func TestTransportClosesBodyOnError(t *testing.T) { 3592 setParallel(t) 3593 defer afterTest(t) 3594 readBody := make(chan error, 1) 3595 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3596 _, err := io.ReadAll(r.Body) 3597 readBody <- err 3598 })) 3599 defer ts.Close() 3600 c := ts.Client() 3601 fakeErr := errors.New("fake error") 3602 didClose := make(chan bool, 1) 3603 req, _ := NewRequest("POST", ts.URL, struct { 3604 io.Reader 3605 io.Closer 3606 }{ 3607 io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), iotest.ErrReader(fakeErr)), 3608 closerFunc(func() error { 3609 select { 3610 case didClose <- true: 3611 default: 3612 } 3613 return nil 3614 }), 3615 }) 3616 res, err := c.Do(req) 3617 if res != nil { 3618 defer res.Body.Close() 3619 } 3620 if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) { 3621 t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error()) 3622 } 3623 select { 3624 case err := <-readBody: 3625 if err == nil { 3626 t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'") 3627 } 3628 case <-time.After(5 * time.Second): 3629 t.Error("timeout waiting for server handler to complete") 3630 } 3631 select { 3632 case <-didClose: 3633 default: 3634 t.Errorf("didn't see Body.Close") 3635 } 3636 } 3637 3638 func TestTransportDialTLS(t *testing.T) { 3639 setParallel(t) 3640 defer afterTest(t) 3641 var mu sync.Mutex // guards following 3642 var gotReq, didDial bool 3643 3644 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3645 mu.Lock() 3646 gotReq = true 3647 mu.Unlock() 3648 })) 3649 defer ts.Close() 3650 c := ts.Client() 3651 c.Transport.(*Transport).DialTLS = func(netw, addr string) (net.Conn, error) { 3652 mu.Lock() 3653 didDial = true 3654 mu.Unlock() 3655 c, err := tls.Dial(netw, addr, c.Transport.(*Transport).TLSClientConfig) 3656 if err != nil { 3657 return nil, err 3658 } 3659 return c, c.Handshake() 3660 } 3661 3662 res, err := c.Get(ts.URL) 3663 if err != nil { 3664 t.Fatal(err) 3665 } 3666 res.Body.Close() 3667 mu.Lock() 3668 if !gotReq { 3669 t.Error("didn't get request") 3670 } 3671 if !didDial { 3672 t.Error("didn't use dial hook") 3673 } 3674 } 3675 3676 func TestTransportDialContext(t *testing.T) { 3677 setParallel(t) 3678 defer afterTest(t) 3679 var mu sync.Mutex // guards following 3680 var gotReq bool 3681 var receivedContext context.Context 3682 3683 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3684 mu.Lock() 3685 gotReq = true 3686 mu.Unlock() 3687 })) 3688 defer ts.Close() 3689 c := ts.Client() 3690 c.Transport.(*Transport).DialContext = func(ctx context.Context, netw, addr string) (net.Conn, error) { 3691 mu.Lock() 3692 receivedContext = ctx 3693 mu.Unlock() 3694 return net.Dial(netw, addr) 3695 } 3696 3697 req, err := NewRequest("GET", ts.URL, nil) 3698 if err != nil { 3699 t.Fatal(err) 3700 } 3701 ctx := context.WithValue(context.Background(), "some-Key", "some-value") 3702 res, err := c.Do(req.WithContext(ctx)) 3703 if err != nil { 3704 t.Fatal(err) 3705 } 3706 res.Body.Close() 3707 mu.Lock() 3708 if !gotReq { 3709 t.Error("didn't get request") 3710 } 3711 if receivedContext != ctx { 3712 t.Error("didn't receive correct context") 3713 } 3714 } 3715 3716 func TestTransportDialTLSContext(t *testing.T) { 3717 setParallel(t) 3718 defer afterTest(t) 3719 var mu sync.Mutex // guards following 3720 var gotReq bool 3721 var receivedContext context.Context 3722 3723 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3724 mu.Lock() 3725 gotReq = true 3726 mu.Unlock() 3727 })) 3728 defer ts.Close() 3729 c := ts.Client() 3730 c.Transport.(*Transport).DialTLSContext = func(ctx context.Context, netw, addr string) (net.Conn, error) { 3731 mu.Lock() 3732 receivedContext = ctx 3733 mu.Unlock() 3734 c, err := tls.Dial(netw, addr, c.Transport.(*Transport).TLSClientConfig) 3735 if err != nil { 3736 return nil, err 3737 } 3738 return c, c.Handshake() 3739 } 3740 3741 req, err := NewRequest("GET", ts.URL, nil) 3742 if err != nil { 3743 t.Fatal(err) 3744 } 3745 ctx := context.WithValue(context.Background(), "some-Key", "some-value") 3746 res, err := c.Do(req.WithContext(ctx)) 3747 if err != nil { 3748 t.Fatal(err) 3749 } 3750 res.Body.Close() 3751 mu.Lock() 3752 if !gotReq { 3753 t.Error("didn't get request") 3754 } 3755 if receivedContext != ctx { 3756 t.Error("didn't receive correct context") 3757 } 3758 } 3759 3760 // Test for issue 8755 3761 // Ensure that if a proxy returns an error, it is exposed by RoundTrip 3762 func TestRoundTripReturnsProxyError(t *testing.T) { 3763 badProxy := func(*Request) (*url.URL, error) { 3764 return nil, errors.New("errorMessage") 3765 } 3766 3767 tr := &Transport{Proxy: badProxy} 3768 3769 req, _ := NewRequest("GET", "http://example.com", nil) 3770 3771 _, err := tr.RoundTrip(req) 3772 3773 if err == nil { 3774 t.Error("Expected proxy error to be returned by RoundTrip") 3775 } 3776 } 3777 3778 // tests that putting an idle conn after a call to CloseIdleConns does return it 3779 func TestTransportCloseIdleConnsThenReturn(t *testing.T) { 3780 tr := &Transport{} 3781 wantIdle := func(when string, n int) bool { 3782 got := tr.IdleConnCountForTesting("http", "example.com") // Key used by PutIdleTestConn 3783 if got == n { 3784 return true 3785 } 3786 t.Errorf("%s: idle conns = %d; want %d", when, got, n) 3787 return false 3788 } 3789 wantIdle("start", 0) 3790 if !tr.PutIdleTestConn("http", "example.com") { 3791 t.Fatal("put failed") 3792 } 3793 if !tr.PutIdleTestConn("http", "example.com") { 3794 t.Fatal("second put failed") 3795 } 3796 wantIdle("after put", 2) 3797 tr.CloseIdleConnections() 3798 if !tr.IsIdleForTesting() { 3799 t.Error("should be idle after CloseIdleConnections") 3800 } 3801 wantIdle("after close idle", 0) 3802 if tr.PutIdleTestConn("http", "example.com") { 3803 t.Fatal("put didn't fail") 3804 } 3805 wantIdle("after second put", 0) 3806 3807 tr.QueueForIdleConnForTesting() // should toggle the transport out of idle mode 3808 if tr.IsIdleForTesting() { 3809 t.Error("shouldn't be idle after QueueForIdleConnForTesting") 3810 } 3811 if !tr.PutIdleTestConn("http", "example.com") { 3812 t.Fatal("after re-activation") 3813 } 3814 wantIdle("after final put", 1) 3815 } 3816 3817 // Test for issue 34282 3818 // Ensure that getConn doesn't call the GotConn trace hook on a HTTP/2 idle conn 3819 func TestTransportTraceGotConnH2IdleConns(t *testing.T) { 3820 tr := &Transport{} 3821 wantIdle := func(when string, n int) bool { 3822 got := tr.IdleConnCountForTesting("https", "example.com:443") // Key used by PutIdleTestConnH2 3823 if got == n { 3824 return true 3825 } 3826 t.Errorf("%s: idle conns = %d; want %d", when, got, n) 3827 return false 3828 } 3829 wantIdle("start", 0) 3830 alt := funcRoundTripper(func() {}) 3831 if !tr.PutIdleTestConnH2("https", "example.com:443", alt) { 3832 t.Fatal("put failed") 3833 } 3834 wantIdle("after put", 1) 3835 ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ 3836 GotConn: func(httptrace.GotConnInfo) { 3837 // tr.getConn should leave it for the HTTP/2 alt to call GotConn. 3838 t.Error("GotConn called") 3839 }, 3840 }) 3841 req, _ := NewRequestWithContext(ctx, MethodGet, "https://example.com", nil) 3842 _, err := tr.RoundTrip(req) 3843 if err != errFakeRoundTrip { 3844 t.Errorf("got error: %v; want %q", err, errFakeRoundTrip) 3845 } 3846 wantIdle("after round trip", 1) 3847 } 3848 3849 func TestTransportRemovesH2ConnsAfterIdle(t *testing.T) { 3850 if testing.Short() { 3851 t.Skip("skipping in short mode") 3852 } 3853 3854 trFunc := func(tr *Transport) { 3855 tr.MaxConnsPerHost = 1 3856 tr.MaxIdleConnsPerHost = 1 3857 tr.IdleConnTimeout = 10 * time.Millisecond 3858 } 3859 cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {}), trFunc) 3860 defer cst.close() 3861 3862 if _, err := cst.c.Get(cst.ts.URL); err != nil { 3863 t.Fatalf("got error: %s", err) 3864 } 3865 3866 time.Sleep(100 * time.Millisecond) 3867 got := make(chan error) 3868 go func() { 3869 if _, err := cst.c.Get(cst.ts.URL); err != nil { 3870 got <- err 3871 } 3872 close(got) 3873 }() 3874 3875 timeout := time.NewTimer(5 * time.Second) 3876 defer timeout.Stop() 3877 select { 3878 case err := <-got: 3879 if err != nil { 3880 t.Fatalf("got error: %s", err) 3881 } 3882 case <-timeout.C: 3883 t.Fatal("request never completed") 3884 } 3885 } 3886 3887 // This tests that a client requesting a content range won't also 3888 // implicitly ask for gzip support. If they want that, they need to do it 3889 // on their own. 3890 // golang.org/issue/8923 3891 func TestTransportRangeAndGzip(t *testing.T) { 3892 defer afterTest(t) 3893 reqc := make(chan *Request, 1) 3894 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3895 reqc <- r 3896 })) 3897 defer ts.Close() 3898 c := ts.Client() 3899 3900 req, _ := NewRequest("GET", ts.URL, nil) 3901 req.Header.Set("Range", "bytes=7-11") 3902 res, err := c.Do(req) 3903 if err != nil { 3904 t.Fatal(err) 3905 } 3906 3907 select { 3908 case r := <-reqc: 3909 if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { 3910 t.Error("Transport advertised gzip support in the Accept header") 3911 } 3912 if r.Header.Get("Range") == "" { 3913 t.Error("no Range in request") 3914 } 3915 case <-time.After(10 * time.Second): 3916 t.Fatal("timeout") 3917 } 3918 res.Body.Close() 3919 } 3920 3921 // Test for issue 10474 3922 func TestTransportResponseCancelRace(t *testing.T) { 3923 defer afterTest(t) 3924 3925 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3926 // important that this response has a body. 3927 var b [1024]byte 3928 w.Write(b[:]) 3929 })) 3930 defer ts.Close() 3931 tr := ts.Client().Transport.(*Transport) 3932 3933 req, err := NewRequest("GET", ts.URL, nil) 3934 if err != nil { 3935 t.Fatal(err) 3936 } 3937 res, err := tr.RoundTrip(req) 3938 if err != nil { 3939 t.Fatal(err) 3940 } 3941 // If we do an early close, Transport just throws the connection away and 3942 // doesn't reuse it. In order to trigger the bug, it has to reuse the connection 3943 // so read the body 3944 if _, err := io.Copy(io.Discard, res.Body); err != nil { 3945 t.Fatal(err) 3946 } 3947 3948 req2, err := NewRequest("GET", ts.URL, nil) 3949 if err != nil { 3950 t.Fatal(err) 3951 } 3952 tr.CancelRequest(req) 3953 res, err = tr.RoundTrip(req2) 3954 if err != nil { 3955 t.Fatal(err) 3956 } 3957 res.Body.Close() 3958 } 3959 3960 // Test for issue 19248: Content-Encoding's value is case insensitive. 3961 func TestTransportContentEncodingCaseInsensitive(t *testing.T) { 3962 setParallel(t) 3963 defer afterTest(t) 3964 for _, ce := range []string{"gzip", "GZIP"} { 3965 ce := ce 3966 t.Run(ce, func(t *testing.T) { 3967 const encodedString = "Hello Gopher" 3968 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 3969 w.Header().Set("Content-Encoding", ce) 3970 gz := gzip.NewWriter(w) 3971 gz.Write([]byte(encodedString)) 3972 gz.Close() 3973 })) 3974 defer ts.Close() 3975 3976 res, err := ts.Client().Get(ts.URL) 3977 if err != nil { 3978 t.Fatal(err) 3979 } 3980 3981 body, err := io.ReadAll(res.Body) 3982 res.Body.Close() 3983 if err != nil { 3984 t.Fatal(err) 3985 } 3986 3987 if string(body) != encodedString { 3988 t.Fatalf("Expected body %q, got: %q\n", encodedString, string(body)) 3989 } 3990 }) 3991 } 3992 } 3993 3994 func TestTransportDialCancelRace(t *testing.T) { 3995 defer afterTest(t) 3996 3997 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) 3998 defer ts.Close() 3999 tr := ts.Client().Transport.(*Transport) 4000 4001 req, err := NewRequest("GET", ts.URL, nil) 4002 if err != nil { 4003 t.Fatal(err) 4004 } 4005 SetEnterRoundTripHook(func() { 4006 tr.CancelRequest(req) 4007 }) 4008 defer SetEnterRoundTripHook(nil) 4009 res, err := tr.RoundTrip(req) 4010 if err != ExportErrRequestCanceled { 4011 t.Errorf("expected canceled request error; got %v", err) 4012 if err == nil { 4013 res.Body.Close() 4014 } 4015 } 4016 } 4017 4018 // logWritesConn is a net.Conn that logs each Write call to writes 4019 // and then proxies to w. 4020 // It proxies Read calls to a reader it receives from rch. 4021 type logWritesConn struct { 4022 net.Conn // nil. crash on use. 4023 4024 w io.Writer 4025 4026 rch <-chan io.Reader 4027 r io.Reader // nil until received by rch 4028 4029 mu sync.Mutex 4030 writes []string 4031 } 4032 4033 func (c *logWritesConn) Write(p []byte) (n int, err error) { 4034 c.mu.Lock() 4035 defer c.mu.Unlock() 4036 c.writes = append(c.writes, string(p)) 4037 return c.w.Write(p) 4038 } 4039 4040 func (c *logWritesConn) Read(p []byte) (n int, err error) { 4041 if c.r == nil { 4042 c.r = <-c.rch 4043 } 4044 return c.r.Read(p) 4045 } 4046 4047 func (c *logWritesConn) Close() error { return nil } 4048 4049 // Issue 6574 4050 func TestTransportFlushesBodyChunks(t *testing.T) { 4051 defer afterTest(t) 4052 resBody := make(chan io.Reader, 1) 4053 connr, connw := io.Pipe() // connection pipe pair 4054 lw := &logWritesConn{ 4055 rch: resBody, 4056 w: connw, 4057 } 4058 tr := &Transport{ 4059 Dial: func(network, addr string) (net.Conn, error) { 4060 return lw, nil 4061 }, 4062 } 4063 bodyr, bodyw := io.Pipe() // body pipe pair 4064 go func() { 4065 defer bodyw.Close() 4066 for i := 0; i < 3; i++ { 4067 fmt.Fprintf(bodyw, "num%d\n", i) 4068 } 4069 }() 4070 resc := make(chan *Response) 4071 go func() { 4072 req, _ := NewRequest("POST", "http://localhost:8080", bodyr) 4073 req.Header.Set("User-Agent", "x") // known value for test 4074 res, err := tr.RoundTrip(req) 4075 if err != nil { 4076 t.Errorf("RoundTrip: %v", err) 4077 close(resc) 4078 return 4079 } 4080 resc <- res 4081 4082 }() 4083 // Fully consume the request before checking the Write log vs. want. 4084 req, err := ReadRequest(bufio.NewReader(connr)) 4085 if err != nil { 4086 t.Fatal(err) 4087 } 4088 io.Copy(io.Discard, req.Body) 4089 4090 // Unblock the transport's roundTrip goroutine. 4091 resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n") 4092 res, ok := <-resc 4093 if !ok { 4094 return 4095 } 4096 defer res.Body.Close() 4097 4098 want := []string{ 4099 "POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n", 4100 "5\r\nnum0\n\r\n", 4101 "5\r\nnum1\n\r\n", 4102 "5\r\nnum2\n\r\n", 4103 "0\r\n\r\n", 4104 } 4105 if !reflect.DeepEqual(lw.writes, want) { 4106 t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want) 4107 } 4108 } 4109 4110 // Issue 22088: flush Transport request headers if we're not sure the body won't block on read. 4111 func TestTransportFlushesRequestHeader(t *testing.T) { 4112 defer afterTest(t) 4113 gotReq := make(chan struct{}) 4114 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 4115 close(gotReq) 4116 })) 4117 defer cst.close() 4118 4119 pr, pw := io.Pipe() 4120 req, err := NewRequest("POST", cst.ts.URL, pr) 4121 if err != nil { 4122 t.Fatal(err) 4123 } 4124 gotRes := make(chan struct{}) 4125 go func() { 4126 defer close(gotRes) 4127 res, err := cst.tr.RoundTrip(req) 4128 if err != nil { 4129 t.Error(err) 4130 return 4131 } 4132 res.Body.Close() 4133 }() 4134 4135 select { 4136 case <-gotReq: 4137 pw.Close() 4138 case <-time.After(5 * time.Second): 4139 t.Fatal("timeout waiting for handler to get request") 4140 } 4141 <-gotRes 4142 } 4143 4144 // Issue 11745. 4145 func TestTransportPrefersResponseOverWriteError(t *testing.T) { 4146 if testing.Short() { 4147 t.Skip("skipping in short mode") 4148 } 4149 defer afterTest(t) 4150 const contentLengthLimit = 1024 * 1024 // 1MB 4151 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 4152 if r.ContentLength >= contentLengthLimit { 4153 w.WriteHeader(StatusBadRequest) 4154 r.Body.Close() 4155 return 4156 } 4157 w.WriteHeader(StatusOK) 4158 })) 4159 defer ts.Close() 4160 c := ts.Client() 4161 4162 fail := 0 4163 count := 100 4164 bigBody := strings.Repeat("a", contentLengthLimit*2) 4165 for i := 0; i < count; i++ { 4166 req, err := NewRequest("PUT", ts.URL, strings.NewReader(bigBody)) 4167 if err != nil { 4168 t.Fatal(err) 4169 } 4170 resp, err := c.Do(req) 4171 if err != nil { 4172 fail++ 4173 t.Logf("%d = %#v", i, err) 4174 if ue, ok := err.(*url.Error); ok { 4175 t.Logf("urlErr = %#v", ue.Err) 4176 if ne, ok := ue.Err.(*net.OpError); ok { 4177 t.Logf("netOpError = %#v", ne.Err) 4178 } 4179 } 4180 } else { 4181 resp.Body.Close() 4182 if resp.StatusCode != 400 { 4183 t.Errorf("Expected status code 400, got %v", resp.Status) 4184 } 4185 } 4186 } 4187 if fail > 0 { 4188 t.Errorf("Failed %v out of %v\n", fail, count) 4189 } 4190 } 4191 4192 func TestTransportAutomaticHTTP2(t *testing.T) { 4193 testTransportAutoHTTP(t, &Transport{}, true) 4194 } 4195 4196 func TestTransportAutomaticHTTP2_DialerAndTLSConfigSupportsHTTP2AndTLSConfig(t *testing.T) { 4197 testTransportAutoHTTP(t, &Transport{ 4198 ForceAttemptHTTP2: true, 4199 TLSClientConfig: new(tls.Config), 4200 }, true) 4201 } 4202 4203 // golang.org/issue/14391: also check DefaultTransport 4204 func TestTransportAutomaticHTTP2_DefaultTransport(t *testing.T) { 4205 testTransportAutoHTTP(t, DefaultTransport.(*Transport), true) 4206 } 4207 4208 func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) { 4209 testTransportAutoHTTP(t, &Transport{ 4210 TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper), 4211 }, false) 4212 } 4213 4214 func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) { 4215 testTransportAutoHTTP(t, &Transport{ 4216 TLSClientConfig: new(tls.Config), 4217 }, false) 4218 } 4219 4220 func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) { 4221 testTransportAutoHTTP(t, &Transport{ 4222 ExpectContinueTimeout: 1 * time.Second, 4223 }, true) 4224 } 4225 4226 func TestTransportAutomaticHTTP2_Dial(t *testing.T) { 4227 var d net.Dialer 4228 testTransportAutoHTTP(t, &Transport{ 4229 Dial: d.Dial, 4230 }, false) 4231 } 4232 4233 func TestTransportAutomaticHTTP2_DialContext(t *testing.T) { 4234 var d net.Dialer 4235 testTransportAutoHTTP(t, &Transport{ 4236 DialContext: d.DialContext, 4237 }, false) 4238 } 4239 4240 func TestTransportAutomaticHTTP2_DialTLS(t *testing.T) { 4241 testTransportAutoHTTP(t, &Transport{ 4242 DialTLS: func(network, addr string) (net.Conn, error) { 4243 panic("unused") 4244 }, 4245 }, false) 4246 } 4247 4248 func testTransportAutoHTTP(t *testing.T, tr *Transport, wantH2 bool) { 4249 CondSkipHTTP2(t) 4250 _, err := tr.RoundTrip(new(Request)) 4251 if err == nil { 4252 t.Error("expected error from RoundTrip") 4253 } 4254 if reg := tr.TLSNextProto["h2"] != nil; reg != wantH2 { 4255 t.Errorf("HTTP/2 registered = %v; want %v", reg, wantH2) 4256 } 4257 } 4258 4259 // Issue 13633: there was a race where we returned bodyless responses 4260 // to callers before recycling the persistent connection, which meant 4261 // a client doing two subsequent requests could end up on different 4262 // connections. It's somewhat harmless but enough tests assume it's 4263 // not true in order to test other things that it's worth fixing. 4264 // Plus it's nice to be consistent and not have timing-dependent 4265 // behavior. 4266 func TestTransportReuseConnEmptyResponseBody(t *testing.T) { 4267 defer afterTest(t) 4268 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 4269 w.Header().Set("X-Addr", r.RemoteAddr) 4270 // Empty response body. 4271 })) 4272 defer cst.close() 4273 n := 100 4274 if testing.Short() { 4275 n = 10 4276 } 4277 var firstAddr string 4278 for i := 0; i < n; i++ { 4279 res, err := cst.c.Get(cst.ts.URL) 4280 if err != nil { 4281 log.Fatal(err) 4282 } 4283 addr := res.Header.Get("X-Addr") 4284 if i == 0 { 4285 firstAddr = addr 4286 } else if addr != firstAddr { 4287 t.Fatalf("On request %d, addr %q != original addr %q", i+1, addr, firstAddr) 4288 } 4289 res.Body.Close() 4290 } 4291 } 4292 4293 // Issue 13839 4294 func TestNoCrashReturningTransportAltConn(t *testing.T) { 4295 cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey) 4296 if err != nil { 4297 t.Fatal(err) 4298 } 4299 ln := newLocalListener(t) 4300 defer ln.Close() 4301 4302 var wg sync.WaitGroup 4303 SetPendingDialHooks(func() { wg.Add(1) }, wg.Done) 4304 defer SetPendingDialHooks(nil, nil) 4305 4306 testDone := make(chan struct{}) 4307 defer close(testDone) 4308 go func() { 4309 tln := tls.NewListener(ln, &tls.Config{ 4310 NextProtos: []string{"foo"}, 4311 Certificates: []tls.Certificate{cert}, 4312 }) 4313 sc, err := tln.Accept() 4314 if err != nil { 4315 t.Error(err) 4316 return 4317 } 4318 if err := sc.(*tls.Conn).Handshake(); err != nil { 4319 t.Error(err) 4320 return 4321 } 4322 <-testDone 4323 sc.Close() 4324 }() 4325 4326 addr := ln.Addr().String() 4327 4328 req, _ := NewRequest("GET", "https://fake.tld/", nil) 4329 cancel := make(chan struct{}) 4330 req.Cancel = cancel 4331 4332 doReturned := make(chan bool, 1) 4333 madeRoundTripper := make(chan bool, 1) 4334 4335 tr := &Transport{ 4336 DisableKeepAlives: true, 4337 TLSNextProto: map[string]func(string, *tls.Conn) RoundTripper{ 4338 "foo": func(authority string, c *tls.Conn) RoundTripper { 4339 madeRoundTripper <- true 4340 return funcRoundTripper(func() { 4341 t.Error("foo RoundTripper should not be called") 4342 }) 4343 }, 4344 }, 4345 Dial: func(_, _ string) (net.Conn, error) { 4346 panic("shouldn't be called") 4347 }, 4348 DialTLS: func(_, _ string) (net.Conn, error) { 4349 tc, err := tls.Dial("tcp", addr, &tls.Config{ 4350 InsecureSkipVerify: true, 4351 NextProtos: []string{"foo"}, 4352 }) 4353 if err != nil { 4354 return nil, err 4355 } 4356 if err := tc.Handshake(); err != nil { 4357 return nil, err 4358 } 4359 close(cancel) 4360 <-doReturned 4361 return tc, nil 4362 }, 4363 } 4364 c := &Client{Transport: tr} 4365 4366 _, err = c.Do(req) 4367 if ue, ok := err.(*url.Error); !ok || ue.Err != ExportErrRequestCanceledConn { 4368 t.Fatalf("Do error = %v; want url.Error with errRequestCanceledConn", err) 4369 } 4370 4371 doReturned <- true 4372 <-madeRoundTripper 4373 wg.Wait() 4374 } 4375 4376 func TestTransportReuseConnection_Gzip_Chunked(t *testing.T) { 4377 testTransportReuseConnection_Gzip(t, true) 4378 } 4379 4380 func TestTransportReuseConnection_Gzip_ContentLength(t *testing.T) { 4381 testTransportReuseConnection_Gzip(t, false) 4382 } 4383 4384 // Make sure we re-use underlying TCP connection for gzipped responses too. 4385 func testTransportReuseConnection_Gzip(t *testing.T, chunked bool) { 4386 setParallel(t) 4387 defer afterTest(t) 4388 addr := make(chan string, 2) 4389 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 4390 addr <- r.RemoteAddr 4391 w.Header().Set("Content-Encoding", "gzip") 4392 if chunked { 4393 w.(Flusher).Flush() 4394 } 4395 w.Write(rgz) // arbitrary gzip response 4396 })) 4397 defer ts.Close() 4398 c := ts.Client() 4399 4400 for i := 0; i < 2; i++ { 4401 res, err := c.Get(ts.URL) 4402 if err != nil { 4403 t.Fatal(err) 4404 } 4405 buf := make([]byte, len(rgz)) 4406 if n, err := io.ReadFull(res.Body, buf); err != nil { 4407 t.Errorf("%d. ReadFull = %v, %v", i, n, err) 4408 } 4409 // Note: no res.Body.Close call. It should work without it, 4410 // since the flate.Reader's internal buffering will hit EOF 4411 // and that should be sufficient. 4412 } 4413 a1, a2 := <-addr, <-addr 4414 if a1 != a2 { 4415 t.Fatalf("didn't reuse connection") 4416 } 4417 } 4418 4419 func TestTransportResponseHeaderLength(t *testing.T) { 4420 setParallel(t) 4421 defer afterTest(t) 4422 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 4423 if r.URL.Path == "/long" { 4424 w.Header().Set("Long", strings.Repeat("a", 1<<20)) 4425 } 4426 })) 4427 defer ts.Close() 4428 c := ts.Client() 4429 c.Transport.(*Transport).MaxResponseHeaderBytes = 512 << 10 4430 4431 if res, err := c.Get(ts.URL); err != nil { 4432 t.Fatal(err) 4433 } else { 4434 res.Body.Close() 4435 } 4436 4437 res, err := c.Get(ts.URL + "/long") 4438 if err == nil { 4439 defer res.Body.Close() 4440 var n int64 4441 for k, vv := range res.Header { 4442 for _, v := range vv { 4443 n += int64(len(k)) + int64(len(v)) 4444 } 4445 } 4446 t.Fatalf("Unexpected success. Got %v and %d bytes of response headers", res.Status, n) 4447 } 4448 if want := "server response headers exceeded 524288 bytes"; !strings.Contains(err.Error(), want) { 4449 t.Errorf("got error: %v; want %q", err, want) 4450 } 4451 } 4452 4453 func TestTransportEventTrace(t *testing.T) { testTransportEventTrace(t, h1Mode, false) } 4454 func TestTransportEventTrace_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, false) } 4455 4456 // test a non-nil httptrace.ClientTrace but with all hooks set to zero. 4457 func TestTransportEventTrace_NoHooks(t *testing.T) { testTransportEventTrace(t, h1Mode, true) } 4458 func TestTransportEventTrace_NoHooks_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, true) } 4459 4460 func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { 4461 defer afterTest(t) 4462 const resBody = "some body" 4463 gotWroteReqEvent := make(chan struct{}, 500) 4464 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 4465 if r.Method == "GET" { 4466 // Do nothing for the second request. 4467 return 4468 } 4469 if _, err := io.ReadAll(r.Body); err != nil { 4470 t.Error(err) 4471 } 4472 if !noHooks { 4473 select { 4474 case <-gotWroteReqEvent: 4475 case <-time.After(5 * time.Second): 4476 t.Error("timeout waiting for WroteRequest event") 4477 } 4478 } 4479 io.WriteString(w, resBody) 4480 })) 4481 defer cst.close() 4482 4483 cst.tr.ExpectContinueTimeout = 1 * time.Second 4484 4485 var mu sync.Mutex // guards buf 4486 var buf bytes.Buffer 4487 logf := func(format string, args ...interface{}) { 4488 mu.Lock() 4489 defer mu.Unlock() 4490 fmt.Fprintf(&buf, format, args...) 4491 buf.WriteByte('\n') 4492 } 4493 4494 addrStr := cst.ts.Listener.Addr().String() 4495 ip, port, err := net.SplitHostPort(addrStr) 4496 if err != nil { 4497 t.Fatal(err) 4498 } 4499 4500 // Install a fake DNS server. 4501 ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, network, host string) ([]net.IPAddr, error) { 4502 if host != "dns-is-faked.golang" { 4503 t.Errorf("unexpected DNS host lookup for %q/%q", network, host) 4504 return nil, nil 4505 } 4506 return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil 4507 }) 4508 4509 body := "some body" 4510 req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader(body)) 4511 req.Header["X-Foo-Multiple-Vals"] = []string{"bar", "baz"} 4512 trace := &httptrace.ClientTrace{ 4513 GetConn: func(hostPort string) { logf("Getting conn for %v ...", hostPort) }, 4514 GotConn: func(ci httptrace.GotConnInfo) { logf("got conn: %+v", ci) }, 4515 GotFirstResponseByte: func() { logf("first response byte") }, 4516 PutIdleConn: func(err error) { logf("PutIdleConn = %v", err) }, 4517 DNSStart: func(e httptrace.DNSStartInfo) { logf("DNS start: %+v", e) }, 4518 DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNS done: %+v", e) }, 4519 ConnectStart: func(network, addr string) { logf("ConnectStart: Connecting to %s %s ...", network, addr) }, 4520 ConnectDone: func(network, addr string, err error) { 4521 if err != nil { 4522 t.Errorf("ConnectDone: %v", err) 4523 } 4524 logf("ConnectDone: connected to %s %s = %v", network, addr, err) 4525 }, 4526 WroteHeaderField: func(key string, value []string) { 4527 logf("WroteHeaderField: %s: %v", key, value) 4528 }, 4529 WroteHeaders: func() { 4530 logf("WroteHeaders") 4531 }, 4532 Wait100Continue: func() { logf("Wait100Continue") }, 4533 Got100Continue: func() { logf("Got100Continue") }, 4534 WroteRequest: func(e httptrace.WroteRequestInfo) { 4535 logf("WroteRequest: %+v", e) 4536 gotWroteReqEvent <- struct{}{} 4537 }, 4538 } 4539 if h2 { 4540 trace.TLSHandshakeStart = func() { logf("tls handshake start") } 4541 trace.TLSHandshakeDone = func(s tls.ConnectionState, err error) { 4542 logf("tls handshake done. ConnectionState = %v \n err = %v", s, err) 4543 } 4544 } 4545 if noHooks { 4546 // zero out all func pointers, trying to get some path to crash 4547 *trace = httptrace.ClientTrace{} 4548 } 4549 req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) 4550 4551 req.Header.Set("Expect", "100-continue") 4552 res, err := cst.c.Do(req) 4553 if err != nil { 4554 t.Fatal(err) 4555 } 4556 logf("got roundtrip.response") 4557 slurp, err := io.ReadAll(res.Body) 4558 if err != nil { 4559 t.Fatal(err) 4560 } 4561 logf("consumed body") 4562 if string(slurp) != resBody || res.StatusCode != 200 { 4563 t.Fatalf("Got %q, %v; want %q, 200 OK", slurp, res.Status, resBody) 4564 } 4565 res.Body.Close() 4566 4567 if noHooks { 4568 // Done at this point. Just testing a full HTTP 4569 // requests can happen with a trace pointing to a zero 4570 // ClientTrace, full of nil func pointers. 4571 return 4572 } 4573 4574 mu.Lock() 4575 got := buf.String() 4576 mu.Unlock() 4577 4578 wantOnce := func(sub string) { 4579 if strings.Count(got, sub) != 1 { 4580 t.Errorf("expected substring %q exactly once in output.", sub) 4581 } 4582 } 4583 wantOnceOrMore := func(sub string) { 4584 if strings.Count(got, sub) == 0 { 4585 t.Errorf("expected substring %q at least once in output.", sub) 4586 } 4587 } 4588 wantOnce("Getting conn for dns-is-faked.golang:" + port) 4589 wantOnce("DNS start: {Host:dns-is-faked.golang}") 4590 wantOnce("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err:<nil> Coalesced:false}") 4591 wantOnce("got conn: {") 4592 wantOnceOrMore("Connecting to tcp " + addrStr) 4593 wantOnceOrMore("connected to tcp " + addrStr + " = <nil>") 4594 wantOnce("Reused:false WasIdle:false IdleTime:0s") 4595 wantOnce("first response byte") 4596 if h2 { 4597 wantOnce("tls handshake start") 4598 wantOnce("tls handshake done") 4599 } else { 4600 wantOnce("PutIdleConn = <nil>") 4601 wantOnce("WroteHeaderField: User-Agent: [Go-http-client/1.1]") 4602 // TODO(meirf): issue 19761. Make these agnostic to h1/h2. (These are not h1 specific, but the 4603 // WroteHeaderField hook is not yet implemented in h2.) 4604 wantOnce(fmt.Sprintf("WroteHeaderField: Host: [dns-is-faked.golang:%s]", port)) 4605 wantOnce(fmt.Sprintf("WroteHeaderField: Content-Length: [%d]", len(body))) 4606 wantOnce("WroteHeaderField: X-Foo-Multiple-Vals: [bar baz]") 4607 wantOnce("WroteHeaderField: Accept-Encoding: [gzip]") 4608 } 4609 wantOnce("WroteHeaders") 4610 wantOnce("Wait100Continue") 4611 wantOnce("Got100Continue") 4612 wantOnce("WroteRequest: {Err:<nil>}") 4613 if strings.Contains(got, " to udp ") { 4614 t.Errorf("should not see UDP (DNS) connections") 4615 } 4616 if t.Failed() { 4617 t.Errorf("Output:\n%s", got) 4618 } 4619 4620 // And do a second request: 4621 req, _ = NewRequest("GET", cst.scheme()+"://dns-is-faked.golang:"+port, nil) 4622 req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) 4623 res, err = cst.c.Do(req) 4624 if err != nil { 4625 t.Fatal(err) 4626 } 4627 if res.StatusCode != 200 { 4628 t.Fatal(res.Status) 4629 } 4630 res.Body.Close() 4631 4632 mu.Lock() 4633 got = buf.String() 4634 mu.Unlock() 4635 4636 sub := "Getting conn for dns-is-faked.golang:" 4637 if gotn, want := strings.Count(got, sub), 2; gotn != want { 4638 t.Errorf("substring %q appeared %d times; want %d. Log:\n%s", sub, gotn, want, got) 4639 } 4640 4641 } 4642 4643 func TestTransportEventTraceTLSVerify(t *testing.T) { 4644 var mu sync.Mutex 4645 var buf bytes.Buffer 4646 logf := func(format string, args ...interface{}) { 4647 mu.Lock() 4648 defer mu.Unlock() 4649 fmt.Fprintf(&buf, format, args...) 4650 buf.WriteByte('\n') 4651 } 4652 4653 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 4654 t.Error("Unexpected request") 4655 })) 4656 defer ts.Close() 4657 ts.Config.ErrorLog = log.New(funcWriter(func(p []byte) (int, error) { 4658 logf("%s", p) 4659 return len(p), nil 4660 }), "", 0) 4661 4662 certpool := x509.NewCertPool() 4663 certpool.AddCert(ts.Certificate()) 4664 4665 c := &Client{Transport: &Transport{ 4666 TLSClientConfig: &tls.Config{ 4667 ServerName: "dns-is-faked.golang", 4668 RootCAs: certpool, 4669 }, 4670 }} 4671 4672 trace := &httptrace.ClientTrace{ 4673 TLSHandshakeStart: func() { logf("TLSHandshakeStart") }, 4674 TLSHandshakeDone: func(s tls.ConnectionState, err error) { 4675 logf("TLSHandshakeDone: ConnectionState = %v \n err = %v", s, err) 4676 }, 4677 } 4678 4679 req, _ := NewRequest("GET", ts.URL, nil) 4680 req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace)) 4681 _, err := c.Do(req) 4682 if err == nil { 4683 t.Error("Expected request to fail TLS verification") 4684 } 4685 4686 mu.Lock() 4687 got := buf.String() 4688 mu.Unlock() 4689 4690 wantOnce := func(sub string) { 4691 if strings.Count(got, sub) != 1 { 4692 t.Errorf("expected substring %q exactly once in output.", sub) 4693 } 4694 } 4695 4696 wantOnce("TLSHandshakeStart") 4697 wantOnce("TLSHandshakeDone") 4698 wantOnce("err = x509: certificate is valid for example.com") 4699 4700 if t.Failed() { 4701 t.Errorf("Output:\n%s", got) 4702 } 4703 } 4704 4705 var ( 4706 isDNSHijackedOnce sync.Once 4707 isDNSHijacked bool 4708 ) 4709 4710 func skipIfDNSHijacked(t *testing.T) { 4711 // Skip this test if the user is using a shady/ISP 4712 // DNS server hijacking queries. 4713 // See issues 16732, 16716. 4714 isDNSHijackedOnce.Do(func() { 4715 addrs, _ := net.LookupHost("dns-should-not-resolve.golang") 4716 isDNSHijacked = len(addrs) != 0 4717 }) 4718 if isDNSHijacked { 4719 t.Skip("skipping; test requires non-hijacking DNS server") 4720 } 4721 } 4722 4723 func TestTransportEventTraceRealDNS(t *testing.T) { 4724 skipIfDNSHijacked(t) 4725 defer afterTest(t) 4726 tr := &Transport{} 4727 defer tr.CloseIdleConnections() 4728 c := &Client{Transport: tr} 4729 4730 var mu sync.Mutex // guards buf 4731 var buf bytes.Buffer 4732 logf := func(format string, args ...interface{}) { 4733 mu.Lock() 4734 defer mu.Unlock() 4735 fmt.Fprintf(&buf, format, args...) 4736 buf.WriteByte('\n') 4737 } 4738 4739 req, _ := NewRequest("GET", "http://dns-should-not-resolve.golang:80", nil) 4740 trace := &httptrace.ClientTrace{ 4741 DNSStart: func(e httptrace.DNSStartInfo) { logf("DNSStart: %+v", e) }, 4742 DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNSDone: %+v", e) }, 4743 ConnectStart: func(network, addr string) { logf("ConnectStart: %s %s", network, addr) }, 4744 ConnectDone: func(network, addr string, err error) { logf("ConnectDone: %s %s %v", network, addr, err) }, 4745 } 4746 req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace)) 4747 4748 resp, err := c.Do(req) 4749 if err == nil { 4750 resp.Body.Close() 4751 t.Fatal("expected error during DNS lookup") 4752 } 4753 4754 mu.Lock() 4755 got := buf.String() 4756 mu.Unlock() 4757 4758 wantSub := func(sub string) { 4759 if !strings.Contains(got, sub) { 4760 t.Errorf("expected substring %q in output.", sub) 4761 } 4762 } 4763 wantSub("DNSStart: {Host:dns-should-not-resolve.golang}") 4764 wantSub("DNSDone: {Addrs:[] Err:") 4765 if strings.Contains(got, "ConnectStart") || strings.Contains(got, "ConnectDone") { 4766 t.Errorf("should not see Connect events") 4767 } 4768 if t.Failed() { 4769 t.Errorf("Output:\n%s", got) 4770 } 4771 } 4772 4773 // Issue 14353: port can only contain digits. 4774 func TestTransportRejectsAlphaPort(t *testing.T) { 4775 res, err := Get("http://dummy.tld:123foo/bar") 4776 if err == nil { 4777 res.Body.Close() 4778 t.Fatal("unexpected success") 4779 } 4780 ue, ok := err.(*url.Error) 4781 if !ok { 4782 t.Fatalf("got %#v; want *url.Error", err) 4783 } 4784 got := ue.Err.Error() 4785 want := `invalid port ":123foo" after host` 4786 if got != want { 4787 t.Errorf("got error %q; want %q", got, want) 4788 } 4789 } 4790 4791 // Test the httptrace.TLSHandshake{Start,Done} hooks with a https http1 4792 // connections. The http2 test is done in TestTransportEventTrace_h2 4793 func TestTLSHandshakeTrace(t *testing.T) { 4794 defer afterTest(t) 4795 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) 4796 defer ts.Close() 4797 4798 var mu sync.Mutex 4799 var start, done bool 4800 trace := &httptrace.ClientTrace{ 4801 TLSHandshakeStart: func() { 4802 mu.Lock() 4803 defer mu.Unlock() 4804 start = true 4805 }, 4806 TLSHandshakeDone: func(s tls.ConnectionState, err error) { 4807 mu.Lock() 4808 defer mu.Unlock() 4809 done = true 4810 if err != nil { 4811 t.Fatal("Expected error to be nil but was:", err) 4812 } 4813 }, 4814 } 4815 4816 c := ts.Client() 4817 req, err := NewRequest("GET", ts.URL, nil) 4818 if err != nil { 4819 t.Fatal("Unable to construct test request:", err) 4820 } 4821 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) 4822 4823 r, err := c.Do(req) 4824 if err != nil { 4825 t.Fatal("Unexpected error making request:", err) 4826 } 4827 r.Body.Close() 4828 mu.Lock() 4829 defer mu.Unlock() 4830 if !start { 4831 t.Fatal("Expected TLSHandshakeStart to be called, but wasn't") 4832 } 4833 if !done { 4834 t.Fatal("Expected TLSHandshakeDone to be called, but wasnt't") 4835 } 4836 } 4837 4838 func TestTransportMaxIdleConns(t *testing.T) { 4839 defer afterTest(t) 4840 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 4841 // No body for convenience. 4842 })) 4843 defer ts.Close() 4844 c := ts.Client() 4845 tr := c.Transport.(*Transport) 4846 tr.MaxIdleConns = 4 4847 4848 ip, port, err := net.SplitHostPort(ts.Listener.Addr().String()) 4849 if err != nil { 4850 t.Fatal(err) 4851 } 4852 ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, _, host string) ([]net.IPAddr, error) { 4853 return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil 4854 }) 4855 4856 hitHost := func(n int) { 4857 req, _ := NewRequest("GET", fmt.Sprintf("http://host-%d.dns-is-faked.golang:"+port, n), nil) 4858 req = req.WithContext(ctx) 4859 res, err := c.Do(req) 4860 if err != nil { 4861 t.Fatal(err) 4862 } 4863 res.Body.Close() 4864 } 4865 for i := 0; i < 4; i++ { 4866 hitHost(i) 4867 } 4868 want := []string{ 4869 "|http|host-0.dns-is-faked.golang:" + port, 4870 "|http|host-1.dns-is-faked.golang:" + port, 4871 "|http|host-2.dns-is-faked.golang:" + port, 4872 "|http|host-3.dns-is-faked.golang:" + port, 4873 } 4874 if got := tr.IdleConnKeysForTesting(); !reflect.DeepEqual(got, want) { 4875 t.Fatalf("idle conn keys mismatch.\n got: %q\nwant: %q\n", got, want) 4876 } 4877 4878 // Now hitting the 5th host should kick out the first host: 4879 hitHost(4) 4880 want = []string{ 4881 "|http|host-1.dns-is-faked.golang:" + port, 4882 "|http|host-2.dns-is-faked.golang:" + port, 4883 "|http|host-3.dns-is-faked.golang:" + port, 4884 "|http|host-4.dns-is-faked.golang:" + port, 4885 } 4886 if got := tr.IdleConnKeysForTesting(); !reflect.DeepEqual(got, want) { 4887 t.Fatalf("idle conn keys mismatch after 5th host.\n got: %q\nwant: %q\n", got, want) 4888 } 4889 } 4890 4891 func TestTransportIdleConnTimeout_h1(t *testing.T) { testTransportIdleConnTimeout(t, h1Mode) } 4892 func TestTransportIdleConnTimeout_h2(t *testing.T) { testTransportIdleConnTimeout(t, h2Mode) } 4893 func testTransportIdleConnTimeout(t *testing.T, h2 bool) { 4894 if testing.Short() { 4895 t.Skip("skipping in short mode") 4896 } 4897 defer afterTest(t) 4898 4899 const timeout = 1 * time.Second 4900 4901 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 4902 // No body for convenience. 4903 })) 4904 defer cst.close() 4905 tr := cst.tr 4906 tr.IdleConnTimeout = timeout 4907 defer tr.CloseIdleConnections() 4908 c := &Client{Transport: tr} 4909 4910 idleConns := func() []string { 4911 if h2 { 4912 return tr.IdleConnStrsForTesting_h2() 4913 } else { 4914 return tr.IdleConnStrsForTesting() 4915 } 4916 } 4917 4918 var conn string 4919 doReq := func(n int) { 4920 req, _ := NewRequest("GET", cst.ts.URL, nil) 4921 req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ 4922 PutIdleConn: func(err error) { 4923 if err != nil { 4924 t.Errorf("failed to keep idle conn: %v", err) 4925 } 4926 }, 4927 })) 4928 res, err := c.Do(req) 4929 if err != nil { 4930 t.Fatal(err) 4931 } 4932 res.Body.Close() 4933 conns := idleConns() 4934 if len(conns) != 1 { 4935 t.Fatalf("req %v: unexpected number of idle conns: %q", n, conns) 4936 } 4937 if conn == "" { 4938 conn = conns[0] 4939 } 4940 if conn != conns[0] { 4941 t.Fatalf("req %v: cached connection changed; expected the same one throughout the test", n) 4942 } 4943 } 4944 for i := 0; i < 3; i++ { 4945 doReq(i) 4946 time.Sleep(timeout / 2) 4947 } 4948 time.Sleep(timeout * 3 / 2) 4949 if got := idleConns(); len(got) != 0 { 4950 t.Errorf("idle conns = %q; want none", got) 4951 } 4952 } 4953 4954 // Issue 16208: Go 1.7 crashed after Transport.IdleConnTimeout if an 4955 // HTTP/2 connection was established but its caller no longer 4956 // wanted it. (Assuming the connection cache was enabled, which it is 4957 // by default) 4958 // 4959 // This test reproduced the crash by setting the IdleConnTimeout low 4960 // (to make the test reasonable) and then making a request which is 4961 // canceled by the DialTLS hook, which then also waits to return the 4962 // real connection until after the RoundTrip saw the error. Then we 4963 // know the successful tls.Dial from DialTLS will need to go into the 4964 // idle pool. Then we give it a of time to explode. 4965 func TestIdleConnH2Crash(t *testing.T) { 4966 setParallel(t) 4967 cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 4968 // nothing 4969 })) 4970 defer cst.close() 4971 4972 ctx, cancel := context.WithCancel(context.Background()) 4973 defer cancel() 4974 4975 sawDoErr := make(chan bool, 1) 4976 testDone := make(chan struct{}) 4977 defer close(testDone) 4978 4979 cst.tr.IdleConnTimeout = 5 * time.Millisecond 4980 cst.tr.DialTLS = func(network, addr string) (net.Conn, error) { 4981 c, err := tls.Dial(network, addr, &tls.Config{ 4982 InsecureSkipVerify: true, 4983 NextProtos: []string{"h2"}, 4984 }) 4985 if err != nil { 4986 t.Error(err) 4987 return nil, err 4988 } 4989 if cs := c.ConnectionState(); cs.NegotiatedProtocol != "h2" { 4990 t.Errorf("protocol = %q; want %q", cs.NegotiatedProtocol, "h2") 4991 c.Close() 4992 return nil, errors.New("bogus") 4993 } 4994 4995 cancel() 4996 4997 failTimer := time.NewTimer(5 * time.Second) 4998 defer failTimer.Stop() 4999 select { 5000 case <-sawDoErr: 5001 case <-testDone: 5002 case <-failTimer.C: 5003 t.Error("timeout in DialTLS, waiting too long for cst.c.Do to fail") 5004 } 5005 return c, nil 5006 } 5007 5008 req, _ := NewRequest("GET", cst.ts.URL, nil) 5009 req = req.WithContext(ctx) 5010 res, err := cst.c.Do(req) 5011 if err == nil { 5012 res.Body.Close() 5013 t.Fatal("unexpected success") 5014 } 5015 sawDoErr <- true 5016 5017 // Wait for the explosion. 5018 time.Sleep(cst.tr.IdleConnTimeout * 10) 5019 } 5020 5021 type funcConn struct { 5022 net.Conn 5023 read func([]byte) (int, error) 5024 write func([]byte) (int, error) 5025 } 5026 5027 func (c funcConn) Read(p []byte) (int, error) { return c.read(p) } 5028 func (c funcConn) Write(p []byte) (int, error) { return c.write(p) } 5029 func (c funcConn) Close() error { return nil } 5030 5031 // Issue 16465: Transport.RoundTrip should return the raw net.Conn.Read error from Peek 5032 // back to the caller. 5033 func TestTransportReturnsPeekError(t *testing.T) { 5034 errValue := errors.New("specific error value") 5035 5036 wrote := make(chan struct{}) 5037 var wroteOnce sync.Once 5038 5039 tr := &Transport{ 5040 Dial: func(network, addr string) (net.Conn, error) { 5041 c := funcConn{ 5042 read: func([]byte) (int, error) { 5043 <-wrote 5044 return 0, errValue 5045 }, 5046 write: func(p []byte) (int, error) { 5047 wroteOnce.Do(func() { close(wrote) }) 5048 return len(p), nil 5049 }, 5050 } 5051 return c, nil 5052 }, 5053 } 5054 _, err := tr.RoundTrip(httptest.NewRequest("GET", "http://fake.tld/", nil)) 5055 if err != errValue { 5056 t.Errorf("error = %#v; want %v", err, errValue) 5057 } 5058 } 5059 5060 // Issue 13835: international domain names should work 5061 func TestTransportIDNA_h1(t *testing.T) { testTransportIDNA(t, h1Mode) } 5062 func TestTransportIDNA_h2(t *testing.T) { testTransportIDNA(t, h2Mode) } 5063 func testTransportIDNA(t *testing.T, h2 bool) { 5064 defer afterTest(t) 5065 5066 const uniDomain = "гофер.го" 5067 const punyDomain = "xn--c1ae0ajs.xn--c1aw" 5068 5069 var port string 5070 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 5071 want := punyDomain + ":" + port 5072 if r.Host != want { 5073 t.Errorf("Host header = %q; want %q", r.Host, want) 5074 } 5075 if h2 { 5076 if r.TLS == nil { 5077 t.Errorf("r.TLS == nil") 5078 } else if r.TLS.ServerName != punyDomain { 5079 t.Errorf("TLS.ServerName = %q; want %q", r.TLS.ServerName, punyDomain) 5080 } 5081 } 5082 w.Header().Set("Hit-Handler", "1") 5083 })) 5084 defer cst.close() 5085 5086 ip, port, err := net.SplitHostPort(cst.ts.Listener.Addr().String()) 5087 if err != nil { 5088 t.Fatal(err) 5089 } 5090 5091 // Install a fake DNS server. 5092 ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, network, host string) ([]net.IPAddr, error) { 5093 if host != punyDomain { 5094 t.Errorf("got DNS host lookup for %q/%q; want %q", network, host, punyDomain) 5095 return nil, nil 5096 } 5097 return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil 5098 }) 5099 5100 req, _ := NewRequest("GET", cst.scheme()+"://"+uniDomain+":"+port, nil) 5101 trace := &httptrace.ClientTrace{ 5102 GetConn: func(hostPort string) { 5103 want := net.JoinHostPort(punyDomain, port) 5104 if hostPort != want { 5105 t.Errorf("getting conn for %q; want %q", hostPort, want) 5106 } 5107 }, 5108 DNSStart: func(e httptrace.DNSStartInfo) { 5109 if e.Host != punyDomain { 5110 t.Errorf("DNSStart Host = %q; want %q", e.Host, punyDomain) 5111 } 5112 }, 5113 } 5114 req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) 5115 5116 res, err := cst.tr.RoundTrip(req) 5117 if err != nil { 5118 t.Fatal(err) 5119 } 5120 defer res.Body.Close() 5121 if res.Header.Get("Hit-Handler") != "1" { 5122 out, err := httputil.DumpResponse(res, true) 5123 if err != nil { 5124 t.Fatal(err) 5125 } 5126 t.Errorf("Response body wasn't from Handler. Got:\n%s\n", out) 5127 } 5128 } 5129 5130 // Issue 13290: send User-Agent in proxy CONNECT 5131 func TestTransportProxyConnectHeader(t *testing.T) { 5132 defer afterTest(t) 5133 reqc := make(chan *Request, 1) 5134 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 5135 if r.Method != "CONNECT" { 5136 t.Errorf("method = %q; want CONNECT", r.Method) 5137 } 5138 reqc <- r 5139 c, _, err := w.(Hijacker).Hijack() 5140 if err != nil { 5141 t.Errorf("Hijack: %v", err) 5142 return 5143 } 5144 c.Close() 5145 })) 5146 defer ts.Close() 5147 5148 c := ts.Client() 5149 c.Transport.(*Transport).Proxy = func(r *Request) (*url.URL, error) { 5150 return url.Parse(ts.URL) 5151 } 5152 c.Transport.(*Transport).ProxyConnectHeader = Header{ 5153 "User-Agent": {"foo"}, 5154 "Other": {"bar"}, 5155 } 5156 5157 res, err := c.Get("https://dummy.tld/") // https to force a CONNECT 5158 if err == nil { 5159 res.Body.Close() 5160 t.Errorf("unexpected success") 5161 } 5162 select { 5163 case <-time.After(3 * time.Second): 5164 t.Fatal("timeout") 5165 case r := <-reqc: 5166 if got, want := r.Header.Get("User-Agent"), "foo"; got != want { 5167 t.Errorf("CONNECT request User-Agent = %q; want %q", got, want) 5168 } 5169 if got, want := r.Header.Get("Other"), "bar"; got != want { 5170 t.Errorf("CONNECT request Other = %q; want %q", got, want) 5171 } 5172 } 5173 } 5174 5175 func TestTransportProxyGetConnectHeader(t *testing.T) { 5176 defer afterTest(t) 5177 reqc := make(chan *Request, 1) 5178 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 5179 if r.Method != "CONNECT" { 5180 t.Errorf("method = %q; want CONNECT", r.Method) 5181 } 5182 reqc <- r 5183 c, _, err := w.(Hijacker).Hijack() 5184 if err != nil { 5185 t.Errorf("Hijack: %v", err) 5186 return 5187 } 5188 c.Close() 5189 })) 5190 defer ts.Close() 5191 5192 c := ts.Client() 5193 c.Transport.(*Transport).Proxy = func(r *Request) (*url.URL, error) { 5194 return url.Parse(ts.URL) 5195 } 5196 // These should be ignored: 5197 c.Transport.(*Transport).ProxyConnectHeader = Header{ 5198 "User-Agent": {"foo"}, 5199 "Other": {"bar"}, 5200 } 5201 c.Transport.(*Transport).GetProxyConnectHeader = func(ctx context.Context, proxyURL *url.URL, target string) (Header, error) { 5202 return Header{ 5203 "User-Agent": {"foo2"}, 5204 "Other": {"bar2"}, 5205 }, nil 5206 } 5207 5208 res, err := c.Get("https://dummy.tld/") // https to force a CONNECT 5209 if err == nil { 5210 res.Body.Close() 5211 t.Errorf("unexpected success") 5212 } 5213 select { 5214 case <-time.After(3 * time.Second): 5215 t.Fatal("timeout") 5216 case r := <-reqc: 5217 if got, want := r.Header.Get("User-Agent"), "foo2"; got != want { 5218 t.Errorf("CONNECT request User-Agent = %q; want %q", got, want) 5219 } 5220 if got, want := r.Header.Get("Other"), "bar2"; got != want { 5221 t.Errorf("CONNECT request Other = %q; want %q", got, want) 5222 } 5223 } 5224 } 5225 5226 var errFakeRoundTrip = errors.New("fake roundtrip") 5227 5228 type funcRoundTripper func() 5229 5230 func (fn funcRoundTripper) RoundTrip(*Request) (*Response, error) { 5231 fn() 5232 return nil, errFakeRoundTrip 5233 } 5234 5235 func wantBody(res *Response, err error, want string) error { 5236 if err != nil { 5237 return err 5238 } 5239 slurp, err := io.ReadAll(res.Body) 5240 if err != nil { 5241 return fmt.Errorf("error reading body: %v", err) 5242 } 5243 if string(slurp) != want { 5244 return fmt.Errorf("body = %q; want %q", slurp, want) 5245 } 5246 if err := res.Body.Close(); err != nil { 5247 return fmt.Errorf("body Close = %v", err) 5248 } 5249 return nil 5250 } 5251 5252 func newLocalListener(t *testing.T) net.Listener { 5253 ln, err := net.Listen("tcp", "127.0.0.1:0") 5254 if err != nil { 5255 ln, err = net.Listen("tcp6", "[::1]:0") 5256 } 5257 if err != nil { 5258 t.Fatal(err) 5259 } 5260 return ln 5261 } 5262 5263 type countCloseReader struct { 5264 n *int 5265 io.Reader 5266 } 5267 5268 func (cr countCloseReader) Close() error { 5269 (*cr.n)++ 5270 return nil 5271 } 5272 5273 // rgz is a gzip quine that uncompresses to itself. 5274 var rgz = []byte{ 5275 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 5276 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 5277 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0, 5278 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 5279 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 5280 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60, 5281 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2, 5282 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00, 5283 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 5284 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16, 5285 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05, 5286 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff, 5287 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00, 5288 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 5289 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 5290 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 5291 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 5292 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 5293 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 5294 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 5295 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 5296 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff, 5297 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00, 5298 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 5299 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 5300 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 5301 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 5302 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06, 5303 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00, 5304 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 5305 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 5306 0x00, 0x00, 5307 } 5308 5309 // Ensure that a missing status doesn't make the server panic 5310 // See Issue https://golang.org/issues/21701 5311 func TestMissingStatusNoPanic(t *testing.T) { 5312 t.Parallel() 5313 5314 const want = "unknown status code" 5315 5316 ln := newLocalListener(t) 5317 addr := ln.Addr().String() 5318 shutdown := make(chan bool, 1) 5319 done := make(chan bool) 5320 fullAddrURL := fmt.Sprintf("http://%s", addr) 5321 raw := "HTTP/1.1 400\r\n" + 5322 "Date: Wed, 30 Aug 2017 19:09:27 GMT\r\n" + 5323 "Content-Type: text/html; charset=utf-8\r\n" + 5324 "Content-Length: 10\r\n" + 5325 "Last-Modified: Wed, 30 Aug 2017 19:02:02 GMT\r\n" + 5326 "Vary: Accept-Encoding\r\n\r\n" + 5327 "Aloha Olaa" 5328 5329 go func() { 5330 defer func() { 5331 ln.Close() 5332 close(done) 5333 }() 5334 5335 conn, _ := ln.Accept() 5336 if conn != nil { 5337 io.WriteString(conn, raw) 5338 io.ReadAll(conn) 5339 conn.Close() 5340 } 5341 }() 5342 5343 proxyURL, err := url.Parse(fullAddrURL) 5344 if err != nil { 5345 t.Fatalf("proxyURL: %v", err) 5346 } 5347 5348 tr := &Transport{Proxy: ProxyURL(proxyURL)} 5349 5350 req, _ := NewRequest("GET", "https://golang.org/", nil) 5351 res, err, panicked := doFetchCheckPanic(tr, req) 5352 if panicked { 5353 t.Error("panicked, expecting an error") 5354 } 5355 if res != nil && res.Body != nil { 5356 io.Copy(io.Discard, res.Body) 5357 res.Body.Close() 5358 } 5359 5360 if err == nil || !strings.Contains(err.Error(), want) { 5361 t.Errorf("got=%v want=%q", err, want) 5362 } 5363 5364 close(shutdown) 5365 <-done 5366 } 5367 5368 func doFetchCheckPanic(tr *Transport, req *Request) (res *Response, err error, panicked bool) { 5369 defer func() { 5370 if r := recover(); r != nil { 5371 panicked = true 5372 } 5373 }() 5374 res, err = tr.RoundTrip(req) 5375 return 5376 } 5377 5378 // Issue 22330: do not allow the response body to be read when the status code 5379 // forbids a response body. 5380 func TestNoBodyOnChunked304Response(t *testing.T) { 5381 defer afterTest(t) 5382 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 5383 conn, buf, _ := w.(Hijacker).Hijack() 5384 buf.Write([]byte("HTTP/1.1 304 NOT MODIFIED\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n")) 5385 buf.Flush() 5386 conn.Close() 5387 })) 5388 defer cst.close() 5389 5390 // Our test server above is sending back bogus data after the 5391 // response (the "0\r\n\r\n" part), which causes the Transport 5392 // code to log spam. Disable keep-alives so we never even try 5393 // to reuse the connection. 5394 cst.tr.DisableKeepAlives = true 5395 5396 res, err := cst.c.Get(cst.ts.URL) 5397 if err != nil { 5398 t.Fatal(err) 5399 } 5400 5401 if res.Body != NoBody { 5402 t.Errorf("Unexpected body on 304 response") 5403 } 5404 } 5405 5406 type funcWriter func([]byte) (int, error) 5407 5408 func (f funcWriter) Write(p []byte) (int, error) { return f(p) } 5409 5410 type doneContext struct { 5411 context.Context 5412 err error 5413 } 5414 5415 func (doneContext) Done() <-chan struct{} { 5416 c := make(chan struct{}) 5417 close(c) 5418 return c 5419 } 5420 5421 func (d doneContext) Err() error { return d.err } 5422 5423 // Issue 25852: Transport should check whether Context is done early. 5424 func TestTransportCheckContextDoneEarly(t *testing.T) { 5425 tr := &Transport{} 5426 req, _ := NewRequest("GET", "http://fake.example/", nil) 5427 wantErr := errors.New("some error") 5428 req = req.WithContext(doneContext{context.Background(), wantErr}) 5429 _, err := tr.RoundTrip(req) 5430 if err != wantErr { 5431 t.Errorf("error = %v; want %v", err, wantErr) 5432 } 5433 } 5434 5435 // Issue 23399: verify that if a client request times out, the Transport's 5436 // conn is closed so that it's not reused. 5437 // 5438 // This is the test variant that times out before the server replies with 5439 // any response headers. 5440 func TestClientTimeoutKillsConn_BeforeHeaders(t *testing.T) { 5441 setParallel(t) 5442 defer afterTest(t) 5443 inHandler := make(chan net.Conn, 1) 5444 handlerReadReturned := make(chan bool, 1) 5445 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 5446 conn, _, err := w.(Hijacker).Hijack() 5447 if err != nil { 5448 t.Error(err) 5449 return 5450 } 5451 inHandler <- conn 5452 n, err := conn.Read([]byte{0}) 5453 if n != 0 || err != io.EOF { 5454 t.Errorf("unexpected Read result: %v, %v", n, err) 5455 } 5456 handlerReadReturned <- true 5457 })) 5458 defer cst.close() 5459 5460 const timeout = 50 * time.Millisecond 5461 cst.c.Timeout = timeout 5462 5463 _, err := cst.c.Get(cst.ts.URL) 5464 if err == nil { 5465 t.Fatal("unexpected Get succeess") 5466 } 5467 5468 select { 5469 case c := <-inHandler: 5470 select { 5471 case <-handlerReadReturned: 5472 // Success. 5473 return 5474 case <-time.After(5 * time.Second): 5475 t.Error("Handler's conn.Read seems to be stuck in Read") 5476 c.Close() // close it to unblock Handler 5477 } 5478 case <-time.After(timeout * 10): 5479 // If we didn't get into the Handler in 50ms, that probably means 5480 // the builder was just slow and the Get failed in that time 5481 // but never made it to the server. That's fine. We'll usually 5482 // test the part above on faster machines. 5483 t.Skip("skipping test on slow builder") 5484 } 5485 } 5486 5487 // Issue 23399: verify that if a client request times out, the Transport's 5488 // conn is closed so that it's not reused. 5489 // 5490 // This is the test variant that has the server send response headers 5491 // first, and time out during the write of the response body. 5492 func TestClientTimeoutKillsConn_AfterHeaders(t *testing.T) { 5493 setParallel(t) 5494 defer afterTest(t) 5495 inHandler := make(chan net.Conn, 1) 5496 handlerResult := make(chan error, 1) 5497 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 5498 w.Header().Set("Content-Length", "100") 5499 w.(Flusher).Flush() 5500 conn, _, err := w.(Hijacker).Hijack() 5501 if err != nil { 5502 t.Error(err) 5503 return 5504 } 5505 conn.Write([]byte("foo")) 5506 inHandler <- conn 5507 n, err := conn.Read([]byte{0}) 5508 // The error should be io.EOF or "read tcp 5509 // 127.0.0.1:35827->127.0.0.1:40290: read: connection 5510 // reset by peer" depending on timing. Really we just 5511 // care that it returns at all. But if it returns with 5512 // data, that's weird. 5513 if n != 0 || err == nil { 5514 handlerResult <- fmt.Errorf("unexpected Read result: %v, %v", n, err) 5515 return 5516 } 5517 handlerResult <- nil 5518 })) 5519 defer cst.close() 5520 5521 // Set Timeout to something very long but non-zero to exercise 5522 // the codepaths that check for it. But rather than wait for it to fire 5523 // (which would make the test slow), we send on the req.Cancel channel instead, 5524 // which happens to exercise the same code paths. 5525 cst.c.Timeout = time.Minute // just to be non-zero, not to hit it. 5526 req, _ := NewRequest("GET", cst.ts.URL, nil) 5527 cancel := make(chan struct{}) 5528 req.Cancel = cancel 5529 5530 res, err := cst.c.Do(req) 5531 if err != nil { 5532 select { 5533 case <-inHandler: 5534 t.Fatalf("Get error: %v", err) 5535 default: 5536 // Failed before entering handler. Ignore result. 5537 t.Skip("skipping test on slow builder") 5538 } 5539 } 5540 5541 close(cancel) 5542 got, err := io.ReadAll(res.Body) 5543 if err == nil { 5544 t.Fatalf("unexpected success; read %q, nil", got) 5545 } 5546 5547 select { 5548 case c := <-inHandler: 5549 select { 5550 case err := <-handlerResult: 5551 if err != nil { 5552 t.Errorf("handler: %v", err) 5553 } 5554 return 5555 case <-time.After(5 * time.Second): 5556 t.Error("Handler's conn.Read seems to be stuck in Read") 5557 c.Close() // close it to unblock Handler 5558 } 5559 case <-time.After(5 * time.Second): 5560 t.Fatal("timeout") 5561 } 5562 } 5563 5564 func TestTransportResponseBodyWritableOnProtocolSwitch(t *testing.T) { 5565 setParallel(t) 5566 defer afterTest(t) 5567 done := make(chan struct{}) 5568 defer close(done) 5569 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 5570 conn, _, err := w.(Hijacker).Hijack() 5571 if err != nil { 5572 t.Error(err) 5573 return 5574 } 5575 defer conn.Close() 5576 io.WriteString(conn, "HTTP/1.1 101 Switching Protocols Hi\r\nConnection: upgRADe\r\nUpgrade: foo\r\n\r\nSome buffered data\n") 5577 bs := bufio.NewScanner(conn) 5578 bs.Scan() 5579 fmt.Fprintf(conn, "%s\n", strings.ToUpper(bs.Text())) 5580 <-done 5581 })) 5582 defer cst.close() 5583 5584 req, _ := NewRequest("GET", cst.ts.URL, nil) 5585 req.Header.Set("Upgrade", "foo") 5586 req.Header.Set("Connection", "upgrade") 5587 res, err := cst.c.Do(req) 5588 if err != nil { 5589 t.Fatal(err) 5590 } 5591 if res.StatusCode != 101 { 5592 t.Fatalf("expected 101 switching protocols; got %v, %v", res.Status, res.Header) 5593 } 5594 rwc, ok := res.Body.(io.ReadWriteCloser) 5595 if !ok { 5596 t.Fatalf("expected a ReadWriteCloser; got a %T", res.Body) 5597 } 5598 defer rwc.Close() 5599 bs := bufio.NewScanner(rwc) 5600 if !bs.Scan() { 5601 t.Fatalf("expected readable input") 5602 } 5603 if got, want := bs.Text(), "Some buffered data"; got != want { 5604 t.Errorf("read %q; want %q", got, want) 5605 } 5606 io.WriteString(rwc, "echo\n") 5607 if !bs.Scan() { 5608 t.Fatalf("expected another line") 5609 } 5610 if got, want := bs.Text(), "ECHO"; got != want { 5611 t.Errorf("read %q; want %q", got, want) 5612 } 5613 } 5614 5615 func TestTransportCONNECTBidi(t *testing.T) { 5616 defer afterTest(t) 5617 const target = "backend:443" 5618 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 5619 if r.Method != "CONNECT" { 5620 t.Errorf("unexpected method %q", r.Method) 5621 w.WriteHeader(500) 5622 return 5623 } 5624 if r.RequestURI != target { 5625 t.Errorf("unexpected CONNECT target %q", r.RequestURI) 5626 w.WriteHeader(500) 5627 return 5628 } 5629 nc, brw, err := w.(Hijacker).Hijack() 5630 if err != nil { 5631 t.Error(err) 5632 return 5633 } 5634 defer nc.Close() 5635 nc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) 5636 // Switch to a little protocol that capitalize its input lines: 5637 for { 5638 line, err := brw.ReadString('\n') 5639 if err != nil { 5640 if err != io.EOF { 5641 t.Error(err) 5642 } 5643 return 5644 } 5645 io.WriteString(brw, strings.ToUpper(line)) 5646 brw.Flush() 5647 } 5648 })) 5649 defer cst.close() 5650 pr, pw := io.Pipe() 5651 defer pw.Close() 5652 req, err := NewRequest("CONNECT", cst.ts.URL, pr) 5653 if err != nil { 5654 t.Fatal(err) 5655 } 5656 req.URL.Opaque = target 5657 res, err := cst.c.Do(req) 5658 if err != nil { 5659 t.Fatal(err) 5660 } 5661 defer res.Body.Close() 5662 if res.StatusCode != 200 { 5663 t.Fatalf("status code = %d; want 200", res.StatusCode) 5664 } 5665 br := bufio.NewReader(res.Body) 5666 for _, str := range []string{"foo", "bar", "baz"} { 5667 fmt.Fprintf(pw, "%s\n", str) 5668 got, err := br.ReadString('\n') 5669 if err != nil { 5670 t.Fatal(err) 5671 } 5672 got = strings.TrimSpace(got) 5673 want := strings.ToUpper(str) 5674 if got != want { 5675 t.Fatalf("got %q; want %q", got, want) 5676 } 5677 } 5678 } 5679 5680 func TestTransportRequestReplayable(t *testing.T) { 5681 someBody := io.NopCloser(strings.NewReader("")) 5682 tests := []struct { 5683 name string 5684 req *Request 5685 want bool 5686 }{ 5687 { 5688 name: "GET", 5689 req: &Request{Method: "GET"}, 5690 want: true, 5691 }, 5692 { 5693 name: "GET_http.NoBody", 5694 req: &Request{Method: "GET", Body: NoBody}, 5695 want: true, 5696 }, 5697 { 5698 name: "GET_body", 5699 req: &Request{Method: "GET", Body: someBody}, 5700 want: false, 5701 }, 5702 { 5703 name: "POST", 5704 req: &Request{Method: "POST"}, 5705 want: false, 5706 }, 5707 { 5708 name: "POST_idempotency-Key", 5709 req: &Request{Method: "POST", Header: Header{"Idempotency-Key": {"x"}}}, 5710 want: true, 5711 }, 5712 { 5713 name: "POST_x-idempotency-Key", 5714 req: &Request{Method: "POST", Header: Header{"X-Idempotency-Key": {"x"}}}, 5715 want: true, 5716 }, 5717 { 5718 name: "POST_body", 5719 req: &Request{Method: "POST", Header: Header{"Idempotency-Key": {"x"}}, Body: someBody}, 5720 want: false, 5721 }, 5722 } 5723 for _, tt := range tests { 5724 t.Run(tt.name, func(t *testing.T) { 5725 got := tt.req.ExportIsReplayable() 5726 if got != tt.want { 5727 t.Errorf("replyable = %v; want %v", got, tt.want) 5728 } 5729 }) 5730 } 5731 } 5732 5733 // testMockTCPConn is a mock TCP connection used to test that 5734 // ReadFrom is called when sending the request body. 5735 type testMockTCPConn struct { 5736 *net.TCPConn 5737 5738 ReadFromCalled bool 5739 } 5740 5741 func (c *testMockTCPConn) ReadFrom(r io.Reader) (int64, error) { 5742 c.ReadFromCalled = true 5743 return c.TCPConn.ReadFrom(r) 5744 } 5745 5746 func TestTransportRequestWriteRoundTrip(t *testing.T) { 5747 nBytes := int64(1 << 10) 5748 newFileFunc := func() (r io.Reader, done func(), err error) { 5749 f, err := os.CreateTemp("", "net-http-newfilefunc") 5750 if err != nil { 5751 return nil, nil, err 5752 } 5753 5754 // Write some bytes to the file to enable reading. 5755 if _, err := io.CopyN(f, rand.Reader, nBytes); err != nil { 5756 return nil, nil, fmt.Errorf("failed to write data to file: %v", err) 5757 } 5758 if _, err := f.Seek(0, 0); err != nil { 5759 return nil, nil, fmt.Errorf("failed to seek to front: %v", err) 5760 } 5761 5762 done = func() { 5763 f.Close() 5764 os.Remove(f.Name()) 5765 } 5766 5767 return f, done, nil 5768 } 5769 5770 newBufferFunc := func() (io.Reader, func(), error) { 5771 return bytes.NewBuffer(make([]byte, nBytes)), func() {}, nil 5772 } 5773 5774 cases := []struct { 5775 name string 5776 readerFunc func() (io.Reader, func(), error) 5777 contentLength int64 5778 expectedReadFrom bool 5779 }{ 5780 { 5781 name: "file, length", 5782 readerFunc: newFileFunc, 5783 contentLength: nBytes, 5784 expectedReadFrom: true, 5785 }, 5786 { 5787 name: "file, no length", 5788 readerFunc: newFileFunc, 5789 }, 5790 { 5791 name: "file, negative length", 5792 readerFunc: newFileFunc, 5793 contentLength: -1, 5794 }, 5795 { 5796 name: "buffer", 5797 contentLength: nBytes, 5798 readerFunc: newBufferFunc, 5799 }, 5800 { 5801 name: "buffer, no length", 5802 readerFunc: newBufferFunc, 5803 }, 5804 { 5805 name: "buffer, length -1", 5806 contentLength: -1, 5807 readerFunc: newBufferFunc, 5808 }, 5809 } 5810 5811 for _, tc := range cases { 5812 t.Run(tc.name, func(t *testing.T) { 5813 r, cleanup, err := tc.readerFunc() 5814 if err != nil { 5815 t.Fatal(err) 5816 } 5817 defer cleanup() 5818 5819 tConn := &testMockTCPConn{} 5820 trFunc := func(tr *Transport) { 5821 tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { 5822 var d net.Dialer 5823 conn, err := d.DialContext(ctx, network, addr) 5824 if err != nil { 5825 return nil, err 5826 } 5827 5828 tcpConn, ok := conn.(*net.TCPConn) 5829 if !ok { 5830 return nil, fmt.Errorf("%s/%s does not provide a *net.TCPConn", network, addr) 5831 } 5832 5833 tConn.TCPConn = tcpConn 5834 return tConn, nil 5835 } 5836 } 5837 5838 cst := newClientServerTest( 5839 t, 5840 h1Mode, 5841 HandlerFunc(func(w ResponseWriter, r *Request) { 5842 io.Copy(io.Discard, r.Body) 5843 r.Body.Close() 5844 w.WriteHeader(200) 5845 }), 5846 trFunc, 5847 ) 5848 defer cst.close() 5849 5850 req, err := NewRequest("PUT", cst.ts.URL, r) 5851 if err != nil { 5852 t.Fatal(err) 5853 } 5854 req.ContentLength = tc.contentLength 5855 req.Header.Set("Content-Type", "application/octet-stream") 5856 resp, err := cst.c.Do(req) 5857 if err != nil { 5858 t.Fatal(err) 5859 } 5860 defer resp.Body.Close() 5861 if resp.StatusCode != 200 { 5862 t.Fatalf("status code = %d; want 200", resp.StatusCode) 5863 } 5864 5865 if !tConn.ReadFromCalled && tc.expectedReadFrom { 5866 t.Fatalf("did not call ReadFrom") 5867 } 5868 5869 if tConn.ReadFromCalled && !tc.expectedReadFrom { 5870 t.Fatalf("ReadFrom was unexpectedly invoked") 5871 } 5872 }) 5873 } 5874 } 5875 5876 func TestTransportClone(t *testing.T) { 5877 tr := &Transport{ 5878 Proxy: func(*Request) (*url.URL, error) { panic("") }, 5879 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { panic("") }, 5880 Dial: func(network, addr string) (net.Conn, error) { panic("") }, 5881 DialTLS: func(network, addr string) (net.Conn, error) { panic("") }, 5882 DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { panic("") }, 5883 TLSClientConfig: new(tls.Config), 5884 TLSHandshakeTimeout: time.Second, 5885 DisableKeepAlives: true, 5886 DisableCompression: true, 5887 MaxIdleConns: 1, 5888 MaxIdleConnsPerHost: 1, 5889 MaxConnsPerHost: 1, 5890 IdleConnTimeout: time.Second, 5891 ResponseHeaderTimeout: time.Second, 5892 ExpectContinueTimeout: time.Second, 5893 ProxyConnectHeader: Header{}, 5894 GetProxyConnectHeader: func(context.Context, *url.URL, string) (Header, error) { return nil, nil }, 5895 MaxResponseHeaderBytes: 1, 5896 ForceAttemptHTTP2: true, 5897 TLSNextProto: map[string]func(authority string, c *tls.Conn) RoundTripper{ 5898 "foo": func(authority string, c *tls.Conn) RoundTripper { panic("") }, 5899 }, 5900 ReadBufferSize: 1, 5901 WriteBufferSize: 1, 5902 } 5903 tr2 := tr.Clone() 5904 rv := reflect.ValueOf(tr2).Elem() 5905 rt := rv.Type() 5906 for i := 0; i < rt.NumField(); i++ { 5907 sf := rt.Field(i) 5908 if !token.IsExported(sf.Name) { 5909 continue 5910 } 5911 if rv.Field(i).IsZero() { 5912 t.Errorf("cloned field t2.%s is zero", sf.Name) 5913 } 5914 } 5915 5916 if _, ok := tr2.TLSNextProto["foo"]; !ok { 5917 t.Errorf("cloned Transport lacked TLSNextProto 'foo' Key") 5918 } 5919 5920 // But test that a nil TLSNextProto is kept nil: 5921 tr = new(Transport) 5922 tr2 = tr.Clone() 5923 if tr2.TLSNextProto != nil { 5924 t.Errorf("Transport.TLSNextProto unexpected non-nil") 5925 } 5926 } 5927 5928 func TestIs408(t *testing.T) { 5929 tests := []struct { 5930 in string 5931 want bool 5932 }{ 5933 {"HTTP/1.0 408", true}, 5934 {"HTTP/1.1 408", true}, 5935 {"HTTP/1.8 408", true}, 5936 {"HTTP/2.0 408", false}, // maybe h2c would do this? but false for now. 5937 {"HTTP/1.1 408 ", true}, 5938 {"HTTP/1.1 40", false}, 5939 {"http/1.0 408", false}, 5940 {"HTTP/1-1 408", false}, 5941 } 5942 for _, tt := range tests { 5943 if got := Export_is408Message([]byte(tt.in)); got != tt.want { 5944 t.Errorf("is408Message(%q) = %v; want %v", tt.in, got, tt.want) 5945 } 5946 } 5947 } 5948 5949 func TestTransportIgnores408(t *testing.T) { 5950 // Not parallel. Relies on mutating the log package's global Output. 5951 defer log.SetOutput(log.Writer()) 5952 5953 var logout bytes.Buffer 5954 log.SetOutput(&logout) 5955 5956 defer afterTest(t) 5957 const target = "backend:443" 5958 5959 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 5960 nc, _, err := w.(Hijacker).Hijack() 5961 if err != nil { 5962 t.Error(err) 5963 return 5964 } 5965 defer nc.Close() 5966 nc.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok")) 5967 nc.Write([]byte("HTTP/1.1 408 bye\r\n")) // changing 408 to 409 makes test fail 5968 })) 5969 defer cst.close() 5970 req, err := NewRequest("GET", cst.ts.URL, nil) 5971 if err != nil { 5972 t.Fatal(err) 5973 } 5974 res, err := cst.c.Do(req) 5975 if err != nil { 5976 t.Fatal(err) 5977 } 5978 slurp, err := io.ReadAll(res.Body) 5979 if err != nil { 5980 t.Fatal(err) 5981 } 5982 if err != nil { 5983 t.Fatal(err) 5984 } 5985 if string(slurp) != "ok" { 5986 t.Fatalf("got %q; want ok", slurp) 5987 } 5988 5989 t0 := time.Now() 5990 for i := 0; i < 50; i++ { 5991 time.Sleep(time.Duration(i) * 5 * time.Millisecond) 5992 if cst.tr.IdleConnKeyCountForTesting() == 0 { 5993 if got := logout.String(); got != "" { 5994 t.Fatalf("expected no log output; got: %s", got) 5995 } 5996 return 5997 } 5998 } 5999 t.Fatalf("timeout after %v waiting for Transport connections to die off", time.Since(t0)) 6000 } 6001 6002 func TestInvalidHeaderResponse(t *testing.T) { 6003 setParallel(t) 6004 defer afterTest(t) 6005 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 6006 conn, buf, _ := w.(Hijacker).Hijack() 6007 buf.Write([]byte("HTTP/1.1 200 OK\r\n" + 6008 "Date: Wed, 30 Aug 2017 19:09:27 GMT\r\n" + 6009 "Content-Type: text/html; charset=utf-8\r\n" + 6010 "Content-Length: 0\r\n" + 6011 "Foo : bar\r\n\r\n")) 6012 buf.Flush() 6013 conn.Close() 6014 })) 6015 defer cst.close() 6016 res, err := cst.c.Get(cst.ts.URL) 6017 if err != nil { 6018 t.Fatal(err) 6019 } 6020 defer res.Body.Close() 6021 if v := res.Header.Get("Foo"); v != "" { 6022 t.Errorf(`unexpected "Foo" header: %q`, v) 6023 } 6024 if v := res.Header.Get("Foo "); v != "bar" { 6025 t.Errorf(`bad "Foo " header value: %q, want %q`, v, "bar") 6026 } 6027 } 6028 6029 type bodyCloser bool 6030 6031 func (bc *bodyCloser) Close() error { 6032 *bc = true 6033 return nil 6034 } 6035 func (bc *bodyCloser) Read(b []byte) (n int, err error) { 6036 return 0, io.EOF 6037 } 6038 6039 // Issue 35015: ensure that Transport closes the body on any error 6040 // with an invalid request, as promised by Client.Do docs. 6041 func TestTransportClosesBodyOnInvalidRequests(t *testing.T) { 6042 cst := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 6043 t.Errorf("Should not have been invoked") 6044 })) 6045 defer cst.Close() 6046 6047 u, _ := url.Parse(cst.URL) 6048 6049 tests := []struct { 6050 name string 6051 req *Request 6052 wantErr string 6053 }{ 6054 { 6055 name: "invalid method", 6056 req: &Request{ 6057 Method: " ", 6058 URL: u, 6059 }, 6060 wantErr: "invalid method", 6061 }, 6062 { 6063 name: "nil URL", 6064 req: &Request{ 6065 Method: "GET", 6066 }, 6067 wantErr: "nil Request.URL", 6068 }, 6069 { 6070 name: "invalid header Key", 6071 req: &Request{ 6072 Method: "GET", 6073 Header: Header{"💡": {"emoji"}}, 6074 URL: u, 6075 }, 6076 wantErr: "invalid header field name", 6077 }, 6078 { 6079 name: "invalid header value", 6080 req: &Request{ 6081 Method: "POST", 6082 Header: Header{"Key": {"\x19"}}, 6083 URL: u, 6084 }, 6085 wantErr: "invalid header field value", 6086 }, 6087 { 6088 name: "non HTTP(s) scheme", 6089 req: &Request{ 6090 Method: "POST", 6091 URL: &url.URL{Scheme: "faux"}, 6092 }, 6093 wantErr: "unsupported protocol scheme", 6094 }, 6095 { 6096 name: "no Host in URL", 6097 req: &Request{ 6098 Method: "POST", 6099 URL: &url.URL{Scheme: "http"}, 6100 }, 6101 wantErr: "no Host", 6102 }, 6103 } 6104 6105 for _, tt := range tests { 6106 t.Run(tt.name, func(t *testing.T) { 6107 var bc bodyCloser 6108 req := tt.req 6109 req.Body = &bc 6110 _, err := DefaultClient.Do(tt.req) 6111 if err == nil { 6112 t.Fatal("Expected an error") 6113 } 6114 if !bc { 6115 t.Fatal("Expected body to have been closed") 6116 } 6117 if g, w := err.Error(), tt.wantErr; !strings.Contains(g, w) { 6118 t.Fatalf("Error mismatch\n\t%q\ndoes not contain\n\t%q", g, w) 6119 } 6120 }) 6121 } 6122 } 6123 6124 // breakableConn is a net.Conn wrapper with a Write method 6125 // that will fail when its brokenState is true. 6126 type breakableConn struct { 6127 net.Conn 6128 *brokenState 6129 } 6130 6131 type brokenState struct { 6132 sync.Mutex 6133 broken bool 6134 } 6135 6136 func (w *breakableConn) Write(b []byte) (n int, err error) { 6137 w.Lock() 6138 defer w.Unlock() 6139 if w.broken { 6140 return 0, errors.New("some write error") 6141 } 6142 return w.Conn.Write(b) 6143 } 6144 6145 // Issue 34978: don't cache a broken HTTP/2 connection 6146 func TestDontCacheBrokenHTTP2Conn(t *testing.T) { 6147 cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {}), optQuietLog) 6148 defer cst.close() 6149 6150 var brokenState brokenState 6151 6152 const numReqs = 5 6153 var numDials, gotConns uint32 // atomic 6154 6155 cst.tr.Dial = func(netw, addr string) (net.Conn, error) { 6156 atomic.AddUint32(&numDials, 1) 6157 c, err := net.Dial(netw, addr) 6158 if err != nil { 6159 t.Errorf("unexpected Dial error: %v", err) 6160 return nil, err 6161 } 6162 return &breakableConn{c, &brokenState}, err 6163 } 6164 6165 for i := 1; i <= numReqs; i++ { 6166 brokenState.Lock() 6167 brokenState.broken = false 6168 brokenState.Unlock() 6169 6170 // doBreak controls whether we break the TCP connection after the TLS 6171 // handshake (before the HTTP/2 handshake). We test a few failures 6172 // in a row followed by a final success. 6173 doBreak := i != numReqs 6174 6175 ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ 6176 GotConn: func(info httptrace.GotConnInfo) { 6177 t.Logf("got conn: %v, reused=%v, wasIdle=%v, idleTime=%v", info.Conn.LocalAddr(), info.Reused, info.WasIdle, info.IdleTime) 6178 atomic.AddUint32(&gotConns, 1) 6179 }, 6180 TLSHandshakeDone: func(cfg tls.ConnectionState, err error) { 6181 brokenState.Lock() 6182 defer brokenState.Unlock() 6183 if doBreak { 6184 brokenState.broken = true 6185 } 6186 }, 6187 }) 6188 req, err := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil) 6189 if err != nil { 6190 t.Fatal(err) 6191 } 6192 _, err = cst.c.Do(req) 6193 if doBreak != (err != nil) { 6194 t.Errorf("for iteration %d, doBreak=%v; unexpected error %v", i, doBreak, err) 6195 } 6196 } 6197 if got, want := atomic.LoadUint32(&gotConns), 1; int(got) != want { 6198 t.Errorf("GotConn calls = %v; want %v", got, want) 6199 } 6200 if got, want := atomic.LoadUint32(&numDials), numReqs; int(got) != want { 6201 t.Errorf("Dials = %v; want %v", got, want) 6202 } 6203 } 6204 6205 // Issue 34941 6206 // When the client has too many concurrent requests on a single connection, 6207 // http.http2noCachedConnError is reported on multiple requests. There should 6208 // only be one decrement regardless of the number of failures. 6209 func TestTransportDecrementConnWhenIdleConnRemoved(t *testing.T) { 6210 defer afterTest(t) 6211 CondSkipHTTP2(t) 6212 6213 h := HandlerFunc(func(w ResponseWriter, r *Request) { 6214 _, err := w.Write([]byte("foo")) 6215 if err != nil { 6216 t.Fatalf("Write: %v", err) 6217 } 6218 }) 6219 6220 ts := httptest.NewUnstartedServer(h) 6221 ts.EnableHTTP2 = true 6222 ts.StartTLS() 6223 defer ts.Close() 6224 6225 c := ts.Client() 6226 tr := c.Transport.(*Transport) 6227 tr.MaxConnsPerHost = 1 6228 if err := ExportHttp2ConfigureTransport(tr); err != nil { 6229 t.Fatalf("ExportHttp2ConfigureTransport: %v", err) 6230 } 6231 6232 errCh := make(chan error, 300) 6233 doReq := func() { 6234 resp, err := c.Get(ts.URL) 6235 if err != nil { 6236 errCh <- fmt.Errorf("request failed: %v", err) 6237 return 6238 } 6239 defer resp.Body.Close() 6240 _, err = io.ReadAll(resp.Body) 6241 if err != nil { 6242 errCh <- fmt.Errorf("read body failed: %v", err) 6243 } 6244 } 6245 6246 var wg sync.WaitGroup 6247 for i := 0; i < 300; i++ { 6248 wg.Add(1) 6249 go func() { 6250 defer wg.Done() 6251 doReq() 6252 }() 6253 } 6254 wg.Wait() 6255 close(errCh) 6256 6257 for err := range errCh { 6258 t.Errorf("error occurred: %v", err) 6259 } 6260 } 6261 6262 // Issue 36820 6263 // Test that we use the older backward compatible cancellation protocol 6264 // when a RoundTripper is registered via RegisterProtocol. 6265 func TestAltProtoCancellation(t *testing.T) { 6266 defer afterTest(t) 6267 tr := &Transport{} 6268 c := &Client{ 6269 Transport: tr, 6270 Timeout: time.Millisecond, 6271 } 6272 tr.RegisterProtocol("timeout", timeoutProto{}) 6273 _, err := c.Get("timeout://bar.com/path") 6274 if err == nil { 6275 t.Error("request unexpectedly succeeded") 6276 } else if !strings.Contains(err.Error(), timeoutProtoErr.Error()) { 6277 t.Errorf("got error %q, does not contain expected string %q", err, timeoutProtoErr) 6278 } 6279 } 6280 6281 var timeoutProtoErr = errors.New("canceled as expected") 6282 6283 type timeoutProto struct{} 6284 6285 func (timeoutProto) RoundTrip(req *Request) (*Response, error) { 6286 select { 6287 case <-req.Cancel: 6288 return nil, timeoutProtoErr 6289 case <-time.After(5 * time.Second): 6290 return nil, errors.New("request was not canceled") 6291 } 6292 } 6293 6294 type roundTripFunc func(r *Request) (*Response, error) 6295 6296 func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) { return f(r) } 6297 6298 // Issue 32441: body is not reset after ErrSkipAltProtocol 6299 func TestIssue32441(t *testing.T) { 6300 defer afterTest(t) 6301 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 6302 if n, _ := io.Copy(io.Discard, r.Body); n == 0 { 6303 t.Error("body length is zero") 6304 } 6305 })) 6306 defer ts.Close() 6307 c := ts.Client() 6308 c.Transport.(*Transport).RegisterProtocol("http", roundTripFunc(func(r *Request) (*Response, error) { 6309 // Draining body to trigger failure condition on actual request to server. 6310 if n, _ := io.Copy(io.Discard, r.Body); n == 0 { 6311 t.Error("body length is zero during round trip") 6312 } 6313 return nil, ErrSkipAltProtocol 6314 })) 6315 if _, err := c.Post(ts.URL, "application/octet-stream", bytes.NewBufferString("data")); err != nil { 6316 t.Error(err) 6317 } 6318 } 6319 6320 // Issue 39017. Ensure that HTTP/1 transports reject Content-Length headers 6321 // that contain a sign (eg. "+3"), per RFC 2616, Section 14.13. 6322 func TestTransportRejectsSignInContentLength(t *testing.T) { 6323 cst := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 6324 w.Header().Set("Content-Length", "+3") 6325 w.Write([]byte("abc")) 6326 })) 6327 defer cst.Close() 6328 6329 c := cst.Client() 6330 res, err := c.Get(cst.URL) 6331 if err == nil || res != nil { 6332 t.Fatal("Expected a non-nil error and a nil http.Response") 6333 } 6334 if got, want := err.Error(), `bad Content-Length "+3"`; !strings.Contains(got, want) { 6335 t.Fatalf("Error mismatch\nGot: %q\nWanted substring: %q", got, want) 6336 } 6337 } 6338 6339 // dumpConn is a net.Conn which writes to Writer and reads from Reader 6340 type dumpConn struct { 6341 io.Writer 6342 io.Reader 6343 } 6344 6345 func (c *dumpConn) Close() error { return nil } 6346 func (c *dumpConn) LocalAddr() net.Addr { return nil } 6347 func (c *dumpConn) RemoteAddr() net.Addr { return nil } 6348 func (c *dumpConn) SetDeadline(t time.Time) error { return nil } 6349 func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil } 6350 func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil } 6351 6352 // delegateReader is a reader that delegates to another reader, 6353 // once it arrives on a channel. 6354 type delegateReader struct { 6355 c chan io.Reader 6356 r io.Reader // nil until received from c 6357 } 6358 6359 func (r *delegateReader) Read(p []byte) (int, error) { 6360 if r.r == nil { 6361 var ok bool 6362 if r.r, ok = <-r.c; !ok { 6363 return 0, errors.New("delegate closed") 6364 } 6365 } 6366 return r.r.Read(p) 6367 } 6368 6369 func testTransportRace(req *Request) { 6370 save := req.Body 6371 pr, pw := io.Pipe() 6372 defer pr.Close() 6373 defer pw.Close() 6374 dr := &delegateReader{c: make(chan io.Reader)} 6375 6376 t := &Transport{ 6377 Dial: func(net, addr string) (net.Conn, error) { 6378 return &dumpConn{pw, dr}, nil 6379 }, 6380 } 6381 defer t.CloseIdleConnections() 6382 6383 quitReadCh := make(chan struct{}) 6384 // Wait for the request before replying with a dummy response: 6385 go func() { 6386 defer close(quitReadCh) 6387 6388 req, err := ReadRequest(bufio.NewReader(pr)) 6389 if err == nil { 6390 // Ensure all the body is read; otherwise 6391 // we'll get a partial dump. 6392 io.Copy(io.Discard, req.Body) 6393 req.Body.Close() 6394 } 6395 select { 6396 case dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n"): 6397 case quitReadCh <- struct{}{}: 6398 // Ensure delegate is closed so Read doesn't block forever. 6399 close(dr.c) 6400 } 6401 }() 6402 6403 t.RoundTrip(req) 6404 6405 // Ensure the reader returns before we reset req.Body to prevent 6406 // a data race on req.Body. 6407 pw.Close() 6408 <-quitReadCh 6409 6410 req.Body = save 6411 } 6412 6413 // Issue 37669 6414 // Test that a cancellation doesn't result in a data race due to the writeLoop 6415 // goroutine being left running, if the caller mutates the processed Request 6416 // upon completion. 6417 func TestErrorWriteLoopRace(t *testing.T) { 6418 if testing.Short() { 6419 return 6420 } 6421 t.Parallel() 6422 for i := 0; i < 1000; i++ { 6423 delay := time.Duration(mrand.Intn(5)) * time.Millisecond 6424 ctx, cancel := context.WithTimeout(context.Background(), delay) 6425 defer cancel() 6426 6427 r := bytes.NewBuffer(make([]byte, 10000)) 6428 req, err := NewRequestWithContext(ctx, MethodPost, "http://example.com", r) 6429 if err != nil { 6430 t.Fatal(err) 6431 } 6432 6433 testTransportRace(req) 6434 } 6435 } 6436 6437 // Issue 41600 6438 // Test that a new request which uses the connection of an active request 6439 // cannot cause it to be canceled as well. 6440 func TestCancelRequestWhenSharingConnection(t *testing.T) { 6441 if testing.Short() { 6442 t.Skip("skipping in short mode") 6443 } 6444 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) { 6445 w.Header().Add("Content-Length", "0") 6446 })) 6447 defer ts.Close() 6448 6449 client := ts.Client() 6450 transport := client.Transport.(*Transport) 6451 transport.MaxIdleConns = 1 6452 transport.MaxConnsPerHost = 1 6453 6454 var wg sync.WaitGroup 6455 6456 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 6457 6458 for i := 0; i < 10; i++ { 6459 wg.Add(1) 6460 go func() { 6461 defer wg.Done() 6462 for ctx.Err() == nil { 6463 reqctx, reqcancel := context.WithCancel(ctx) 6464 go reqcancel() 6465 req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil) 6466 res, err := client.Do(req) 6467 if err == nil { 6468 res.Body.Close() 6469 } 6470 } 6471 }() 6472 } 6473 6474 for ctx.Err() == nil { 6475 req, _ := NewRequest("GET", ts.URL, nil) 6476 if res, err := client.Do(req); err != nil { 6477 t.Errorf("unexpected: %p %v", req, err) 6478 break 6479 } else { 6480 res.Body.Close() 6481 } 6482 } 6483 6484 cancel() 6485 wg.Wait() 6486 }