Created
April 20, 2015 12:31
-
-
Save DanielMorsing/b5facf9acd75aee5ab3b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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