aboutsummaryrefslogtreecommitdiff
path: root/src/net/http
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2022-01-19 11:26:46 -0800
committerBryan Mills <bcmills@google.com>2022-02-14 17:30:31 +0000
commit3d7f83612390d913e7e8bb4ffa3dc69c41b3078d (patch)
tree4d914ceba53ad556a3c9ba004ff6b091599411e2 /src/net/http
parent875a6d40107d560473d1590425a096dd4cee346f (diff)
downloadgo-3d7f83612390d913e7e8bb4ffa3dc69c41b3078d.tar.xz
net/http: deflake request-not-written path
When we receive an error writing the first byte of a request to a reused connection, we retry the request on a new connection. Remove a flaky path which could cause the request to not be retried if persistConn.roundTrip reads the error caused by closing the connection before it reads the write error that caused the connection to be closed. Fixes #30938. Change-Id: Iafd99e3239cd9dba4a4c9ddd950a877ca9815e59 Reviewed-on: https://go-review.googlesource.com/c/go/+/379554 Trust: Bryan Mills <bcmills@google.com> Trust: Damien Neil <dneil@google.com> Reviewed-by: Russ Cox <rsc@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/net/http')
-rw-r--r--src/net/http/transport.go6
-rw-r--r--src/net/http/transport_internal_test.go9
2 files changed, 13 insertions, 2 deletions
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 5fe3e6ebb4..e41b20a15b 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -606,6 +606,9 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
} else if !pconn.shouldRetryRequest(req, err) {
// Issue 16465: return underlying net.Conn.Read error from peek,
// as we've historically done.
+ if e, ok := err.(nothingWrittenError); ok {
+ err = e.error
+ }
if e, ok := err.(transportReadFromServerError); ok {
err = e.err
}
@@ -2032,6 +2035,9 @@ func (pc *persistConn) mapRoundTripError(req *transportRequest, startBytesWritte
}
if _, ok := err.(transportReadFromServerError); ok {
+ if pc.nwrite == startBytesWritten {
+ return nothingWrittenError{err}
+ }
// Don't decorate
return err
}
diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go
index 1cce27235d..2ed637e9f0 100644
--- a/src/net/http/transport_internal_test.go
+++ b/src/net/http/transport_internal_test.go
@@ -52,8 +52,8 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
conn.Close() // simulate the server hanging up on the client
_, err = pc.roundTrip(treq)
- if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
- t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
+ if !isNothingWrittenError(err) && !isTransportReadFromServerError(err) && err != errServerClosedIdle {
+ t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle, transportReadFromServerError, or nothingWrittenError", err, err)
}
<-pc.closech
@@ -63,6 +63,11 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
}
}
+func isNothingWrittenError(err error) bool {
+ _, ok := err.(nothingWrittenError)
+ return ok
+}
+
func isTransportReadFromServerError(err error) bool {
_, ok := err.(transportReadFromServerError)
return ok