1
0
mirror of https://github.com/golang/go synced 2024-11-07 10:26:20 -07:00

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>
This commit is contained in:
Damien Neil 2022-01-19 11:26:46 -08:00 committed by Bryan Mills
parent 875a6d4010
commit 3d7f836123
2 changed files with 13 additions and 2 deletions

View File

@ -606,6 +606,9 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
} else if !pconn.shouldRetryRequest(req, err) { } else if !pconn.shouldRetryRequest(req, err) {
// Issue 16465: return underlying net.Conn.Read error from peek, // Issue 16465: return underlying net.Conn.Read error from peek,
// as we've historically done. // as we've historically done.
if e, ok := err.(nothingWrittenError); ok {
err = e.error
}
if e, ok := err.(transportReadFromServerError); ok { if e, ok := err.(transportReadFromServerError); ok {
err = e.err err = e.err
} }
@ -2032,6 +2035,9 @@ func (pc *persistConn) mapRoundTripError(req *transportRequest, startBytesWritte
} }
if _, ok := err.(transportReadFromServerError); ok { if _, ok := err.(transportReadFromServerError); ok {
if pc.nwrite == startBytesWritten {
return nothingWrittenError{err}
}
// Don't decorate // Don't decorate
return err return err
} }

View File

@ -52,8 +52,8 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
conn.Close() // simulate the server hanging up on the client conn.Close() // simulate the server hanging up on the client
_, err = pc.roundTrip(treq) _, err = pc.roundTrip(treq)
if !isTransportReadFromServerError(err) && err != errServerClosedIdle { if !isNothingWrittenError(err) && !isTransportReadFromServerError(err) && err != errServerClosedIdle {
t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err) t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle, transportReadFromServerError, or nothingWrittenError", err, err)
} }
<-pc.closech <-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 { func isTransportReadFromServerError(err error) bool {
_, ok := err.(transportReadFromServerError) _, ok := err.(transportReadFromServerError)
return ok return ok