@@ -100,7 +100,7 @@ type Transport struct {
100
100
idleLRU connLRU
101
101
102
102
reqMu sync.Mutex
103
- reqCanceler map [* Request ]func (error )
103
+ reqCanceler map [cancelKey ]func (error )
104
104
105
105
altMu sync.Mutex // guards changing altProto only
106
106
altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme
@@ -273,6 +273,13 @@ type Transport struct {
273
273
ForceAttemptHTTP2 bool
274
274
}
275
275
276
+ // A cancelKey is the key of the reqCanceler map.
277
+ // We wrap the *Request in this type since we want to use the original request,
278
+ // not any transient one created by roundTrip.
279
+ type cancelKey struct {
280
+ req * Request
281
+ }
282
+
276
283
func (t * Transport ) writeBufferSize () int {
277
284
if t .WriteBufferSize > 0 {
278
285
return t .WriteBufferSize
@@ -433,9 +440,10 @@ func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
433
440
// optional extra headers to write and stores any error to return
434
441
// from roundTrip.
435
442
type transportRequest struct {
436
- * Request // original request, not to be mutated
437
- extra Header // extra headers to write, or nil
438
- trace * httptrace.ClientTrace // optional
443
+ * Request // original request, not to be mutated
444
+ extra Header // extra headers to write, or nil
445
+ trace * httptrace.ClientTrace // optional
446
+ cancelKey cancelKey
439
447
440
448
mu sync.Mutex // guards err
441
449
err error // first setError value for mapRoundTripError to consider
@@ -512,6 +520,7 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
512
520
}
513
521
514
522
origReq := req
523
+ cancelKey := cancelKey {origReq }
515
524
req = setupRewindBody (req )
516
525
517
526
if altRT := t .alternateRoundTripper (req ); altRT != nil {
@@ -546,7 +555,7 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
546
555
}
547
556
548
557
// treq gets modified by roundTrip, so we need to recreate for each retry.
549
- treq := & transportRequest {Request : req , trace : trace }
558
+ treq := & transportRequest {Request : req , trace : trace , cancelKey : cancelKey }
550
559
cm , err := t .connectMethodForRequest (treq )
551
560
if err != nil {
552
561
req .closeBody ()
@@ -559,15 +568,15 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
559
568
// to send it requests.
560
569
pconn , err := t .getConn (treq , cm )
561
570
if err != nil {
562
- t .setReqCanceler (req , nil )
571
+ t .setReqCanceler (cancelKey , nil )
563
572
req .closeBody ()
564
573
return nil , err
565
574
}
566
575
567
576
var resp * Response
568
577
if pconn .alt != nil {
569
578
// HTTP/2 path.
570
- t .setReqCanceler (req , nil ) // not cancelable with CancelRequest
579
+ t .setReqCanceler (cancelKey , nil ) // not cancelable with CancelRequest
571
580
resp , err = pconn .alt .RoundTrip (req )
572
581
} else {
573
582
resp , err = pconn .roundTrip (treq )
@@ -756,14 +765,14 @@ func (t *Transport) CloseIdleConnections() {
756
765
// cancelable context instead. CancelRequest cannot cancel HTTP/2
757
766
// requests.
758
767
func (t * Transport ) CancelRequest (req * Request ) {
759
- t .cancelRequest (req , errRequestCanceled )
768
+ t .cancelRequest (cancelKey { req } , errRequestCanceled )
760
769
}
761
770
762
771
// Cancel an in-flight request, recording the error value.
763
- func (t * Transport ) cancelRequest (req * Request , err error ) {
772
+ func (t * Transport ) cancelRequest (key cancelKey , err error ) {
764
773
t .reqMu .Lock ()
765
- cancel := t .reqCanceler [req ]
766
- delete (t .reqCanceler , req )
774
+ cancel := t .reqCanceler [key ]
775
+ delete (t .reqCanceler , key )
767
776
t .reqMu .Unlock ()
768
777
if cancel != nil {
769
778
cancel (err )
@@ -1096,34 +1105,34 @@ func (t *Transport) removeIdleConnLocked(pconn *persistConn) bool {
1096
1105
return removed
1097
1106
}
1098
1107
1099
- func (t * Transport ) setReqCanceler (r * Request , fn func (error )) {
1108
+ func (t * Transport ) setReqCanceler (key cancelKey , fn func (error )) {
1100
1109
t .reqMu .Lock ()
1101
1110
defer t .reqMu .Unlock ()
1102
1111
if t .reqCanceler == nil {
1103
- t .reqCanceler = make (map [* Request ]func (error ))
1112
+ t .reqCanceler = make (map [cancelKey ]func (error ))
1104
1113
}
1105
1114
if fn != nil {
1106
- t .reqCanceler [r ] = fn
1115
+ t .reqCanceler [key ] = fn
1107
1116
} else {
1108
- delete (t .reqCanceler , r )
1117
+ delete (t .reqCanceler , key )
1109
1118
}
1110
1119
}
1111
1120
1112
1121
// replaceReqCanceler replaces an existing cancel function. If there is no cancel function
1113
1122
// for the request, we don't set the function and return false.
1114
1123
// Since CancelRequest will clear the canceler, we can use the return value to detect if
1115
1124
// the request was canceled since the last setReqCancel call.
1116
- func (t * Transport ) replaceReqCanceler (r * Request , fn func (error )) bool {
1125
+ func (t * Transport ) replaceReqCanceler (key cancelKey , fn func (error )) bool {
1117
1126
t .reqMu .Lock ()
1118
1127
defer t .reqMu .Unlock ()
1119
- _ , ok := t .reqCanceler [r ]
1128
+ _ , ok := t .reqCanceler [key ]
1120
1129
if ! ok {
1121
1130
return false
1122
1131
}
1123
1132
if fn != nil {
1124
- t .reqCanceler [r ] = fn
1133
+ t .reqCanceler [key ] = fn
1125
1134
} else {
1126
- delete (t .reqCanceler , r )
1135
+ delete (t .reqCanceler , key )
1127
1136
}
1128
1137
return true
1129
1138
}
@@ -1327,12 +1336,12 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi
1327
1336
// set request canceler to some non-nil function so we
1328
1337
// can detect whether it was cleared between now and when
1329
1338
// we enter roundTrip
1330
- t .setReqCanceler (req , func (error ) {})
1339
+ t .setReqCanceler (treq . cancelKey , func (error ) {})
1331
1340
return pc , nil
1332
1341
}
1333
1342
1334
1343
cancelc := make (chan error , 1 )
1335
- t .setReqCanceler (req , func (err error ) { cancelc <- err })
1344
+ t .setReqCanceler (treq . cancelKey , func (err error ) { cancelc <- err })
1336
1345
1337
1346
// Queue for permission to dial.
1338
1347
t .queueForDial (w )
@@ -2075,7 +2084,7 @@ func (pc *persistConn) readLoop() {
2075
2084
}
2076
2085
2077
2086
if ! hasBody || bodyWritable {
2078
- pc .t .setReqCanceler (rc .req , nil )
2087
+ pc .t .setReqCanceler (rc .cancelKey , nil )
2079
2088
2080
2089
// Put the idle conn back into the pool before we send the response
2081
2090
// so if they process it quickly and make another request, they'll
@@ -2148,7 +2157,7 @@ func (pc *persistConn) readLoop() {
2148
2157
// reading the response body. (or for cancellation or death)
2149
2158
select {
2150
2159
case bodyEOF := <- waitForBodyRead :
2151
- pc .t .setReqCanceler (rc .req , nil ) // before pc might return to idle pool
2160
+ pc .t .setReqCanceler (rc .cancelKey , nil ) // before pc might return to idle pool
2152
2161
alive = alive &&
2153
2162
bodyEOF &&
2154
2163
! pc .sawEOF &&
@@ -2162,7 +2171,7 @@ func (pc *persistConn) readLoop() {
2162
2171
pc .t .CancelRequest (rc .req )
2163
2172
case <- rc .req .Context ().Done ():
2164
2173
alive = false
2165
- pc .t .cancelRequest (rc .req , rc .req .Context ().Err ())
2174
+ pc .t .cancelRequest (rc .cancelKey , rc .req .Context ().Err ())
2166
2175
case <- pc .closech :
2167
2176
alive = false
2168
2177
}
@@ -2403,8 +2412,9 @@ type responseAndError struct {
2403
2412
}
2404
2413
2405
2414
type requestAndChan struct {
2406
- req * Request
2407
- ch chan responseAndError // unbuffered; always send in select on callerGone
2415
+ req * Request
2416
+ cancelKey cancelKey
2417
+ ch chan responseAndError // unbuffered; always send in select on callerGone
2408
2418
2409
2419
// whether the Transport (as opposed to the user client code)
2410
2420
// added the Accept-Encoding gzip header. If the Transport
@@ -2466,7 +2476,7 @@ var (
2466
2476
2467
2477
func (pc * persistConn ) roundTrip (req * transportRequest ) (resp * Response , err error ) {
2468
2478
testHookEnterRoundTrip ()
2469
- if ! pc .t .replaceReqCanceler (req .Request , pc .cancelRequest ) {
2479
+ if ! pc .t .replaceReqCanceler (req .cancelKey , pc .cancelRequest ) {
2470
2480
pc .t .putOrCloseIdleConn (pc )
2471
2481
return nil , errRequestCanceled
2472
2482
}
@@ -2518,7 +2528,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
2518
2528
2519
2529
defer func () {
2520
2530
if err != nil {
2521
- pc .t .setReqCanceler (req .Request , nil )
2531
+ pc .t .setReqCanceler (req .cancelKey , nil )
2522
2532
}
2523
2533
}()
2524
2534
@@ -2534,6 +2544,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
2534
2544
resc := make (chan responseAndError )
2535
2545
pc .reqch <- requestAndChan {
2536
2546
req : req .Request ,
2547
+ cancelKey : req .cancelKey ,
2537
2548
ch : resc ,
2538
2549
addedGzip : requestedGzip ,
2539
2550
continueCh : continueCh ,
@@ -2585,10 +2596,10 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
2585
2596
}
2586
2597
return re .res , nil
2587
2598
case <- cancelChan :
2588
- pc .t .CancelRequest (req .Request )
2599
+ pc .t .cancelRequest (req .cancelKey , errRequestCanceled )
2589
2600
cancelChan = nil
2590
2601
case <- ctxDoneChan :
2591
- pc .t .cancelRequest (req .Request , req .Context ().Err ())
2602
+ pc .t .cancelRequest (req .cancelKey , req .Context ().Err ())
2592
2603
cancelChan = nil
2593
2604
ctxDoneChan = nil
2594
2605
}
0 commit comments