|
|
@@ -20,6 +20,7 @@ import (
|
|
|
"net/url"
|
|
|
"os"
|
|
|
"reflect"
|
|
|
+ "runtime"
|
|
|
"sort"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
@@ -101,6 +102,7 @@ func TestTransport(t *testing.T) {
|
|
|
t.Errorf("Body = %q; want %q", slurp, body)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
func onSameConn(t *testing.T, modReq func(*http.Request)) bool {
|
|
|
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
io.WriteString(w, r.RemoteAddr)
|
|
|
@@ -1862,3 +1864,54 @@ func TestTransportReadHeadResponse(t *testing.T) {
|
|
|
}
|
|
|
ct.run()
|
|
|
}
|
|
|
+
|
|
|
+type neverEnding byte
|
|
|
+
|
|
|
+func (b neverEnding) Read(p []byte) (int, error) {
|
|
|
+ for i := range p {
|
|
|
+ p[i] = byte(b)
|
|
|
+ }
|
|
|
+ return len(p), nil
|
|
|
+}
|
|
|
+
|
|
|
+// golang.org/issue/15425: test that a handler closing the request
|
|
|
+// body doesn't terminate the stream to the peer. (It just stops
|
|
|
+// readability from the handler's side, and eventually the client
|
|
|
+// runs out of flow control tokens)
|
|
|
+func TestTransportHandlerBodyClose(t *testing.T) {
|
|
|
+ const bodySize = 10 << 20
|
|
|
+ st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
+ r.Body.Close()
|
|
|
+ io.Copy(w, io.LimitReader(neverEnding('A'), bodySize))
|
|
|
+ }, optOnlyServer)
|
|
|
+ defer st.Close()
|
|
|
+
|
|
|
+ tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
|
|
+ defer tr.CloseIdleConnections()
|
|
|
+
|
|
|
+ g0 := runtime.NumGoroutine()
|
|
|
+
|
|
|
+ const numReq = 10
|
|
|
+ for i := 0; i < numReq; i++ {
|
|
|
+ req, err := http.NewRequest("POST", st.ts.URL, struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)})
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ res, err := tr.RoundTrip(req)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ n, err := io.Copy(ioutil.Discard, res.Body)
|
|
|
+ res.Body.Close()
|
|
|
+ if n != bodySize || err != nil {
|
|
|
+ t.Fatalf("req#d: Copy = %d, %v; want %d, nil", i, n, err, bodySize)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tr.CloseIdleConnections()
|
|
|
+
|
|
|
+ gd := runtime.NumGoroutine() - g0
|
|
|
+ if gd > numReq/2 {
|
|
|
+ t.Errorf("appeared to leak goroutines")
|
|
|
+ }
|
|
|
+
|
|
|
+}
|