Commit 9bad9957 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: enable HTTP/2 on all Transports, not just the DefaultTransport

This mirrors the same behavior and API from the server code to the
client side: if TLSNextProto is nil, HTTP/2 is on by default for
both. If it's non-nil, the user was trying to do something fancy and
step out of their way.

Updates #6891

Change-Id: Ia31808b71f336a8d5b44b985591d72113429e1d4
Reviewed-on: https://go-review.googlesource.com/17300Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 3b3f422a
...@@ -40,15 +40,6 @@ var DefaultTransport RoundTripper = &Transport{ ...@@ -40,15 +40,6 @@ var DefaultTransport RoundTripper = &Transport{
ExpectContinueTimeout: 1 * time.Second, ExpectContinueTimeout: 1 * time.Second,
} }
func init() {
if !strings.Contains(os.Getenv("GODEBUG"), "h2client=0") {
err := http2ConfigureTransport(DefaultTransport.(*Transport))
if err != nil {
panic(err)
}
}
}
// DefaultMaxIdleConnsPerHost is the default value of Transport's // DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost. // MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2 const DefaultMaxIdleConnsPerHost = 2
...@@ -138,12 +129,30 @@ type Transport struct { ...@@ -138,12 +129,30 @@ type Transport struct {
// called with the request's authority (such as "example.com" // called with the request's authority (such as "example.com"
// or "example.com:1234") and the TLS connection. The function // or "example.com:1234") and the TLS connection. The function
// must return a RoundTripper that then handles the request. // must return a RoundTripper that then handles the request.
// If TLSNextProto is nil, HTTP/2 support is enabled automatically.
TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
nextProtoOnce sync.Once // guards initialization of TLSNextProto (onceSetNextProtoDefaults)
// TODO: tunable on global max cached connections // TODO: tunable on global max cached connections
// TODO: tunable on timeout on cached connections // TODO: tunable on timeout on cached connections
} }
// onceSetNextProtoDefaults initializes TLSNextProto.
// It must be called via t.nextProtoOnce.Do.
func (t *Transport) onceSetNextProtoDefaults() {
if strings.Contains(os.Getenv("GODEBUG"), "h2client=0") {
return
}
if t.TLSNextProto != nil {
return
}
err := http2ConfigureTransport(t)
if err != nil {
log.Printf("Error enabling Transport HTTP/2 support: %v", err)
}
}
// ProxyFromEnvironment returns the URL of the proxy to use for a // ProxyFromEnvironment returns the URL of the proxy to use for a
// given request, as indicated by the environment variables // given request, as indicated by the environment variables
// HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the lowercase versions // HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the lowercase versions
...@@ -216,6 +225,7 @@ func (tr *transportRequest) extraHeaders() Header { ...@@ -216,6 +225,7 @@ func (tr *transportRequest) extraHeaders() Header {
// For higher-level HTTP client support (such as handling of cookies // For higher-level HTTP client support (such as handling of cookies
// and redirects), see Get, Post, and the Client type. // and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (*Response, error) { func (t *Transport) RoundTrip(req *Request) (*Response, error) {
t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
if req.URL == nil { if req.URL == nil {
req.closeBody() req.closeBody()
return nil, errors.New("http: nil Request.URL") return nil, errors.New("http: nil Request.URL")
......
...@@ -2921,6 +2921,27 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) { ...@@ -2921,6 +2921,27 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) {
} }
} }
func TestTransportAutomaticHTTP2(t *testing.T) {
tr := &Transport{}
_, err := tr.RoundTrip(new(Request))
if err == nil {
t.Error("expected error from RoundTrip")
}
if tr.TLSNextProto["h2"] == nil {
t.Errorf("HTTP/2 not registered.")
}
// Now with TLSNextProto set:
tr = &Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper)}
_, err = tr.RoundTrip(new(Request))
if err == nil {
t.Error("expected error from RoundTrip")
}
if tr.TLSNextProto["h2"] != nil {
t.Errorf("HTTP/2 registered, despite non-nil TLSNextProto field")
}
}
func wantBody(res *Response, err error, want string) error { func wantBody(res *Response, err error, want string) error {
if err != nil { if err != nil {
return err return err
......
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