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