mirror of
https://github.com/golang/go
synced 2024-11-23 21:10:05 -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:
parent
875a6d4010
commit
3d7f836123
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user