diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 9b5ea52c9b..a298e2ef03 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -370,6 +370,13 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { } for { + select { + case <-ctx.Done(): + req.closeBody() + return nil, ctx.Err() + default: + } + // treq gets modified by roundTrip, so we need to recreate for each retry. treq := &transportRequest{Request: req, trace: trace} cm, err := t.connectMethodForRequest(treq) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 01a209c633..a02867a2d0 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -4544,3 +4544,28 @@ func TestNoBodyOnChunked304Response(t *testing.T) { type funcWriter func([]byte) (int, error) func (f funcWriter) Write(p []byte) (int, error) { return f(p) } + +type doneContext struct { + context.Context + err error +} + +func (doneContext) Done() <-chan struct{} { + c := make(chan struct{}) + close(c) + return c +} + +func (d doneContext) Err() error { return d.err } + +// Issue 25852: Transport should check whether Context is done early. +func TestTransportCheckContextDoneEarly(t *testing.T) { + tr := &Transport{} + req, _ := NewRequest("GET", "http://fake.example/", nil) + wantErr := errors.New("some error") + req = req.WithContext(doneContext{context.Background(), wantErr}) + _, err := tr.RoundTrip(req) + if err != wantErr { + t.Errorf("error = %v; want %v", err, wantErr) + } +}