Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1438)

Delta Between Two Patch Sets: src/pkg/net/http/transport.go

Issue 137940043: code review 137940043: net/http: add Transport.DialTLS hook (Closed)
Left Patch Set: diff -r fdb52a28028a3144f8350dee3b56b15493ebf148 https://go.googlecode.com/hg/ Created 9 years, 7 months ago
Right Patch Set: diff -r 0a5fafdd2343b083457d0baf6487dfce0f01e25f https://go.googlecode.com/hg/ Created 9 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/pkg/net/http/transport_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // HTTP client implementation. See RFC 2616. 5 // HTTP client implementation. See RFC 2616.
6 // 6 //
7 // This is the low-level Transport implementation of RoundTripper. 7 // This is the low-level Transport implementation of RoundTripper.
8 // The high-level interface is in client.go. 8 // The high-level interface is in client.go.
9 9
10 package http 10 package http
(...skipping 25 matching lines...) Expand all
36 Timeout: 30 * time.Second, 36 Timeout: 30 * time.Second,
37 KeepAlive: 30 * time.Second, 37 KeepAlive: 30 * time.Second,
38 }).Dial, 38 }).Dial,
39 TLSHandshakeTimeout: 10 * time.Second, 39 TLSHandshakeTimeout: 10 * time.Second,
40 } 40 }
41 41
42 // DefaultMaxIdleConnsPerHost is the default value of Transport's 42 // DefaultMaxIdleConnsPerHost is the default value of Transport's
43 // MaxIdleConnsPerHost. 43 // MaxIdleConnsPerHost.
44 const DefaultMaxIdleConnsPerHost = 2 44 const DefaultMaxIdleConnsPerHost = 2
45 45
46 // Transport is an implementation of RoundTripper that supports http, 46 // Transport is an implementation of RoundTripper that supports HTTP,
47 // https, and http proxies (for either http or https with CONNECT). 47 // HTTPS, and HTTP proxies (for either HTTP or HTTPS with CONNECT).
48 // Transport can also cache connections for future re-use. 48 // Transport can also cache connections for future re-use.
49 type Transport struct { 49 type Transport struct {
50 idleMu sync.Mutex 50 idleMu sync.Mutex
51 idleConn map[connectMethodKey][]*persistConn 51 idleConn map[connectMethodKey][]*persistConn
52 idleConnCh map[connectMethodKey]chan *persistConn 52 idleConnCh map[connectMethodKey]chan *persistConn
53 reqMu sync.Mutex 53 reqMu sync.Mutex
54 reqCanceler map[*Request]func() 54 reqCanceler map[*Request]func()
55 altMu sync.RWMutex 55 altMu sync.RWMutex
56 altProto map[string]RoundTripper // nil or map of URI scheme => Round Tripper 56 altProto map[string]RoundTripper // nil or map of URI scheme => Round Tripper
57 57
58 // Proxy specifies a function to return a proxy for a given 58 // Proxy specifies a function to return a proxy for a given
59 // Request. If the function returns a non-nil error, the 59 // Request. If the function returns a non-nil error, the
60 // request is aborted with the provided error. 60 // request is aborted with the provided error.
61 // If Proxy is nil or returns a nil *URL, no proxy is used. 61 // If Proxy is nil or returns a nil *URL, no proxy is used.
62 Proxy func(*Request) (*url.URL, error) 62 Proxy func(*Request) (*url.URL, error)
63 63
64 » // Dial specifies the dial function for creating TCP 64 » // Dial specifies the dial function for creating unencrypted
65 » // connections. 65 » // TCP connections.
66 // If Dial is nil, net.Dial is used. 66 // If Dial is nil, net.Dial is used.
67 Dial func(network, addr string) (net.Conn, error) 67 Dial func(network, addr string) (net.Conn, error)
68
69 // DialTLS specifies an optional dial function for creating
70 // TLS connections for non-proxied HTTPS requests.
71 //
72 // If DialTLS is nil, Dial and TLSClientConfig are used.
73 //
74 // If DialTLS is set, the Dial hook is not used for HTTPS
75 // requests and the TLSClientConfig and TLSHandshakeTimeout
76 // are ignored. The returned net.Conn is assumed to already be
77 // past the TLS handshake.
78 DialTLS func(network, addr string) (net.Conn, error)
68 79
69 // TLSClientConfig specifies the TLS configuration to use with 80 // TLSClientConfig specifies the TLS configuration to use with
70 // tls.Client. If nil, the default configuration is used. 81 // tls.Client. If nil, the default configuration is used.
71 TLSClientConfig *tls.Config 82 TLSClientConfig *tls.Config
72 83
73 // TLSHandshakeTimeout specifies the maximum amount of time waiting to 84 // TLSHandshakeTimeout specifies the maximum amount of time waiting to
74 // wait for a TLS handshake. Zero means no timeout. 85 // wait for a TLS handshake. Zero means no timeout.
75 TLSHandshakeTimeout time.Duration 86 TLSHandshakeTimeout time.Duration
76 87
77 // DisableKeepAlives, if true, prevents re-use of TCP connections 88 // DisableKeepAlives, if true, prevents re-use of TCP connections
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 // when it finishes: 508 // when it finishes:
498 handlePendingDial() 509 handlePendingDial()
499 return pc, nil 510 return pc, nil
500 case <-cancelc: 511 case <-cancelc:
501 handlePendingDial() 512 handlePendingDial()
502 return nil, errors.New("net/http: request canceled while waiting for connection") 513 return nil, errors.New("net/http: request canceled while waiting for connection")
503 } 514 }
504 } 515 }
505 516
506 func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) { 517 func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
507 conn, err := t.dial("tcp", cm.addr())
508 if err != nil {
509 if cm.proxyURL != nil {
510 err = fmt.Errorf("http: error connecting to proxy %s: %v ", cm.proxyURL, err)
511 }
512 return nil, err
513 }
514
515 pa := cm.proxyAuth()
516
517 pconn := &persistConn{ 518 pconn := &persistConn{
518 t: t, 519 t: t,
519 cacheKey: cm.key(), 520 cacheKey: cm.key(),
520 conn: conn,
521 reqch: make(chan requestAndChan, 1), 521 reqch: make(chan requestAndChan, 1),
522 writech: make(chan writeRequest, 1), 522 writech: make(chan writeRequest, 1),
523 closech: make(chan struct{}), 523 closech: make(chan struct{}),
524 writeErrCh: make(chan error, 1), 524 writeErrCh: make(chan error, 1),
525 } 525 }
526 526 » tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil
527 » if tlsDial {
528 » » var err error
529 » » pconn.conn, err = t.DialTLS("tcp", cm.addr())
530 » » if err != nil {
531 » » » return nil, err
532 » » }
533 » » if tc, ok := pconn.conn.(*tls.Conn); ok {
534 » » » cs := tc.ConnectionState()
535 » » » pconn.tlsState = &cs
536 » » }
537 » } else {
538 » » conn, err := t.dial("tcp", cm.addr())
539 » » if err != nil {
540 » » » if cm.proxyURL != nil {
541 » » » » err = fmt.Errorf("http: error connecting to prox y %s: %v", cm.proxyURL, err)
542 » » » }
543 » » » return nil, err
544 » » }
545 » » pconn.conn = conn
546 » }
547
548 » // Proxy setup.
527 switch { 549 switch {
528 case cm.proxyURL == nil: 550 case cm.proxyURL == nil:
529 » » // Do nothing. 551 » » // Do nothing. Not using a proxy.
530 case cm.targetScheme == "http": 552 case cm.targetScheme == "http":
531 pconn.isProxy = true 553 pconn.isProxy = true
532 » » if pa != "" { 554 » » if pa := cm.proxyAuth(); pa != "" {
533 pconn.mutateHeaderFunc = func(h Header) { 555 pconn.mutateHeaderFunc = func(h Header) {
534 h.Set("Proxy-Authorization", pa) 556 h.Set("Proxy-Authorization", pa)
535 } 557 }
536 } 558 }
537 case cm.targetScheme == "https": 559 case cm.targetScheme == "https":
560 conn := pconn.conn
538 connectReq := &Request{ 561 connectReq := &Request{
539 Method: "CONNECT", 562 Method: "CONNECT",
540 URL: &url.URL{Opaque: cm.targetAddr}, 563 URL: &url.URL{Opaque: cm.targetAddr},
541 Host: cm.targetAddr, 564 Host: cm.targetAddr,
542 Header: make(Header), 565 Header: make(Header),
543 } 566 }
544 » » if pa != "" { 567 » » if pa := cm.proxyAuth(); pa != "" {
545 connectReq.Header.Set("Proxy-Authorization", pa) 568 connectReq.Header.Set("Proxy-Authorization", pa)
546 } 569 }
547 connectReq.Write(conn) 570 connectReq.Write(conn)
548 571
549 // Read response. 572 // Read response.
550 // Okay to use and discard buffered reader here, because 573 // Okay to use and discard buffered reader here, because
551 // TLS server will not speak until spoken to. 574 // TLS server will not speak until spoken to.
552 br := bufio.NewReader(conn) 575 br := bufio.NewReader(conn)
553 resp, err := ReadResponse(br, connectReq) 576 resp, err := ReadResponse(br, connectReq)
554 if err != nil { 577 if err != nil {
555 conn.Close() 578 conn.Close()
556 return nil, err 579 return nil, err
557 } 580 }
558 if resp.StatusCode != 200 { 581 if resp.StatusCode != 200 {
559 f := strings.SplitN(resp.Status, " ", 2) 582 f := strings.SplitN(resp.Status, " ", 2)
560 conn.Close() 583 conn.Close()
561 return nil, errors.New(f[1]) 584 return nil, errors.New(f[1])
562 } 585 }
563 } 586 }
564 587
565 » if cm.targetScheme == "https" { 588 » if cm.targetScheme == "https" && !tlsDial {
566 // Initiate TLS and check remote host name against certificate. 589 // Initiate TLS and check remote host name against certificate.
567 cfg := t.TLSClientConfig 590 cfg := t.TLSClientConfig
568 if cfg == nil || cfg.ServerName == "" { 591 if cfg == nil || cfg.ServerName == "" {
569 host := cm.tlsHost() 592 host := cm.tlsHost()
570 if cfg == nil { 593 if cfg == nil {
571 cfg = &tls.Config{ServerName: host} 594 cfg = &tls.Config{ServerName: host}
572 } else { 595 } else {
573 clone := *cfg // shallow clone 596 clone := *cfg // shallow clone
574 clone.ServerName = host 597 clone.ServerName = host
575 cfg = &clone 598 cfg = &clone
576 } 599 }
577 } 600 }
578 » » plainConn := conn 601 » » plainConn := pconn.conn
579 tlsConn := tls.Client(plainConn, cfg) 602 tlsConn := tls.Client(plainConn, cfg)
580 errc := make(chan error, 2) 603 errc := make(chan error, 2)
581 var timer *time.Timer // for canceling TLS handshake 604 var timer *time.Timer // for canceling TLS handshake
582 if d := t.TLSHandshakeTimeout; d != 0 { 605 if d := t.TLSHandshakeTimeout; d != 0 {
583 timer = time.AfterFunc(d, func() { 606 timer = time.AfterFunc(d, func() {
584 errc <- tlsHandshakeTimeoutError{} 607 errc <- tlsHandshakeTimeoutError{}
585 }) 608 })
586 } 609 }
587 go func() { 610 go func() {
588 err := tlsConn.Handshake() 611 err := tlsConn.Handshake()
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after
1210 sawEOF *bool 1233 sawEOF *bool
1211 } 1234 }
1212 1235
1213 func (nr noteEOFReader) Read(p []byte) (n int, err error) { 1236 func (nr noteEOFReader) Read(p []byte) (n int, err error) {
1214 n, err = nr.r.Read(p) 1237 n, err = nr.r.Read(p)
1215 if err == io.EOF { 1238 if err == io.EOF {
1216 *nr.sawEOF = true 1239 *nr.sawEOF = true
1217 } 1240 }
1218 return 1241 return
1219 } 1242 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b