// setRequestCancel sets the Cancel field of req, if deadline is
// non-zero. The RoundTripper's type is used to determine whether the legacy
// CancelRequest behavior should be used.
+//
+// As background, there are three ways to cancel a request:
+// First was Transport.CancelRequest. (deprecated)
+// Second was Request.Cancel (this mechanism).
+// Third was Request.Context.
func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), didTimeout func() bool) {
if deadline.IsZero() {
return nop, alwaysFalse
req.Cancel = cancel
doCancel := func() {
- // The new way:
+ // The newer way (the second way in the func comment):
close(cancel)
// The legacy compatibility way, used only
// value.
select {
case <-req.Cancel:
+ // It was an error due to cancelation, so prioritize that
+ // error value. (Issue 16049)
+ return nil, errRequestCanceledConn
case <-req.Context().Done():
return nil, req.Context().Err()
case err := <-cancelc:
// return the original error message:
return nil, v.err
}
- // It was an error due to cancelation, so prioritize that
- // error value. (Issue 16049)
- return nil, errRequestCanceledConn
case pc := <-idleConnCh:
// Another request finished first and its net.Conn
// became available before our dial. Or somebody