From: Emmanuel T Odeke Date: Sat, 12 Oct 2019 00:27:33 +0000 (-0400) Subject: net/http: fix and lock-in Client.Do docs on request cancelation X-Git-Tag: go1.14beta1~754 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=19e0799ba049bf26e770d150d4c296f247e1de5c;p=gostls13.git net/http: fix and lock-in Client.Do docs on request cancelation Fixes the docs to correctly match the implementation and also adds a test locking-in the behavior to prevent any accidental future regressions on the docs. Fixes #33545 Change-Id: I6fdac6048cce8ac99beaa2db0dfc81d0dccc10f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/200798 Run-TryBot: Emmanuel Odeke TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/net/http/client.go b/src/net/http/client.go index 9566b8940e..6a8c59a670 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -434,8 +434,8 @@ func Get(url string) (resp *Response, err error) { // An error is returned if the Client's CheckRedirect function fails // or if there was an HTTP protocol error. A non-2xx response doesn't // cause an error. Any returned error will be of type *url.Error. The -// url.Error value's Timeout method will report true if request timed -// out or was canceled. +// url.Error value's Timeout method will report true if the request +// timed out. // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 37c0390a73..2b4f53f802 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -1936,3 +1936,58 @@ func TestClientPropagatesTimeoutToContext(t *testing.T) { } c.Get("https://example.tld/") } + +func TestClientDoCanceledVsTimeout_h1(t *testing.T) { + testClientDoCanceledVsTimeout(t, h1Mode) +} + +func TestClientDoCanceledVsTimeout_h2(t *testing.T) { + testClientDoCanceledVsTimeout(t, h2Mode) +} + +// Issue 33545: lock-in the behavior promised by Client.Do's +// docs about request cancelation vs timing out. +func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) { + defer afterTest(t) + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + w.Write([]byte("Hello, World!")) + })) + defer cst.close() + + cases := []string{"timeout", "canceled"} + + for _, name := range cases { + t.Run(name, func(t *testing.T) { + var ctx context.Context + var cancel func() + if name == "timeout" { + ctx, cancel = context.WithTimeout(context.Background(), -time.Nanosecond) + } else { + ctx, cancel = context.WithCancel(context.Background()) + cancel() + } + defer cancel() + + req, _ := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil) + _, err := cst.c.Do(req) + if err == nil { + t.Fatal("Unexpectedly got a nil error") + } + + ue := err.(*url.Error) + + var wantIsTimeout bool + var wantErr error = context.Canceled + if name == "timeout" { + wantErr = context.DeadlineExceeded + wantIsTimeout = true + } + if g, w := ue.Timeout(), wantIsTimeout; g != w { + t.Fatalf("url.Timeout() = %t, want %t", g, w) + } + if g, w := ue.Err, wantErr; g != w { + t.Errorf("url.Error.Err = %v; want %v", g, w) + } + }) + } +}