Skip to content

Commit

Permalink
net/http: enable HTTP/2 on all Transports, not just the DefaultTransport
Browse files Browse the repository at this point in the history
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/17300
Reviewed-by: Ian Lance Taylor <[email protected]>
Run-TryBot: Brad Fitzpatrick <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
  • Loading branch information
bradfitz committed Dec 2, 2015
1 parent 3b3f422 commit 9bad995
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
28 changes: 19 additions & 9 deletions src/net/http/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,6 @@ var DefaultTransport RoundTripper = &Transport{
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
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2
Expand Down Expand Up @@ -138,12 +129,30 @@ type Transport struct {
// called with the request's authority (such as "example.com"
// or "example.com:1234") and the TLS connection. The function
// 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

nextProtoOnce sync.Once // guards initialization of TLSNextProto (onceSetNextProtoDefaults)

// TODO: tunable on global max 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
// given request, as indicated by the environment variables
// HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the lowercase versions
Expand Down Expand Up @@ -216,6 +225,7 @@ func (tr *transportRequest) extraHeaders() Header {
// For higher-level HTTP client support (such as handling of cookies
// and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
if req.URL == nil {
req.closeBody()
return nil, errors.New("http: nil Request.URL")
Expand Down
21 changes: 21 additions & 0 deletions src/net/http/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
if err != nil {
return err
Expand Down

0 comments on commit 9bad995

Please sign in to comment.