|
|
@@ -2690,3 +2690,58 @@ func TestClientConnPing(t *testing.T) {
|
|
|
t.Fatal(err)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// Issue 16974: if the server sent a DATA frame after the user
|
|
|
+// canceled the Transport's Request, the Transport previously wrote to a
|
|
|
+// closed pipe, got an error, and ended up closing the whole TCP
|
|
|
+// connection.
|
|
|
+func TestTransportCancelDataResponseRace(t *testing.T) {
|
|
|
+ cancel := make(chan struct{})
|
|
|
+ clientGotError := make(chan bool, 1)
|
|
|
+
|
|
|
+ const msg = "Hello."
|
|
|
+ st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ if strings.Contains(r.URL.Path, "/hello") {
|
|
|
+ time.Sleep(50 * time.Millisecond)
|
|
|
+ io.WriteString(w, msg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for i := 0; i < 50; i++ {
|
|
|
+ io.WriteString(w, "Some data.")
|
|
|
+ w.(http.Flusher).Flush()
|
|
|
+ if i == 2 {
|
|
|
+ close(cancel)
|
|
|
+ <-clientGotError
|
|
|
+ }
|
|
|
+ time.Sleep(10 * time.Millisecond)
|
|
|
+ }
|
|
|
+ }, optOnlyServer)
|
|
|
+ defer st.Close()
|
|
|
+
|
|
|
+ tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
|
|
+ defer tr.CloseIdleConnections()
|
|
|
+
|
|
|
+ c := &http.Client{Transport: tr}
|
|
|
+ req, _ := http.NewRequest("GET", st.ts.URL, nil)
|
|
|
+ req.Cancel = cancel
|
|
|
+ res, err := c.Do(req)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if _, err = io.Copy(ioutil.Discard, res.Body); err == nil {
|
|
|
+ t.Fatal("unexpected success")
|
|
|
+ }
|
|
|
+ clientGotError <- true
|
|
|
+
|
|
|
+ res, err = c.Get(st.ts.URL + "/hello")
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ slurp, err := ioutil.ReadAll(res.Body)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if string(slurp) != msg {
|
|
|
+ t.Errorf("Got = %q; want %q", slurp, msg)
|
|
|
+ }
|
|
|
+}
|