Skip to content

Commit f22dd66

Browse files
committed
net/http: make Transport.CloseIdleConnections close non-bundled http2.Transport
Previously Transport.CloseIdleConnections only closed the HTTP/2 Transport's idle connections if the HTTP/2 transport was configured automatically via the bundled copy (in h2_bundle.go). This makes it also work if the user called http2.ConfigureTransport themselves using golang.org/x/net/http2 instead of the bundled copy. No tests because we have no current way to run such cross-repo tests, at least in any efficient or non-flaky way. Tested by hand that: package main import ( "net/http" "golang.org/x/net/http2" ) func main() { tr := &http.Transport{} http2.ConfigureTransport(tr) tr.CloseIdleConnections() } ... now works and calls the x/net/http2.Transport.CloseIdleConnections code. (I threw in a print statement locally) Fixes #22891 once CL 123656 is also in. Change-Id: Id697fd3e7877c3a988bc3c3368b88940ba56cfd0 Reviewed-on: https://go-review.googlesource.com/123657 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent b888a62 commit f22dd66

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

src/net/http/export_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func (t *Transport) IdleConnStrsForTesting() []string {
117117

118118
func (t *Transport) IdleConnStrsForTesting_h2() []string {
119119
var ret []string
120-
noDialPool := t.h2transport.ConnPool.(http2noDialClientConnPool)
120+
noDialPool := t.h2transport.(*http2Transport).ConnPool.(http2noDialClientConnPool)
121121
pool := noDialPool.http2clientConnPool
122122

123123
pool.mu.Lock()

src/net/http/transport.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"net/textproto"
2525
"net/url"
2626
"os"
27+
"reflect"
2728
"strings"
2829
"sync"
2930
"sync/atomic"
@@ -255,7 +256,17 @@ type Transport struct {
255256
// nextProtoOnce guards initialization of TLSNextProto and
256257
// h2transport (via onceSetNextProtoDefaults)
257258
nextProtoOnce sync.Once
258-
h2transport *http2Transport // non-nil if http2 wired up
259+
h2transport h2Transport // non-nil if http2 wired up
260+
}
261+
262+
// h2Transport is the interface we expect to be able to call from
263+
// net/http against an *http2.Transport that's either bundled into
264+
// h2_bundle.go or supplied by the user via x/net/http2.
265+
//
266+
// We name it with the "h2" prefix to stay out of the "http2" prefix
267+
// namespace used by x/tools/cmd/bundle for h2_bundle.go.
268+
type h2Transport interface {
269+
CloseIdleConnections()
259270
}
260271

261272
// onceSetNextProtoDefaults initializes TLSNextProto.
@@ -264,6 +275,21 @@ func (t *Transport) onceSetNextProtoDefaults() {
264275
if strings.Contains(os.Getenv("GODEBUG"), "http2client=0") {
265276
return
266277
}
278+
279+
// If they've already configured http2 with
280+
// golang.org/x/net/http2 instead of the bundled copy, try to
281+
// get at its http2.Transport value (via the the "https"
282+
// altproto map) so we can call CloseIdleConnections on it if
283+
// requested. (Issue 22891)
284+
altProto, _ := t.altProto.Load().(map[string]RoundTripper)
285+
if rv := reflect.ValueOf(altProto["https"]); rv.IsValid() && rv.Type().Kind() == reflect.Struct && rv.Type().NumField() == 1 {
286+
if v := rv.Field(0); v.CanInterface() {
287+
if h2i, ok := v.Interface().(h2Transport); ok {
288+
t.h2transport = h2i
289+
}
290+
}
291+
}
292+
267293
if t.TLSNextProto != nil {
268294
// This is the documented way to disable http2 on a
269295
// Transport.

0 commit comments

Comments
 (0)