Skip to content

Instantly share code, notes, and snippets.

@DanielMorsing
Created April 20, 2015 12:31
Show Gist options
  • Save DanielMorsing/b5facf9acd75aee5ab3b to your computer and use it in GitHub Desktop.
Save DanielMorsing/b5facf9acd75aee5ab3b to your computer and use it in GitHub Desktop.
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 354b5c0..0ec5398 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -358,6 +358,7 @@ func (cm *connectMethod) proxyAuth() string {
// If pconn is no longer needed or not in a good state, putIdleConn
// returns false.
func (t *Transport) putIdleConn(pconn *persistConn) bool {
+ fmt.Println("putidle")
if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
pconn.close()
return false
@@ -462,6 +463,7 @@ func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) {
}
func (t *Transport) setReqCanceler(r *Request, fn func()) {
+ fmt.Println("setcancel", fn == nil)
t.reqMu.Lock()
defer t.reqMu.Unlock()
if t.reqCanceler == nil {
@@ -820,6 +822,7 @@ func (pc *persistConn) isBroken() bool {
}
func (pc *persistConn) cancelRequest() {
+ fmt.Println("canceled")
pc.conn.Close()
}
@@ -909,7 +912,11 @@ func (pc *persistConn) readLoop() {
}
resp.Body.(*bodyEOFSignal).fn = func(err error) {
isEOF := err == nil
+ fmt.Println(err)
+ fmt.Println("sleeeep")
+ time.Sleep(500 * time.Millisecond)
waitForBodyRead <- isEOF
+ fmt.Println("done sleeping")
if isEOF {
<-eofc // see comment at top
}
@@ -938,9 +945,10 @@ func (pc *persistConn) readLoop() {
!pc.sawEOF &&
pc.wroteRequest() &&
pc.t.putIdleConn(pc)
+ fmt.Println(alive)
if bodyEOF {
eofc <- struct{}{}
- }
+ }
case <-pc.closech:
alive = false
}
@@ -951,6 +959,7 @@ func (pc *persistConn) readLoop() {
pc.wroteRequest() &&
pc.t.putIdleConn(pc)
}
+ time.Sleep(500 * time.Millisecond)
}
pc.close()
}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index b56defd..b22cc42 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -2321,6 +2321,51 @@ func TestTransportResponseCloseRace(t *testing.T) {
}
}
+func TestTransportResponseCancelRace(t *testing.T) {
+ defer afterTest(t)
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ // important that this response has a body.
+ var b [1024]byte
+ w.Write(b[:])
+ }))
+ defer ts.Close()
+ tr := &Transport{}
+ req, err := NewRequest("GET", ts.URL, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ fmt.Println("first request")
+ resp, err := tr.RoundTrip(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // If we do an early close, Transport just throws the connection away and
+ // doesn't reuse it. In order to trigger the bug, it has to reuse the connection
+ // so read the body
+ go func() {
+ err = resp.Write(ioutil.Discard)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+ time.Sleep(200 * time.Millisecond)
+ req2, err := NewRequest("GET", ts.URL, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tr.CancelRequest(req)
+ time.Sleep(500 * time.Millisecond)
+ fmt.Println("second request")
+ resp, err = tr.RoundTrip(req2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ resp.Body.Close()
+ time.Sleep(1 * time.Second)
+}
+
+
func wantBody(res *http.Response, err error, want string) error {
if err != nil {
return err
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment