From 3d7f83612390d913e7e8bb4ffa3dc69c41b3078d Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 19 Jan 2022 11:26:46 -0800 Subject: [PATCH] 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 Trust: Damien Neil Reviewed-by: Russ Cox Reviewed-by: Bryan Mills Run-TryBot: Bryan Mills TryBot-Result: Gopher Robot --- src/net/http/transport.go | 6 ++++++ src/net/http/transport_internal_test.go | 9 +++++++-- 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 -- 2.50.0