diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 9a722e752ae..d6e749f8cda 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -3585,7 +3585,23 @@ func (sew http2stickyErrWriter) Write(p []byte) (n int, err error) { return } +var http2ErrNoCachedConn = errors.New("http2: no cached connection was available") + +// RoundTripOpt are options for the Transport.RoundTripOpt method. +type http2RoundTripOpt struct { + // OnlyCachedConn controls whether RoundTripOpt may + // create a new TCP connection. If set true and + // no cached connection is available, RoundTripOpt + // will return ErrNoCachedConn. + OnlyCachedConn bool +} + func (t *http2Transport) RoundTrip(req *Request) (*Response, error) { + return t.RoundTripOpt(req, http2RoundTripOpt{}) +} + +// RoundTripOpt is like RoundTrip, but takes options. +func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) { if req.URL.Scheme != "https" { return nil, errors.New("http2: unsupported scheme") } @@ -3597,7 +3613,7 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) { } for { - cc, err := t.getClientConn(host, port) + cc, err := t.getClientConn(host, port, opt.OnlyCachedConn) if err != nil { return nil, err } @@ -3692,7 +3708,7 @@ func (t *http2Transport) addConn(key string, cc *http2clientConn) { t.conns[key] = append(t.conns[key], cc) } -func (t *http2Transport) getClientConn(host, port string) (*http2clientConn, error) { +func (t *http2Transport) getClientConn(host, port string, onlyCached bool) (*http2clientConn, error) { key := net.JoinHostPort(host, port) t.connMu.Lock() @@ -3703,6 +3719,9 @@ func (t *http2Transport) getClientConn(host, port string) (*http2clientConn, err } } t.connMu.Unlock() + if onlyCached { + return nil, http2ErrNoCachedConn + } cc, err := t.dialClientConn(host, port, key) if err != nil { diff --git a/src/net/http/transport.go b/src/net/http/transport.go index ad8aa19c2e4..809f6de2892 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -44,23 +44,21 @@ var DefaultTransport RoundTripper = &Transport{ ExpectContinueTimeout: 1 * time.Second, } +// Wire up HTTP/2 support to the DefaultTransport, unless GODEBUG=h2client=0. func init() { - // TODO(bradfitz,adg): remove the following line before Go 1.6 - // ships. This just gives us a mechanism to temporarily - // enable the http2 client during development. - if !strings.Contains(os.Getenv("GODEBUG"), "h2client=1") { + if strings.Contains(os.Getenv("GODEBUG"), "h2client=0") { return } - t := DefaultTransport.(*Transport) - - // TODO(bradfitz,adg): move all this up to DefaultTransport before Go 1.6: t.RegisterProtocol("https", noDialH2Transport{h2DefaultTransport}) t.TLSClientConfig = &tls.Config{ NextProtos: []string{"h2"}, } t.TLSNextProto = map[string]func(string, *tls.Conn) RoundTripper{ - "h2": http2TransportForConn, + "h2": func(authority string, c *tls.Conn) RoundTripper { + h2DefaultTransport.AddIdleConn(authority, c) + return h2DefaultTransport + }, } } @@ -69,14 +67,11 @@ func init() { type noDialH2Transport struct{ rt *http2Transport } func (t noDialH2Transport) RoundTrip(req *Request) (*Response, error) { - // TODO(bradfitz): wire up http2.Transport - return nil, ErrSkipAltProtocol -} - -func http2TransportForConn(authority string, c *tls.Conn) RoundTripper { - // TODO(bradfitz): donate c to h2DefaultTransport: - // h2DefaultTransport.AddIdleConn(authority, c) - return h2DefaultTransport + res, err := t.rt.RoundTripOpt(req, http2RoundTripOpt{OnlyCachedConn: true}) + if err == http2ErrNoCachedConn { + return nil, ErrSkipAltProtocol + } + return res, err } // DefaultMaxIdleConnsPerHost is the default value of Transport's