aboutsummaryrefslogtreecommitdiff
path: root/src/net/http/transport_test.go
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2019-10-18 20:45:33 +0000
committerBrad Fitzpatrick <bradfitz@golang.org>2019-10-22 19:46:38 +0000
commit88186e5e232625f9c91d639e0cb90a88c6cf1172 (patch)
tree8a5740838cf560f9a95b9d5c0353a1542c611a16 /src/net/http/transport_test.go
parent03fb1f607b54b0c14b6e4ca04b569ec47dd127f9 (diff)
downloadgo-88186e5e232625f9c91d639e0cb90a88c6cf1172.tar.gz
go-88186e5e232625f9c91d639e0cb90a88c6cf1172.zip
net/http: don't cache http2.erringRoundTripper connections
Fixes #34978 Change-Id: I3baf1392ba7366ae6628889c47c343ef702ec438 Reviewed-on: https://go-review.googlesource.com/c/go/+/202078 Reviewed-by: Bryan C. Mills <bcmills@google.com> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/net/http/transport_test.go')
-rw-r--r--src/net/http/transport_test.go75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index c84d3ea1d6..f76530b8fa 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -5814,3 +5814,78 @@ func TestTransportClosesBodyOnInvalidRequests(t *testing.T) {
})
}
}
+
+// breakableConn is a net.Conn wrapper with a Write method
+// that will fail when its brokenState is true.
+type breakableConn struct {
+ net.Conn
+ *brokenState
+}
+
+type brokenState struct {
+ sync.Mutex
+ broken bool
+}
+
+func (w *breakableConn) Write(b []byte) (n int, err error) {
+ w.Lock()
+ defer w.Unlock()
+ if w.broken {
+ return 0, errors.New("some write error")
+ }
+ return w.Conn.Write(b)
+}
+
+// Issue 34978: don't cache a broken HTTP/2 connection
+func TestDontCacheBrokenHTTP2Conn(t *testing.T) {
+ cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {}), optQuietLog)
+ defer cst.close()
+
+ var brokenState brokenState
+
+ cst.tr.Dial = func(netw, addr string) (net.Conn, error) {
+ c, err := net.Dial(netw, addr)
+ if err != nil {
+ t.Errorf("unexpected Dial error: %v", err)
+ return nil, err
+ }
+ return &breakableConn{c, &brokenState}, err
+ }
+
+ const numReqs = 5
+ var gotConns uint32 // atomic
+ for i := 1; i <= numReqs; i++ {
+ brokenState.Lock()
+ brokenState.broken = false
+ brokenState.Unlock()
+
+ // doBreak controls whether we break the TCP connection after the TLS
+ // handshake (before the HTTP/2 handshake). We test a few failures
+ // in a row followed by a final success.
+ doBreak := i != numReqs
+
+ ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
+ GotConn: func(info httptrace.GotConnInfo) {
+ atomic.AddUint32(&gotConns, 1)
+ },
+ TLSHandshakeDone: func(cfg tls.ConnectionState, err error) {
+ brokenState.Lock()
+ defer brokenState.Unlock()
+ if doBreak {
+ brokenState.broken = true
+ }
+ },
+ })
+ req, err := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = cst.c.Do(req)
+ if doBreak != (err != nil) {
+ t.Errorf("for iteration %d, doBreak=%v; unexpected error %v", i, doBreak, err)
+ }
+ }
+ if got, want := atomic.LoadUint32(&gotConns), 1; int(got) != want {
+ t.Errorf("GotConn calls = %v; want %v", got, want)
+ }
+}