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