Repository: go
Issue: net/http: client doesn't check for canceled context (delegates it to the Transport)
Labels: NeedsInvestigation

### What version of Go are you using (`go version`)?

<pre>
go version go1.15.6 linux/amd64

</pre>

### Does this issue reproduce with the latest release?
Yes. Also on go1.16.4


### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
linux amd64

</pre></details>

### What did you do?
```go
package golanghttpbug

import (
	"bytes"
	"context"
	"io/ioutil"
	"net/http"
	"testing"
)

type roundTripperFunc func(req *http.Request) (*http.Response, error)

func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
	return f(r)
}

func createClient(checkCtx bool) *http.Client {
	return &http.Client{
		Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
			resp := &http.Response{
				Body:   ioutil.NopCloser(bytes.NewReader([]byte("a response"))),
				Header: http.Header{},
			}
			if checkCtx && req.Context().Err() != nil {
				return resp, http.ErrHandlerTimeout
			}
			return resp, nil
		}),
	}
}

func TestRequest(t *testing.T) {
	canceledCtx, cancel := context.WithCancel(context.Background())
	cancel()
	tests := []struct {
		name    string
		client  *http.Client
		wantErr bool
	}{
		{
			name:   "default transport handles canceld context",
			client: http.DefaultClient,
		},
		{
			name:    "http package itself doesn't check for canceled context",
			client:  createClient(false),
			wantErr: true,
		},
		{
			name:   "undocumented: custom transport might receive an already canceled context",
			client: createClient(true),
		},
	}

	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			req, err := http.NewRequestWithContext(canceledCtx, http.MethodGet, "https://www.google.com/", http.NoBody)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			resp, err := tt.client.Do(req)
			if err == nil {
				t.Errorf("request not canceled: %v", err)
			}
			if resp != nil {
				defer resp.Body.Close()
				raw, err := ioutil.ReadAll(resp.Body)
				if err == nil {
					t.Logf("response len: %v\n", len(raw))
					t.Fatalf("request body readable: %v", err)
				}
			}
		})
	}
}

```



### What did you expect to see?
Wanted all tests to pass


### What did you see instead?
undocumented behavior.

There is [commit](https://github.com/golang/go/commit/19e0799ba049bf26e770d150d4c296f247e1de5c#diff-0e7b219d80d4a852e1fa733dea8eae46646e4f214fb0835317b73c5afd1e6e19) that has added a test for another issue. But as it spawns a server, it doesn't see the problem when using custom transport.

The request context is [checked here](https://github.com/golang/go/blob/b1aff42900133e4fbc9b7d7c1af13c77e4f647b0/src/net/http/client.go#L300) but it only checks for deadline and not cancelations.

Also as must people use the DefaultTransport this bug does not show itself. But it is an undocumented behavior which either needs to be fixed(which is an easy task) or it must be documented that a `RoundTripper` must handle this.