-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #26013 Change-Id: I2c82bd90ea7ce6f7a8e5b6c460d3982dca681a93 Reviewed-on: https://go-review.googlesource.com/c/go/+/174597 Reviewed-by: Andrew Bonventre <andybons@golang.org>
- Loading branch information
Showing
2 changed files
with
90 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -261,13 +261,14 @@ type Transport struct { | |
|
||
// ReadBufferSize specifies the size of the read buffer used | ||
// when reading from the transport. | ||
//If zero, a default (currently 4KB) is used. | ||
// If zero, a default (currently 4KB) is used. | ||
ReadBufferSize int | ||
|
||
// nextProtoOnce guards initialization of TLSNextProto and | ||
// h2transport (via onceSetNextProtoDefaults) | ||
nextProtoOnce sync.Once | ||
h2transport h2Transport // non-nil if http2 wired up | ||
nextProtoOnce sync.Once | ||
h2transport h2Transport // non-nil if http2 wired up | ||
tlsNextProtoWasNil bool // whether TLSNextProto was nil when the Once fired | ||
|
||
// ForceAttemptHTTP2 controls whether HTTP/2 is enabled when a non-zero | ||
// TLSClientConfig or Dial, DialTLS or DialContext func is provided. By default, use of any those fields conservatively | ||
|
@@ -290,6 +291,40 @@ func (t *Transport) readBufferSize() int { | |
return 4 << 10 | ||
} | ||
|
||
// Clone returns a deep copy of t's exported fields. | ||
func (t *Transport) Clone() *Transport { | ||
t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
bradfitz
Author
Contributor
|
||
t2 := &Transport{ | ||
Proxy: t.Proxy, | ||
DialContext: t.DialContext, | ||
Dial: t.Dial, | ||
DialTLS: t.DialTLS, | ||
TLSClientConfig: t.TLSClientConfig.Clone(), | ||
TLSHandshakeTimeout: t.TLSHandshakeTimeout, | ||
DisableKeepAlives: t.DisableKeepAlives, | ||
DisableCompression: t.DisableCompression, | ||
MaxIdleConns: t.MaxIdleConns, | ||
MaxIdleConnsPerHost: t.MaxIdleConnsPerHost, | ||
MaxConnsPerHost: t.MaxConnsPerHost, | ||
IdleConnTimeout: t.IdleConnTimeout, | ||
ResponseHeaderTimeout: t.ResponseHeaderTimeout, | ||
ExpectContinueTimeout: t.ExpectContinueTimeout, | ||
ProxyConnectHeader: t.ProxyConnectHeader.Clone(), | ||
MaxResponseHeaderBytes: t.MaxResponseHeaderBytes, | ||
ForceAttemptHTTP2: t.ForceAttemptHTTP2, | ||
WriteBufferSize: t.WriteBufferSize, | ||
ReadBufferSize: t.ReadBufferSize, | ||
} | ||
if !t.tlsNextProtoWasNil { | ||
npm := map[string]func(authority string, c *tls.Conn) RoundTripper{} | ||
for k, v := range t.TLSNextProto { | ||
npm[k] = v | ||
} | ||
t2.TLSNextProto = npm | ||
} | ||
return t2 | ||
} | ||
|
||
// h2Transport is the interface we expect to be able to call from | ||
// net/http against an *http2.Transport that's either bundled into | ||
// h2_bundle.go or supplied by the user via x/net/http2. | ||
|
@@ -303,6 +338,7 @@ type h2Transport interface { | |
// onceSetNextProtoDefaults initializes TLSNextProto. | ||
// It must be called via t.nextProtoOnce.Do. | ||
func (t *Transport) onceSetNextProtoDefaults() { | ||
t.tlsNextProtoWasNil = (t.TLSNextProto == nil) | ||
if strings.Contains(os.Getenv("GODEBUG"), "http2client=0") { | ||
return | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This line will cause the auto-generated
TLSClientConfig
of the oldTransport
to be cloned into the new one, further leading to unexpected behavior.For example, the old
Transport
has some auto-generatedTLSClientConfig
for HTTP/2, then it's cloned, the new one has the sameTLSClientConfig
value as the old one. Later, user decides to change theTLSNextProto
field of the new one to an empty map in order to disable HTTP/2 on the new one, but theTLSClientConfig
field of the new one won't adapt to the newTLSNextProto
value neither now nor in the future because it's designed to be one-shot initialized, then mistakes happen.Please fix it~ Thank you for your hard work! @bradfitz