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