Commit 4123be4c authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

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/16693Reviewed-by: default avatarBlake Mizerany <blake.mizerany@gmail.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 4b7d5f0b
...@@ -3585,7 +3585,23 @@ func (sew http2stickyErrWriter) Write(p []byte) (n int, err error) { ...@@ -3585,7 +3585,23 @@ func (sew http2stickyErrWriter) Write(p []byte) (n int, err error) {
return 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) { 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" { if req.URL.Scheme != "https" {
return nil, errors.New("http2: unsupported scheme") return nil, errors.New("http2: unsupported scheme")
} }
...@@ -3597,7 +3613,7 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) { ...@@ -3597,7 +3613,7 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
} }
for { for {
cc, err := t.getClientConn(host, port) cc, err := t.getClientConn(host, port, opt.OnlyCachedConn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -3692,7 +3708,7 @@ func (t *http2Transport) addConn(key string, cc *http2clientConn) { ...@@ -3692,7 +3708,7 @@ func (t *http2Transport) addConn(key string, cc *http2clientConn) {
t.conns[key] = append(t.conns[key], cc) 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) key := net.JoinHostPort(host, port)
t.connMu.Lock() t.connMu.Lock()
...@@ -3703,6 +3719,9 @@ func (t *http2Transport) getClientConn(host, port string) (*http2clientConn, err ...@@ -3703,6 +3719,9 @@ func (t *http2Transport) getClientConn(host, port string) (*http2clientConn, err
} }
} }
t.connMu.Unlock() t.connMu.Unlock()
if onlyCached {
return nil, http2ErrNoCachedConn
}
cc, err := t.dialClientConn(host, port, key) cc, err := t.dialClientConn(host, port, key)
if err != nil { if err != nil {
......
...@@ -44,23 +44,21 @@ var DefaultTransport RoundTripper = &Transport{ ...@@ -44,23 +44,21 @@ var DefaultTransport RoundTripper = &Transport{
ExpectContinueTimeout: 1 * time.Second, ExpectContinueTimeout: 1 * time.Second,
} }
// Wire up HTTP/2 support to the DefaultTransport, unless GODEBUG=h2client=0.
func init() { func init() {
// TODO(bradfitz,adg): remove the following line before Go 1.6 if strings.Contains(os.Getenv("GODEBUG"), "h2client=0") {
// ships. This just gives us a mechanism to temporarily
// enable the http2 client during development.
if !strings.Contains(os.Getenv("GODEBUG"), "h2client=1") {
return return
} }
t := DefaultTransport.(*Transport) t := DefaultTransport.(*Transport)
// TODO(bradfitz,adg): move all this up to DefaultTransport before Go 1.6:
t.RegisterProtocol("https", noDialH2Transport{h2DefaultTransport}) t.RegisterProtocol("https", noDialH2Transport{h2DefaultTransport})
t.TLSClientConfig = &tls.Config{ t.TLSClientConfig = &tls.Config{
NextProtos: []string{"h2"}, NextProtos: []string{"h2"},
} }
t.TLSNextProto = map[string]func(string, *tls.Conn) RoundTripper{ 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() { ...@@ -69,14 +67,11 @@ func init() {
type noDialH2Transport struct{ rt *http2Transport } type noDialH2Transport struct{ rt *http2Transport }
func (t noDialH2Transport) RoundTrip(req *Request) (*Response, error) { func (t noDialH2Transport) RoundTrip(req *Request) (*Response, error) {
// TODO(bradfitz): wire up http2.Transport res, err := t.rt.RoundTripOpt(req, http2RoundTripOpt{OnlyCachedConn: true})
if err == http2ErrNoCachedConn {
return nil, ErrSkipAltProtocol return nil, ErrSkipAltProtocol
} }
return res, err
func http2TransportForConn(authority string, c *tls.Conn) RoundTripper {
// TODO(bradfitz): donate c to h2DefaultTransport:
// h2DefaultTransport.AddIdleConn(authority, c)
return h2DefaultTransport
} }
// DefaultMaxIdleConnsPerHost is the default value of Transport's // DefaultMaxIdleConnsPerHost is the default value of Transport's
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment