http2: consider buffered data when doing stream flow control
Fixes golang/go#15930
Change-Id: Ib5d2f57361d52364edb29df25ec9a498c3088781
Reviewed-on: https://go-review.googlesource.com/23812
Reviewed-by: Aaron Jacobs <jacobsa@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
diff --git a/http2/transport_test.go b/http2/transport_test.go
index 8f13ea4..631a04b 100644
--- a/http2/transport_test.go
+++ b/http2/transport_test.go
@@ -1956,3 +1956,58 @@
}
}
+
+// https://golang.org/issue/15930
+func TestTransportFlowControl(t *testing.T) {
+ const (
+ total = 100 << 20 // 100MB
+ bufLen = 1 << 16
+ )
+
+ var wrote int64 // updated atomically
+ st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
+ b := make([]byte, bufLen)
+ for wrote < total {
+ n, err := w.Write(b)
+ atomic.AddInt64(&wrote, int64(n))
+ if err != nil {
+ t.Errorf("ResponseWriter.Write error: %v", err)
+ break
+ }
+ w.(http.Flusher).Flush()
+ }
+ }, optOnlyServer)
+
+ tr := &Transport{TLSClientConfig: tlsConfigInsecure}
+ defer tr.CloseIdleConnections()
+ req, err := http.NewRequest("GET", st.ts.URL, nil)
+ if err != nil {
+ t.Fatal("NewRequest error:", err)
+ }
+ resp, err := tr.RoundTrip(req)
+ if err != nil {
+ t.Fatal("RoundTrip error:", err)
+ }
+ defer resp.Body.Close()
+
+ var read int64
+ b := make([]byte, bufLen)
+ for {
+ n, err := resp.Body.Read(b)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatal("Read error:", err)
+ }
+ read += int64(n)
+
+ const max = transportDefaultStreamFlow
+ if w := atomic.LoadInt64(&wrote); -max > read-w || read-w > max {
+ t.Fatalf("Too much data inflight: server wrote %v bytes but client only received %v", w, read)
+ }
+
+ // Let the server get ahead of the client.
+ time.Sleep(1 * time.Millisecond)
+ }
+}