github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/http2/transport_test.go (about) 1 // Copyright 2015 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 package http2 6 7 import ( 8 "bufio" 9 "bytes" 10 "crypto/tls" 11 "errors" 12 "flag" 13 "fmt" 14 "io" 15 "io/ioutil" 16 "log" 17 "math/rand" 18 "net" 19 "net/http" 20 "net/url" 21 "os" 22 "reflect" 23 "strconv" 24 "strings" 25 "sync" 26 "sync/atomic" 27 "testing" 28 "time" 29 30 "golang.org/x/net/http2/hpack" 31 ) 32 33 var ( 34 extNet = flag.Bool("extnet", false, "do external network tests") 35 transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport") 36 insecure = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove? 37 ) 38 39 var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true} 40 41 func TestTransportExternal(t *testing.T) { 42 if !*extNet { 43 t.Skip("skipping external network test") 44 } 45 req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil) 46 rt := &Transport{TLSClientConfig: tlsConfigInsecure} 47 res, err := rt.RoundTrip(req) 48 if err != nil { 49 t.Fatalf("%v", err) 50 } 51 res.Write(os.Stdout) 52 } 53 54 func TestTransport(t *testing.T) { 55 const body = "sup" 56 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { 57 io.WriteString(w, body) 58 }, optOnlyServer) 59 defer st.Close() 60 61 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 62 defer tr.CloseIdleConnections() 63 64 req, err := http.NewRequest("GET", st.ts.URL, nil) 65 if err != nil { 66 t.Fatal(err) 67 } 68 res, err := tr.RoundTrip(req) 69 if err != nil { 70 t.Fatal(err) 71 } 72 defer res.Body.Close() 73 74 t.Logf("Got res: %+v", res) 75 if g, w := res.StatusCode, 200; g != w { 76 t.Errorf("StatusCode = %v; want %v", g, w) 77 } 78 if g, w := res.Status, "200 OK"; g != w { 79 t.Errorf("Status = %q; want %q", g, w) 80 } 81 wantHeader := http.Header{ 82 "Content-Length": []string{"3"}, 83 "Content-Type": []string{"text/plain; charset=utf-8"}, 84 "Date": []string{"XXX"}, // see cleanDate 85 } 86 cleanDate(res) 87 if !reflect.DeepEqual(res.Header, wantHeader) { 88 t.Errorf("res Header = %v; want %v", res.Header, wantHeader) 89 } 90 if res.Request != req { 91 t.Errorf("Response.Request = %p; want %p", res.Request, req) 92 } 93 if res.TLS == nil { 94 t.Error("Response.TLS = nil; want non-nil") 95 } 96 slurp, err := ioutil.ReadAll(res.Body) 97 if err != nil { 98 t.Errorf("Body read: %v", err) 99 } else if string(slurp) != body { 100 t.Errorf("Body = %q; want %q", slurp, body) 101 } 102 103 } 104 105 func TestTransportReusesConns(t *testing.T) { 106 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { 107 io.WriteString(w, r.RemoteAddr) 108 }, optOnlyServer) 109 defer st.Close() 110 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 111 defer tr.CloseIdleConnections() 112 get := func() string { 113 req, err := http.NewRequest("GET", st.ts.URL, nil) 114 if err != nil { 115 t.Fatal(err) 116 } 117 res, err := tr.RoundTrip(req) 118 if err != nil { 119 t.Fatal(err) 120 } 121 defer res.Body.Close() 122 slurp, err := ioutil.ReadAll(res.Body) 123 if err != nil { 124 t.Fatalf("Body read: %v", err) 125 } 126 addr := strings.TrimSpace(string(slurp)) 127 if addr == "" { 128 t.Fatalf("didn't get an addr in response") 129 } 130 return addr 131 } 132 first := get() 133 second := get() 134 if first != second { 135 t.Errorf("first and second responses were on different connections: %q vs %q", first, second) 136 } 137 } 138 139 // Tests that the Transport only keeps one pending dial open per destination address. 140 // https://golang.org/issue/13397 141 func TestTransportGroupsPendingDials(t *testing.T) { 142 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { 143 io.WriteString(w, r.RemoteAddr) 144 }, optOnlyServer) 145 defer st.Close() 146 tr := &Transport{ 147 TLSClientConfig: tlsConfigInsecure, 148 } 149 defer tr.CloseIdleConnections() 150 var ( 151 mu sync.Mutex 152 dials = map[string]int{} 153 ) 154 var wg sync.WaitGroup 155 for i := 0; i < 10; i++ { 156 wg.Add(1) 157 go func() { 158 defer wg.Done() 159 req, err := http.NewRequest("GET", st.ts.URL, nil) 160 if err != nil { 161 t.Error(err) 162 return 163 } 164 res, err := tr.RoundTrip(req) 165 if err != nil { 166 t.Error(err) 167 return 168 } 169 defer res.Body.Close() 170 slurp, err := ioutil.ReadAll(res.Body) 171 if err != nil { 172 t.Errorf("Body read: %v", err) 173 } 174 addr := strings.TrimSpace(string(slurp)) 175 if addr == "" { 176 t.Errorf("didn't get an addr in response") 177 } 178 mu.Lock() 179 dials[addr]++ 180 mu.Unlock() 181 }() 182 } 183 wg.Wait() 184 if len(dials) != 1 { 185 t.Errorf("saw %d dials; want 1: %v", len(dials), dials) 186 } 187 tr.CloseIdleConnections() 188 if err := retry(50, 10*time.Millisecond, func() error { 189 cp, ok := tr.connPool().(*clientConnPool) 190 if !ok { 191 return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool()) 192 } 193 cp.mu.Lock() 194 defer cp.mu.Unlock() 195 if len(cp.dialing) != 0 { 196 return fmt.Errorf("dialing map = %v; want empty", cp.dialing) 197 } 198 if len(cp.conns) != 0 { 199 return fmt.Errorf("conns = %v; want empty", cp.conns) 200 } 201 if len(cp.keys) != 0 { 202 return fmt.Errorf("keys = %v; want empty", cp.keys) 203 } 204 return nil 205 }); err != nil { 206 t.Errorf("State of pool after CloseIdleConnections: %v", err) 207 } 208 } 209 210 func retry(tries int, delay time.Duration, fn func() error) error { 211 var err error 212 for i := 0; i < tries; i++ { 213 err = fn() 214 if err == nil { 215 return nil 216 } 217 time.Sleep(delay) 218 } 219 return err 220 } 221 222 func TestTransportAbortClosesPipes(t *testing.T) { 223 shutdown := make(chan struct{}) 224 st := newServerTester(t, 225 func(w http.ResponseWriter, r *http.Request) { 226 w.(http.Flusher).Flush() 227 <-shutdown 228 }, 229 optOnlyServer, 230 ) 231 defer st.Close() 232 defer close(shutdown) // we must shutdown before st.Close() to avoid hanging 233 234 done := make(chan struct{}) 235 requestMade := make(chan struct{}) 236 go func() { 237 defer close(done) 238 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 239 req, err := http.NewRequest("GET", st.ts.URL, nil) 240 if err != nil { 241 t.Fatal(err) 242 } 243 res, err := tr.RoundTrip(req) 244 if err != nil { 245 t.Fatal(err) 246 } 247 defer res.Body.Close() 248 close(requestMade) 249 _, err = ioutil.ReadAll(res.Body) 250 if err == nil { 251 t.Error("expected error from res.Body.Read") 252 } 253 }() 254 255 <-requestMade 256 // Now force the serve loop to end, via closing the connection. 257 st.closeConn() 258 // deadlock? that's a bug. 259 select { 260 case <-done: 261 case <-time.After(3 * time.Second): 262 t.Fatal("timeout") 263 } 264 } 265 266 // TODO: merge this with TestTransportBody to make TestTransportRequest? This 267 // could be a table-driven test with extra goodies. 268 func TestTransportPath(t *testing.T) { 269 gotc := make(chan *url.URL, 1) 270 st := newServerTester(t, 271 func(w http.ResponseWriter, r *http.Request) { 272 gotc <- r.URL 273 }, 274 optOnlyServer, 275 ) 276 defer st.Close() 277 278 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 279 defer tr.CloseIdleConnections() 280 const ( 281 path = "/testpath" 282 query = "q=1" 283 ) 284 surl := st.ts.URL + path + "?" + query 285 req, err := http.NewRequest("POST", surl, nil) 286 if err != nil { 287 t.Fatal(err) 288 } 289 c := &http.Client{Transport: tr} 290 res, err := c.Do(req) 291 if err != nil { 292 t.Fatal(err) 293 } 294 defer res.Body.Close() 295 got := <-gotc 296 if got.Path != path { 297 t.Errorf("Read Path = %q; want %q", got.Path, path) 298 } 299 if got.RawQuery != query { 300 t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query) 301 } 302 } 303 304 func randString(n int) string { 305 rnd := rand.New(rand.NewSource(int64(n))) 306 b := make([]byte, n) 307 for i := range b { 308 b[i] = byte(rnd.Intn(256)) 309 } 310 return string(b) 311 } 312 313 var bodyTests = []struct { 314 body string 315 noContentLen bool 316 }{ 317 {body: "some message"}, 318 {body: "some message", noContentLen: true}, 319 {body: ""}, 320 {body: "", noContentLen: true}, 321 {body: strings.Repeat("a", 1<<20), noContentLen: true}, 322 {body: strings.Repeat("a", 1<<20)}, 323 {body: randString(16<<10 - 1)}, 324 {body: randString(16 << 10)}, 325 {body: randString(16<<10 + 1)}, 326 {body: randString(512<<10 - 1)}, 327 {body: randString(512 << 10)}, 328 {body: randString(512<<10 + 1)}, 329 {body: randString(1<<20 - 1)}, 330 {body: randString(1 << 20)}, 331 {body: randString(1<<20 + 2)}, 332 } 333 334 func TestTransportBody(t *testing.T) { 335 gotc := make(chan interface{}, 1) 336 st := newServerTester(t, 337 func(w http.ResponseWriter, r *http.Request) { 338 slurp, err := ioutil.ReadAll(r.Body) 339 if err != nil { 340 gotc <- err 341 } else { 342 gotc <- string(slurp) 343 } 344 }, 345 optOnlyServer, 346 ) 347 defer st.Close() 348 349 for i, tt := range bodyTests { 350 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 351 defer tr.CloseIdleConnections() 352 353 var body io.Reader = strings.NewReader(tt.body) 354 if tt.noContentLen { 355 body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods 356 } 357 req, err := http.NewRequest("POST", st.ts.URL, body) 358 if err != nil { 359 t.Fatalf("#%d: %v", i, err) 360 } 361 c := &http.Client{Transport: tr} 362 res, err := c.Do(req) 363 if err != nil { 364 t.Fatalf("#%d: %v", i, err) 365 } 366 defer res.Body.Close() 367 got := <-gotc 368 if err, ok := got.(error); ok { 369 t.Fatalf("#%d: %v", i, err) 370 } else if got.(string) != tt.body { 371 got := got.(string) 372 t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body)) 373 } 374 } 375 } 376 377 func shortString(v string) string { 378 const maxLen = 100 379 if len(v) <= maxLen { 380 return v 381 } 382 return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:]) 383 } 384 385 func TestTransportDialTLS(t *testing.T) { 386 var mu sync.Mutex // guards following 387 var gotReq, didDial bool 388 389 ts := newServerTester(t, 390 func(w http.ResponseWriter, r *http.Request) { 391 mu.Lock() 392 gotReq = true 393 mu.Unlock() 394 }, 395 optOnlyServer, 396 ) 397 defer ts.Close() 398 tr := &Transport{ 399 DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { 400 mu.Lock() 401 didDial = true 402 mu.Unlock() 403 cfg.InsecureSkipVerify = true 404 c, err := tls.Dial(netw, addr, cfg) 405 if err != nil { 406 return nil, err 407 } 408 return c, c.Handshake() 409 }, 410 } 411 defer tr.CloseIdleConnections() 412 client := &http.Client{Transport: tr} 413 res, err := client.Get(ts.ts.URL) 414 if err != nil { 415 t.Fatal(err) 416 } 417 res.Body.Close() 418 mu.Lock() 419 if !gotReq { 420 t.Error("didn't get request") 421 } 422 if !didDial { 423 t.Error("didn't use dial hook") 424 } 425 } 426 427 func TestConfigureTransport(t *testing.T) { 428 t1 := &http.Transport{} 429 err := ConfigureTransport(t1) 430 if err == errTransportVersion { 431 t.Skip(err) 432 } 433 if err != nil { 434 t.Fatal(err) 435 } 436 if got := fmt.Sprintf("%#v", *t1); !strings.Contains(got, `"h2"`) { 437 // Laziness, to avoid buildtags. 438 t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got) 439 } 440 wantNextProtos := []string{"h2", "http/1.1"} 441 if t1.TLSClientConfig == nil { 442 t.Errorf("nil t1.TLSClientConfig") 443 } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) { 444 t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos) 445 } 446 if err := ConfigureTransport(t1); err == nil { 447 t.Error("unexpected success on second call to ConfigureTransport") 448 } 449 450 // And does it work? 451 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { 452 io.WriteString(w, r.Proto) 453 }, optOnlyServer) 454 defer st.Close() 455 456 t1.TLSClientConfig.InsecureSkipVerify = true 457 c := &http.Client{Transport: t1} 458 res, err := c.Get(st.ts.URL) 459 if err != nil { 460 t.Fatal(err) 461 } 462 slurp, err := ioutil.ReadAll(res.Body) 463 if err != nil { 464 t.Fatal(err) 465 } 466 if got, want := string(slurp), "HTTP/2.0"; got != want { 467 t.Errorf("body = %q; want %q", got, want) 468 } 469 } 470 471 type capitalizeReader struct { 472 r io.Reader 473 } 474 475 func (cr capitalizeReader) Read(p []byte) (n int, err error) { 476 n, err = cr.r.Read(p) 477 for i, b := range p[:n] { 478 if b >= 'a' && b <= 'z' { 479 p[i] = b - ('a' - 'A') 480 } 481 } 482 return 483 } 484 485 type flushWriter struct { 486 w io.Writer 487 } 488 489 func (fw flushWriter) Write(p []byte) (n int, err error) { 490 n, err = fw.w.Write(p) 491 if f, ok := fw.w.(http.Flusher); ok { 492 f.Flush() 493 } 494 return 495 } 496 497 type clientTester struct { 498 t *testing.T 499 tr *Transport 500 sc, cc net.Conn // server and client conn 501 fr *Framer // server's framer 502 client func() error 503 server func() error 504 } 505 506 func newClientTester(t *testing.T) *clientTester { 507 var dialOnce struct { 508 sync.Mutex 509 dialed bool 510 } 511 ct := &clientTester{ 512 t: t, 513 } 514 ct.tr = &Transport{ 515 TLSClientConfig: tlsConfigInsecure, 516 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { 517 dialOnce.Lock() 518 defer dialOnce.Unlock() 519 if dialOnce.dialed { 520 return nil, errors.New("only one dial allowed in test mode") 521 } 522 dialOnce.dialed = true 523 return ct.cc, nil 524 }, 525 } 526 527 ln := newLocalListener(t) 528 cc, err := net.Dial("tcp", ln.Addr().String()) 529 if err != nil { 530 t.Fatal(err) 531 532 } 533 sc, err := ln.Accept() 534 if err != nil { 535 t.Fatal(err) 536 } 537 ln.Close() 538 ct.cc = cc 539 ct.sc = sc 540 ct.fr = NewFramer(sc, sc) 541 return ct 542 } 543 544 func newLocalListener(t *testing.T) net.Listener { 545 ln, err := net.Listen("tcp4", "127.0.0.1:0") 546 if err == nil { 547 return ln 548 } 549 ln, err = net.Listen("tcp6", "[::1]:0") 550 if err != nil { 551 t.Fatal(err) 552 } 553 return ln 554 } 555 556 func (ct *clientTester) greet() { 557 buf := make([]byte, len(ClientPreface)) 558 _, err := io.ReadFull(ct.sc, buf) 559 if err != nil { 560 ct.t.Fatalf("reading client preface: %v", err) 561 } 562 f, err := ct.fr.ReadFrame() 563 if err != nil { 564 ct.t.Fatalf("Reading client settings frame: %v", err) 565 } 566 if sf, ok := f.(*SettingsFrame); !ok { 567 ct.t.Fatalf("Wanted client settings frame; got %v", f) 568 _ = sf // stash it away? 569 } 570 if err := ct.fr.WriteSettings(); err != nil { 571 ct.t.Fatal(err) 572 } 573 if err := ct.fr.WriteSettingsAck(); err != nil { 574 ct.t.Fatal(err) 575 } 576 } 577 578 func (ct *clientTester) run() { 579 errc := make(chan error, 2) 580 ct.start("client", errc, ct.client) 581 ct.start("server", errc, ct.server) 582 for i := 0; i < 2; i++ { 583 if err := <-errc; err != nil { 584 ct.t.Error(err) 585 return 586 } 587 } 588 } 589 590 func (ct *clientTester) start(which string, errc chan<- error, fn func() error) { 591 go func() { 592 finished := false 593 var err error 594 defer func() { 595 if !finished { 596 err = fmt.Errorf("%s goroutine didn't finish.", which) 597 } else if err != nil { 598 err = fmt.Errorf("%s: %v", which, err) 599 } 600 errc <- err 601 }() 602 err = fn() 603 finished = true 604 }() 605 } 606 607 type countingReader struct { 608 n *int64 609 } 610 611 func (r countingReader) Read(p []byte) (n int, err error) { 612 for i := range p { 613 p[i] = byte(i) 614 } 615 atomic.AddInt64(r.n, int64(len(p))) 616 return len(p), err 617 } 618 619 func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) } 620 func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) } 621 622 func testTransportReqBodyAfterResponse(t *testing.T, status int) { 623 const bodySize = 10 << 20 624 ct := newClientTester(t) 625 ct.client = func() error { 626 var n int64 // atomic 627 req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize)) 628 if err != nil { 629 return err 630 } 631 res, err := ct.tr.RoundTrip(req) 632 if err != nil { 633 return fmt.Errorf("RoundTrip: %v", err) 634 } 635 defer res.Body.Close() 636 if res.StatusCode != status { 637 return fmt.Errorf("status code = %v; want %v", res.StatusCode, status) 638 } 639 slurp, err := ioutil.ReadAll(res.Body) 640 if err != nil { 641 return fmt.Errorf("Slurp: %v", err) 642 } 643 if len(slurp) > 0 { 644 return fmt.Errorf("unexpected body: %q", slurp) 645 } 646 if status == 200 { 647 if got := atomic.LoadInt64(&n); got != bodySize { 648 return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize) 649 } 650 } else { 651 if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize { 652 return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize) 653 } 654 } 655 return nil 656 } 657 ct.server = func() error { 658 ct.greet() 659 var buf bytes.Buffer 660 enc := hpack.NewEncoder(&buf) 661 var dataRecv int64 662 var closed bool 663 for { 664 f, err := ct.fr.ReadFrame() 665 if err != nil { 666 return err 667 } 668 //println(fmt.Sprintf("server got frame: %v", f)) 669 switch f := f.(type) { 670 case *WindowUpdateFrame, *SettingsFrame: 671 case *HeadersFrame: 672 if !f.HeadersEnded() { 673 return fmt.Errorf("headers should have END_HEADERS be ended: %v", f) 674 } 675 if f.StreamEnded() { 676 return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f) 677 } 678 time.Sleep(50 * time.Millisecond) // let client send body 679 enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)}) 680 ct.fr.WriteHeaders(HeadersFrameParam{ 681 StreamID: f.StreamID, 682 EndHeaders: true, 683 EndStream: false, 684 BlockFragment: buf.Bytes(), 685 }) 686 case *DataFrame: 687 dataLen := len(f.Data()) 688 dataRecv += int64(dataLen) 689 if dataLen > 0 { 690 if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil { 691 return err 692 } 693 if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil { 694 return err 695 } 696 } 697 if !closed && ((status != 200 && dataRecv > 0) || 698 (status == 200 && dataRecv == bodySize)) { 699 closed = true 700 if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil { 701 return err 702 } 703 return nil 704 } 705 default: 706 return fmt.Errorf("Unexpected client frame %v", f) 707 } 708 } 709 return nil 710 } 711 ct.run() 712 } 713 714 // See golang.org/issue/13444 715 func TestTransportFullDuplex(t *testing.T) { 716 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { 717 w.WriteHeader(200) // redundant but for clarity 718 w.(http.Flusher).Flush() 719 io.Copy(flushWriter{w}, capitalizeReader{r.Body}) 720 fmt.Fprintf(w, "bye.\n") 721 }, optOnlyServer) 722 defer st.Close() 723 724 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 725 defer tr.CloseIdleConnections() 726 c := &http.Client{Transport: tr} 727 728 pr, pw := io.Pipe() 729 req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr)) 730 if err != nil { 731 log.Fatal(err) 732 } 733 res, err := c.Do(req) 734 if err != nil { 735 log.Fatal(err) 736 } 737 defer res.Body.Close() 738 if res.StatusCode != 200 { 739 t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200) 740 } 741 bs := bufio.NewScanner(res.Body) 742 want := func(v string) { 743 if !bs.Scan() { 744 t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err()) 745 } 746 } 747 write := func(v string) { 748 _, err := io.WriteString(pw, v) 749 if err != nil { 750 t.Fatalf("pipe write: %v", err) 751 } 752 } 753 write("foo\n") 754 want("FOO") 755 write("bar\n") 756 want("BAR") 757 pw.Close() 758 want("bye.") 759 if err := bs.Err(); err != nil { 760 t.Fatal(err) 761 } 762 } 763 764 func TestTransportConnectRequest(t *testing.T) { 765 gotc := make(chan *http.Request, 1) 766 st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { 767 gotc <- r 768 }, optOnlyServer) 769 defer st.Close() 770 771 u, err := url.Parse(st.ts.URL) 772 if err != nil { 773 t.Fatal(err) 774 } 775 776 tr := &Transport{TLSClientConfig: tlsConfigInsecure} 777 defer tr.CloseIdleConnections() 778 c := &http.Client{Transport: tr} 779 780 tests := []struct { 781 req *http.Request 782 want string 783 }{ 784 { 785 req: &http.Request{ 786 Method: "CONNECT", 787 Header: http.Header{}, 788 URL: u, 789 }, 790 want: u.Host, 791 }, 792 { 793 req: &http.Request{ 794 Method: "CONNECT", 795 Header: http.Header{}, 796 URL: u, 797 Host: "example.com:123", 798 }, 799 want: "example.com:123", 800 }, 801 } 802 803 for i, tt := range tests { 804 res, err := c.Do(tt.req) 805 if err != nil { 806 t.Errorf("%d. RoundTrip = %v", i, err) 807 continue 808 } 809 res.Body.Close() 810 req := <-gotc 811 if req.Method != "CONNECT" { 812 t.Errorf("method = %q; want CONNECT", req.Method) 813 } 814 if req.Host != tt.want { 815 t.Errorf("Host = %q; want %q", req.Host, tt.want) 816 } 817 if req.URL.Host != tt.want { 818 t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want) 819 } 820 } 821 }