@@ -2374,59 +2374,68 @@ func testTransportStreamEndsWhileBodyIsBeingWritten(t testing.TB) {
2374
2374
rt .wantStatus (413 )
2375
2375
}
2376
2376
2377
- // https://golang.org/issue/15930
2378
- func TestTransportFlowControl (t * testing.T ) {
2379
- const bufLen = 64 << 10
2380
- var total int64 = 100 << 20 // 100MB
2381
- if testing .Short () {
2382
- total = 10 << 20
2383
- }
2384
-
2385
- var wrote int64 // updated atomically
2386
- ts := newTestServer (t , func (w http.ResponseWriter , r * http.Request ) {
2387
- b := make ([]byte , bufLen )
2388
- for wrote < total {
2389
- n , err := w .Write (b )
2390
- atomic .AddInt64 (& wrote , int64 (n ))
2391
- if err != nil {
2392
- t .Errorf ("ResponseWriter.Write error: %v" , err )
2393
- break
2394
- }
2395
- w .(http.Flusher ).Flush ()
2377
+ func TestTransportFlowControl (t * testing.T ) { synctestTest (t , testTransportFlowControl ) }
2378
+ func testTransportFlowControl (t testing.TB ) {
2379
+ const maxBuffer = 64 << 10 // 64KiB
2380
+ tc := newTestClientConn (t , func (tr * http.Transport ) {
2381
+ tr .HTTP2 = & http.HTTP2Config {
2382
+ MaxReceiveBufferPerConnection : maxBuffer ,
2383
+ MaxReceiveBufferPerStream : maxBuffer ,
2384
+ MaxReadFrameSize : 16 << 20 , // 16MiB
2396
2385
}
2397
2386
})
2387
+ tc .greet ()
2398
2388
2399
- tr := & Transport {TLSClientConfig : tlsConfigInsecure }
2400
- defer tr .CloseIdleConnections ()
2401
- req , err := http .NewRequest ("GET" , ts .URL , nil )
2402
- if err != nil {
2403
- t .Fatal ("NewRequest error:" , err )
2404
- }
2405
- resp , err := tr .RoundTrip (req )
2406
- if err != nil {
2407
- t .Fatal ("RoundTrip error:" , err )
2408
- }
2409
- defer resp .Body .Close ()
2389
+ req , _ := http .NewRequest ("GET" , "https://dummy.tld/" , nil )
2390
+ rt := tc .roundTrip (req )
2391
+ tc .wantFrameType (FrameHeaders )
2392
+
2393
+ tc .writeHeaders (HeadersFrameParam {
2394
+ StreamID : rt .streamID (),
2395
+ EndHeaders : true ,
2396
+ EndStream : false ,
2397
+ BlockFragment : tc .makeHeaderBlockFragment (
2398
+ ":status" , "200" ,
2399
+ ),
2400
+ })
2401
+ rt .wantStatus (200 )
2410
2402
2411
- var read int64
2412
- b := make ([]byte , bufLen )
2403
+ // Server fills up its transmit buffer.
2404
+ // The client does not provide more flow control tokens,
2405
+ // since the data hasn't been consumed by the user.
2406
+ tc .writeData (rt .streamID (), false , make ([]byte , maxBuffer ))
2407
+ tc .wantIdle ()
2408
+
2409
+ // User reads data from the response body.
2410
+ // The client sends more flow control tokens.
2411
+ resp := rt .response ()
2412
+ if _ , err := io .ReadFull (resp .Body , make ([]byte , maxBuffer )); err != nil {
2413
+ t .Fatalf ("io.Body.Read: %v" , err )
2414
+ }
2415
+ var connTokens , streamTokens uint32
2413
2416
for {
2414
- n , err := resp . Body . Read ( b )
2415
- if err == io . EOF {
2417
+ f := tc . readFrame ( )
2418
+ if f == nil {
2416
2419
break
2417
2420
}
2418
- if err != nil {
2419
- t .Fatal ("Read error:" , err )
2421
+ wu , ok := f .(* WindowUpdateFrame )
2422
+ if ! ok {
2423
+ t .Fatalf ("received unexpected frame %T (want WINDOW_UPDATE)" , f )
2420
2424
}
2421
- read += int64 (n )
2422
-
2423
- const max = transportDefaultStreamFlow
2424
- if w := atomic .LoadInt64 (& wrote ); - max > read - w || read - w > max {
2425
- t .Fatalf ("Too much data inflight: server wrote %v bytes but client only received %v" , w , read )
2425
+ switch wu .StreamID {
2426
+ case 0 :
2427
+ connTokens += wu .Increment
2428
+ case wu .StreamID :
2429
+ streamTokens += wu .Increment
2430
+ default :
2431
+ t .Fatalf ("received unexpected WINDOW_UPDATE for stream %v" , wu .StreamID )
2426
2432
}
2427
-
2428
- // Let the server get ahead of the client.
2429
- time .Sleep (1 * time .Millisecond )
2433
+ }
2434
+ if got , want := connTokens , uint32 (maxBuffer ); got != want {
2435
+ t .Errorf ("transport provided %v bytes of connection WINDOW_UPDATE, want %v" , got , want )
2436
+ }
2437
+ if got , want := streamTokens , uint32 (maxBuffer ); got != want {
2438
+ t .Errorf ("transport provided %v bytes of stream WINDOW_UPDATE, want %v" , got , want )
2430
2439
}
2431
2440
}
2432
2441
0 commit comments