]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: enable HTTP/2 on all Transports, not just the DefaultTransport
authorBrad Fitzpatrick <bradfitz@golang.org>
Tue, 1 Dec 2015 19:19:55 +0000 (19:19 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 2 Dec 2015 02:03:19 +0000 (02:03 +0000)
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 <iant@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/http/transport.go
src/net/http/transport_test.go

index 5ba072007f850c98ff30b15376027f3c9a64df26..1cd5d84574968094c6688a128d33f488df9263f6 100644 (file)
@@ -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
@@ -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
@@ -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")
index eaed3a484d1b3c126c300a4ca7b3352020c3c07d..e5c8501e19086be9bd49ab95ecfed903cc2930c0 100644 (file)
@@ -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