// HTTP, kingpin of dependencies.
"net/http": {
"L4", "NET", "OS",
- "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
+ "context", "compress/gzip", "crypto/tls",
+ "mime/multipart", "runtime/debug",
"net/http/internal",
"golang.org/x/net/http2/hpack",
},
import (
"bufio"
"bytes"
+ "context"
"crypto/tls"
"encoding/base64"
"errors"
// RoundTripper may support Cancel.
//
// For server requests, this field is not applicable.
+ //
+ // Deprecated: use the Context and WithContext methods
+ // instead. If a Request's Cancel field and context are both
+ // set, it is undefined whether Cancel is respected.
Cancel <-chan struct{}
+
+ // ctx is either the client or server context. It should only
+ // be modified via copying the whole Request using WithContext.
+ // It is unexported to prevent people from using Context wrong
+ // and mutating the contexts held by callers of the same request.
+ ctx context.Context
+}
+
+// Context returns the request's context. To change the context, use
+// WithContext.
+//
+// The returned context is always non-nil; it defaults to the
+// background context.
+func (r *Request) Context() context.Context {
+ // TODO(bradfitz): document above what Context means for server and client
+ // requests, once implemented.
+ if r.ctx != nil {
+ return r.ctx
+ }
+ return context.Background()
+}
+
+// WithContext returns a shallow copy of r with its context changed
+// to ctx. The provided ctx must be non-nil.
+func (r *Request) WithContext(ctx context.Context) *Request {
+ if ctx == nil {
+ panic("nil context")
+ }
+ r2 := new(Request)
+ *r2 = *r
+ r2.ctx = ctx
+ return r2
}
// ProtoAtLeast reports whether the HTTP protocol used
"compress/gzip"
"crypto/rand"
"fmt"
+ "go/ast"
"io"
"io/ioutil"
"net/http/internal"
t.Errorf("%s: type mismatch %v want %v", prefix, hv.Type(), wv.Type())
}
for i := 0; i < hv.NumField(); i++ {
+ name := hv.Type().Field(i).Name
+ if !ast.IsExported(name) {
+ continue
+ }
hf := hv.Field(i).Interface()
wf := wv.Field(i).Interface()
if !reflect.DeepEqual(hf, wf) {
- t.Errorf("%s: %s = %v want %v", prefix, hv.Type().Field(i).Name, hf, wf)
+ t.Errorf("%s: %s = %v want %v", prefix, name, hf, wf)
}
}
}
case <-req.Cancel:
handlePendingDial()
return nil, errRequestCanceledConn
+ case <-req.Context().Done():
+ handlePendingDial()
+ return nil, errRequestCanceledConn
case <-cancelc:
handlePendingDial()
return nil, errRequestCanceledConn
case <-rc.req.Cancel:
alive = false
pc.t.CancelRequest(rc.req)
+ case <-rc.req.Context().Done():
+ alive = false
+ pc.t.CancelRequest(rc.req)
case <-pc.closech:
alive = false
}
case <-cancelChan:
pc.t.CancelRequest(req.Request)
cancelChan = nil
+ case <-req.Context().Done():
+ pc.t.CancelRequest(req.Request)
+ cancelChan = nil
}
}
"bufio"
"bytes"
"compress/gzip"
+ "context"
"crypto/rand"
"crypto/tls"
"errors"
}
}
-func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
+func TestCancelRequestWithChannelBeforeDo_Cancel(t *testing.T) {
+ testCancelRequestWithChannelBeforeDo(t, false)
+}
+func TestCancelRequestWithChannelBeforeDo_Context(t *testing.T) {
+ testCancelRequestWithChannelBeforeDo(t, true)
+}
+func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) {
setParallel(t)
defer afterTest(t)
unblockc := make(chan bool)
c := &Client{Transport: tr}
req, _ := NewRequest("GET", ts.URL, nil)
- ch := make(chan struct{})
- req.Cancel = ch
- close(ch)
+ if withCtx {
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+ req = req.WithContext(ctx)
+ } else {
+ ch := make(chan struct{})
+ req.Cancel = ch
+ close(ch)
+ }
_, err := c.Do(req)
if err == nil || !strings.Contains(err.Error(), "canceled") {