From 4123be4cf66bc478cbed1058d362678ade73fb0b Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 5 Nov 2015 10:28:28 +0100 Subject: [PATCH] net/http: enable HTTP/2 support in DefaultTransport The GODEBUG option remains, for now, but only for turning it off. We'll decide what to do with it before release. This CL includes the dependent http2 change (https://golang.org/cl/16692) in the http2 bundle (h2_bundle.go). Updates golang/go#6891 Change-Id: If9723ef627c7ba4f7343dc8cb89ca88ef0fbcb10 Reviewed-on: https://go-review.googlesource.com/16693 Reviewed-by: Blake Mizerany Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/h2_bundle.go | 23 +++++++++++++++++++++-- src/net/http/transport.go | 27 +++++++++++---------------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 9a722e752a..d6e749f8cd 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 ad8aa19c2e..809f6de289 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 -- 2.48.1