Skip to content

Commit 606b8ff

Browse files
committed
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent b6753ba commit 606b8ff

File tree

3 files changed

+20
-15
lines changed

3 files changed

+20
-15
lines changed

src/net/http/client.go

+2-8
Original file line numberDiff line numberDiff line change
@@ -725,10 +725,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
725725
// c.send() always closes req.Body
726726
reqBodyClosed = true
727727
if !deadline.IsZero() && didTimeout() {
728-
err = &httpError{
729-
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
730-
timeout: true,
731-
}
728+
err = &timeoutError{err.Error() + " (Client.Timeout exceeded while awaiting headers)"}
732729
}
733730
return nil, uerr(err)
734731
}
@@ -968,10 +965,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
968965
return n, err
969966
}
970967
if b.reqDidTimeout() {
971-
err = &httpError{
972-
err: err.Error() + " (Client.Timeout or context cancellation while reading body)",
973-
timeout: true,
974-
}
968+
err = &timeoutError{err.Error() + " (Client.Timeout or context cancellation while reading body)"}
975969
}
976970
return n, err
977971
}

src/net/http/client_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,9 @@ func testClientTimeout(t *testing.T, mode testMode) {
12491249
} else if !ne.Timeout() {
12501250
t.Errorf("net.Error.Timeout = false; want true")
12511251
}
1252+
if !errors.Is(err, context.DeadlineExceeded) {
1253+
t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err)
1254+
}
12521255
if got := ne.Error(); !strings.Contains(got, "(Client.Timeout") {
12531256
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") {
12541257
testenv.SkipFlaky(t, 43120)
@@ -1292,6 +1295,9 @@ func testClientTimeout_Headers(t *testing.T, mode testMode) {
12921295
if !ne.Timeout() {
12931296
t.Error("net.Error.Timeout = false; want true")
12941297
}
1298+
if !errors.Is(err, context.DeadlineExceeded) {
1299+
t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err)
1300+
}
12951301
if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
12961302
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") {
12971303
testenv.SkipFlaky(t, 43120)
@@ -1992,6 +1998,9 @@ func testClientDoCanceledVsTimeout(t *testing.T, mode testMode) {
19921998
if g, w := ue.Err, wantErr; g != w {
19931999
t.Errorf("url.Error.Err = %v; want %v", g, w)
19942000
}
2001+
if got := errors.Is(err, context.DeadlineExceeded); got != wantIsTimeout {
2002+
t.Errorf("errors.Is(err, context.DeadlineExceeded) = %v, want %v", got, wantIsTimeout)
2003+
}
19952004
})
19962005
}
19972006
}

src/net/http/transport.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -2557,16 +2557,18 @@ type writeRequest struct {
25572557
continueCh <-chan struct{}
25582558
}
25592559

2560-
type httpError struct {
2561-
err string
2562-
timeout bool
2560+
// httpTimeoutError represents a timeout.
2561+
// It implements net.Error and wraps context.DeadlineExceeded.
2562+
type timeoutError struct {
2563+
err string
25632564
}
25642565

2565-
func (e *httpError) Error() string { return e.err }
2566-
func (e *httpError) Timeout() bool { return e.timeout }
2567-
func (e *httpError) Temporary() bool { return true }
2566+
func (e *timeoutError) Error() string { return e.err }
2567+
func (e *timeoutError) Timeout() bool { return true }
2568+
func (e *timeoutError) Temporary() bool { return true }
2569+
func (e *timeoutError) Is(err error) bool { return err == context.DeadlineExceeded }
25682570

2569-
var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
2571+
var errTimeout error = &timeoutError{"net/http: timeout awaiting response headers"}
25702572

25712573
// errRequestCanceled is set to be identical to the one from h2 to facilitate
25722574
// testing.

0 commit comments

Comments
 (0)