mirror of https://github.com/golang/go.git
net/http: make timeout errors match context.DeadlineExceeded
When returning an error which implements net.Error and reports itself as a timeout, also report it as matching context.DeadlineExceeded. This matches the behavior of timeout errors in the net package and elsewhere. Fixes #50856 Change-Id: I2ca911e3677a699af27ba89b1200401baa8b3b1b Reviewed-on: https://go-review.googlesource.com/c/go/+/567537 Reviewed-by: Jonathan Amsterdam <jba@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
b6753baaed
commit
606b8ff5ef
|
|
@ -725,10 +725,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
|
|||
// c.send() always closes req.Body
|
||||
reqBodyClosed = true
|
||||
if !deadline.IsZero() && didTimeout() {
|
||||
err = &httpError{
|
||||
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
|
||||
timeout: true,
|
||||
}
|
||||
err = &timeoutError{err.Error() + " (Client.Timeout exceeded while awaiting headers)"}
|
||||
}
|
||||
return nil, uerr(err)
|
||||
}
|
||||
|
|
@ -968,10 +965,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
|
|||
return n, err
|
||||
}
|
||||
if b.reqDidTimeout() {
|
||||
err = &httpError{
|
||||
err: err.Error() + " (Client.Timeout or context cancellation while reading body)",
|
||||
timeout: true,
|
||||
}
|
||||
err = &timeoutError{err.Error() + " (Client.Timeout or context cancellation while reading body)"}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1249,6 +1249,9 @@ func testClientTimeout(t *testing.T, mode testMode) {
|
|||
} else if !ne.Timeout() {
|
||||
t.Errorf("net.Error.Timeout = false; want true")
|
||||
}
|
||||
if !errors.Is(err, context.DeadlineExceeded) {
|
||||
t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err)
|
||||
}
|
||||
if got := ne.Error(); !strings.Contains(got, "(Client.Timeout") {
|
||||
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") {
|
||||
testenv.SkipFlaky(t, 43120)
|
||||
|
|
@ -1292,6 +1295,9 @@ func testClientTimeout_Headers(t *testing.T, mode testMode) {
|
|||
if !ne.Timeout() {
|
||||
t.Error("net.Error.Timeout = false; want true")
|
||||
}
|
||||
if !errors.Is(err, context.DeadlineExceeded) {
|
||||
t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err)
|
||||
}
|
||||
if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
|
||||
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") {
|
||||
testenv.SkipFlaky(t, 43120)
|
||||
|
|
@ -1992,6 +1998,9 @@ func testClientDoCanceledVsTimeout(t *testing.T, mode testMode) {
|
|||
if g, w := ue.Err, wantErr; g != w {
|
||||
t.Errorf("url.Error.Err = %v; want %v", g, w)
|
||||
}
|
||||
if got := errors.Is(err, context.DeadlineExceeded); got != wantIsTimeout {
|
||||
t.Errorf("errors.Is(err, context.DeadlineExceeded) = %v, want %v", got, wantIsTimeout)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2557,16 +2557,18 @@ type writeRequest struct {
|
|||
continueCh <-chan struct{}
|
||||
}
|
||||
|
||||
type httpError struct {
|
||||
err string
|
||||
timeout bool
|
||||
// httpTimeoutError represents a timeout.
|
||||
// It implements net.Error and wraps context.DeadlineExceeded.
|
||||
type timeoutError struct {
|
||||
err string
|
||||
}
|
||||
|
||||
func (e *httpError) Error() string { return e.err }
|
||||
func (e *httpError) Timeout() bool { return e.timeout }
|
||||
func (e *httpError) Temporary() bool { return true }
|
||||
func (e *timeoutError) Error() string { return e.err }
|
||||
func (e *timeoutError) Timeout() bool { return true }
|
||||
func (e *timeoutError) Temporary() bool { return true }
|
||||
func (e *timeoutError) Is(err error) bool { return err == context.DeadlineExceeded }
|
||||
|
||||
var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
|
||||
var errTimeout error = &timeoutError{"net/http: timeout awaiting response headers"}
|
||||
|
||||
// errRequestCanceled is set to be identical to the one from h2 to facilitate
|
||||
// testing.
|
||||
|
|
|
|||
Loading…
Reference in New Issue