Skip to content

Commit 1c60e0d

Browse files
fraenkeldmitshur
authored andcommitted
[release-branch.go1.15] net/http: add connections back that haven't been canceled
Issue #41600 fixed the issue when a second request canceled a connection while the first request was still in roundTrip. This uncovered a second issue where a request was being canceled (in roundtrip) but the connection was put back into the idle pool for a subsequent request. The fix is the similar except its now in readLoop instead of roundTrip. A persistent connection is only added back if it successfully removed the cancel function; otherwise we know the roundTrip has started cancelRequest. Fixes #42935. Updates #42942. Change-Id: Ia56add20880ccd0c1ab812d380d8628e45f6f44c Reviewed-on: https://go-review.googlesource.com/c/go/+/274973 Trust: Dmitri Shuralyov <[email protected]> Trust: Damien Neil <[email protected]> Reviewed-by: Damien Neil <[email protected]> (cherry picked from commit 854a2f8) Reviewed-on: https://go-review.googlesource.com/c/go/+/297910 Run-TryBot: Dmitri Shuralyov <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 5de8d3b commit 1c60e0d

File tree

1 file changed

+12
-10
lines changed

1 file changed

+12
-10
lines changed

src/net/http/transport.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -766,14 +766,17 @@ func (t *Transport) CancelRequest(req *Request) {
766766
}
767767

768768
// Cancel an in-flight request, recording the error value.
769-
func (t *Transport) cancelRequest(key cancelKey, err error) {
769+
// Returns whether the request was canceled.
770+
func (t *Transport) cancelRequest(key cancelKey, err error) bool {
770771
t.reqMu.Lock()
771772
cancel := t.reqCanceler[key]
772773
delete(t.reqCanceler, key)
773774
t.reqMu.Unlock()
774775
if cancel != nil {
775776
cancel(err)
776777
}
778+
779+
return cancel != nil
777780
}
778781

779782
//
@@ -2087,18 +2090,17 @@ func (pc *persistConn) readLoop() {
20872090
}
20882091

20892092
if !hasBody || bodyWritable {
2090-
pc.t.setReqCanceler(rc.cancelKey, nil)
2093+
replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil)
20912094

20922095
// Put the idle conn back into the pool before we send the response
20932096
// so if they process it quickly and make another request, they'll
20942097
// get this same conn. But we use the unbuffered channel 'rc'
20952098
// to guarantee that persistConn.roundTrip got out of its select
20962099
// potentially waiting for this persistConn to close.
2097-
// but after
20982100
alive = alive &&
20992101
!pc.sawEOF &&
21002102
pc.wroteRequest() &&
2101-
tryPutIdleConn(trace)
2103+
replaced && tryPutIdleConn(trace)
21022104

21032105
if bodyWritable {
21042106
closeErr = errCallerOwnsConn
@@ -2160,12 +2162,12 @@ func (pc *persistConn) readLoop() {
21602162
// reading the response body. (or for cancellation or death)
21612163
select {
21622164
case bodyEOF := <-waitForBodyRead:
2163-
pc.t.setReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool
2165+
replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool
21642166
alive = alive &&
21652167
bodyEOF &&
21662168
!pc.sawEOF &&
21672169
pc.wroteRequest() &&
2168-
tryPutIdleConn(trace)
2170+
replaced && tryPutIdleConn(trace)
21692171
if bodyEOF {
21702172
eofc <- struct{}{}
21712173
}
@@ -2561,6 +2563,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
25612563
cancelChan := req.Request.Cancel
25622564
ctxDoneChan := req.Context().Done()
25632565
pcClosed := pc.closech
2566+
canceled := false
25642567
for {
25652568
testHookWaitResLoop()
25662569
select {
@@ -2582,8 +2585,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
25822585
}
25832586
case <-pcClosed:
25842587
pcClosed = nil
2585-
// check if we are still using the connection
2586-
if pc.t.replaceReqCanceler(req.cancelKey, nil) {
2588+
if canceled || pc.t.replaceReqCanceler(req.cancelKey, nil) {
25872589
if debugRoundTrip {
25882590
req.logf("closech recv: %T %#v", pc.closed, pc.closed)
25892591
}
@@ -2607,10 +2609,10 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
26072609
}
26082610
return re.res, nil
26092611
case <-cancelChan:
2610-
pc.t.cancelRequest(req.cancelKey, errRequestCanceled)
2612+
canceled = pc.t.cancelRequest(req.cancelKey, errRequestCanceled)
26112613
cancelChan = nil
26122614
case <-ctxDoneChan:
2613-
pc.t.cancelRequest(req.cancelKey, req.Context().Err())
2615+
canceled = pc.t.cancelRequest(req.cancelKey, req.Context().Err())
26142616
cancelChan = nil
26152617
ctxDoneChan = nil
26162618
}

0 commit comments

Comments
 (0)