git » go-net » commit 8a52c78

http2: fix Transport.CloseIdleConnections when http1+http2 are wired together

author Brad Fitzpatrick
2016-05-19 20:36:08 UTC
committer Brad Fitzpatrick
2016-05-20 03:00:43 UTC
parent 202ff482f7a92ad9c562839c5c1e6b3842efaa69

http2: fix Transport.CloseIdleConnections when http1+http2 are wired together

Go 1.6+ wires up its http.Transport values to http2 with ConfigureTransport.
ConfigureTransport sets the connection pool to a "noDialClientConnPool"
type. But the Transport.CloseIdleConnections implementation was specifically
looking for a concrete type. Look for an interface instead.

Updates golang/go#14607 (needs bundle into the main repo before fix)

Change-Id: I6ad23b6facab5d3c2cbe71a1809a52794375d803
Reviewed-on: https://go-review.googlesource.com/23258
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>

http2/client_conn_pool.go +21 -0
http2/configure_transport.go +0 -9
http2/transport.go +1 -1

diff --git a/http2/client_conn_pool.go b/http2/client_conn_pool.go
index 772ea5e..8cb3eaa 100644
--- a/http2/client_conn_pool.go
+++ b/http2/client_conn_pool.go
@@ -18,6 +18,18 @@ type ClientConnPool interface {
 	MarkDead(*ClientConn)
 }
 
+// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
+// implementations which can close their idle connections.
+type clientConnPoolIdleCloser interface {
+	ClientConnPool
+	closeIdleConnections()
+}
+
+var (
+	_ clientConnPoolIdleCloser = (*clientConnPool)(nil)
+	_ clientConnPoolIdleCloser = noDialClientConnPool{}
+)
+
 // TODO: use singleflight for dialing and addConnCalls?
 type clientConnPool struct {
 	t *Transport
@@ -223,3 +235,12 @@ func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
 	}
 	return out
 }
+
+// noDialClientConnPool is an implementation of http2.ClientConnPool
+// which never dials.  We let the HTTP/1.1 client dial and use its TLS
+// connection instead.
+type noDialClientConnPool struct{ *clientConnPool }
+
+func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
+	return p.getClientConn(req, addr, noDialOnMiss)
+}
diff --git a/http2/configure_transport.go b/http2/configure_transport.go
index daa17f5..d87ba0f 100644
--- a/http2/configure_transport.go
+++ b/http2/configure_transport.go
@@ -67,15 +67,6 @@ func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error)
 	return nil
 }
 
-// noDialClientConnPool is an implementation of http2.ClientConnPool
-// which never dials.  We let the HTTP/1.1 client dial and use its TLS
-// connection instead.
-type noDialClientConnPool struct{ *clientConnPool }
-
-func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
-	return p.getClientConn(req, addr, noDialOnMiss)
-}
-
 // noDialH2RoundTripper is a RoundTripper which only tries to complete the request
 // if there's already has a cached connection to the host.
 type noDialH2RoundTripper struct{ t *Transport }
diff --git a/http2/transport.go b/http2/transport.go
index 03712d5..b666e37 100644
--- a/http2/transport.go
+++ b/http2/transport.go
@@ -310,7 +310,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
 // connected from previous requests but are now sitting idle.
 // It does not interrupt any connections currently in use.
 func (t *Transport) CloseIdleConnections() {
-	if cp, ok := t.connPool().(*clientConnPool); ok {
+	if cp, ok := t.connPool().(clientConnPoolIdleCloser); ok {
 		cp.closeIdleConnections()
 	}
 }