You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
net/http.persistConn.readLoop: If the response has no body, putIdleConn will be called immediately so another request can reuse the persistConn, then setReqCanceler(rc.req, nil) is called.
The problem is: If persistConn is reused by another-request and CancelRequest(old-request) is called before setReqCanceler(old-request, nil), the another-request will failed.
if alive && !hasBody {
alive = !pc.sawEOF &&
pc.wroteRequest() &&
pc.t.putIdleConn(pc) // !!!!! 'pc' can be reused after function called.
}
rc.ch <- responseAndError{resp, err}
// Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader.
if waitForBodyRead != nil {
select {
case alive = <-waitForBodyRead:
case <-pc.closech:
alive = false
}
}
pc.t.setReqCanceler(rc.req, nil) // !!!!! CancelRequest may be invoked before function called
if !alive {
pc.close()
}
Reproduce, client will print "Get http://localhost:12345: net/http: transport closed before response was received"
diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index b1cc632..de3d15f 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -860,6 +860,8 @@ func (pc *persistConn) readLoop() {
pc.t.putIdleConn(pc)
}
+ time.Sleep(10e9) // to simulate an delayed schedule(for easy reproduce)
+
rc.ch <- responseAndError{resp, err}
// Wait for the just-returned response body to be fully consumed
// server
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
var i int
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
i++
if i > 1 {
time.Sleep(5e9)
}
})
err := http.ListenAndServe(":12345", nil)
fmt.Println("ListenAndServer", err)
}
// client
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
tr := &http.Transport{}
client := &http.Client{
Transport: tr,
}
done := make(chan error, 1)
requestCanceled, _ := http.NewRequest("GET", "http://localhost:12345", nil)
requestIrrelevant, _ := http.NewRequest("GET", "http://localhost:12345", nil)
go func() {
time.Sleep(2e9) // waiting for requestToBeCanceled to be responsed
go func() {
time.Sleep(2e9) // waiting for requestIrrelevant to reuse the tcp connection
tr.CancelRequest(requestCanceled)
}()
_, err := client.Do(requestIrrelevant)
done <- err
}()
client.Do(requestCanceled)
errIrrelevant := <-done
if errIrrelevant != nil {
fmt.Println(errIrrelevant)
}
}
The text was updated successfully, but these errors were encountered:
The text was updated successfully, but these errors were encountered: