func configureTransport(t1 *http.Transport) error { connPool := new(clientConnPool) t2 := &Transport{ConnPool: noDialClientConnPool{connPool}} if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil { return err } if t1.TLSClientConfig == nil { t1.TLSClientConfig = new(tls.Config) } if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") { t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...) } upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper { cc, err := t2.NewClientConn(c) if err != nil { c.Close() return erringRoundTripper{err} } connPool.addConn(authorityAddr(authority), cc) return t2 } if m := t1.TLSNextProto; len(m) == 0 { t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{ "h2": upgradeFn, } } else { m["h2"] = upgradeFn } return nil }
func NewClient(e *Env, config *ClientConfig, needCookie bool) *Client { var jar *cookiejar.Jar if needCookie && (config == nil || config.UseCookies) && e.GetTorMode().UseCookies() { jar, _ = cookiejar.New(nil) } var timeout time.Duration // from http.DefaultTransport; // // TODO: change this back (see comment below) to allow // shared Transport after we switch to go1.7 xprt := http.Transport{ Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).Dial, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, } // This disables HTTP/2. There's a bug introduced between (go1.6, go1.6.3] // that makes client.Get hang on certain HTTP/2 servers. See CORE-3441 for // details. // // TODO: remove this after the bug is fixed. xprt.TLSNextProto = make( map[string]func(authority string, c *tls.Conn) http.RoundTripper) if (config != nil && config.RootCAs != nil) || e.GetTorMode().Enabled() { if config != nil && config.RootCAs != nil { xprt.TLSClientConfig = &tls.Config{RootCAs: config.RootCAs} } if e.GetTorMode().Enabled() { dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, e.GetTorProxy()) xprt.Dial = dialSocksProxy } else { xprt.Proxy = http.ProxyFromEnvironment } } if config == nil || config.Timeout == 0 { timeout = HTTPDefaultTimeout } else { timeout = config.Timeout } ret := &Client{ cli: &http.Client{Timeout: timeout}, config: config, } if jar != nil { ret.cli.Jar = jar } ret.cli.Transport = &xprt return ret }
func configureTransport(t1 *http.Transport) (*Transport, error) { connPool := new(clientConnPool) t2 := &Transport{ ConnPool: noDialClientConnPool{connPool}, t1: t1, } connPool.t = t2 if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil { return nil, err } if t1.TLSClientConfig == nil { t1.TLSClientConfig = new(tls.Config) } if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") { t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...) } if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") { t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1") } upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper { addr := authorityAddr(authority) if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil { go c.Close() return erringRoundTripper{err} } else if !used { // Turns out we don't need this c. // For example, two goroutines made requests to the same host // at the same time, both kicking off TCP dials. (since protocol // was unknown) go c.Close() } return t2 } if m := t1.TLSNextProto; len(m) == 0 { t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{ "h2": upgradeFn, } } else { m["h2"] = upgradeFn } return t2, nil }