LEFT | RIGHT |
(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 Loading... |
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 Loading... |
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 Loading... |
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 } |
LEFT | RIGHT |