@@ -39,14 +39,17 @@ import (
3939)
4040
4141const  (
42- 	// transportDefaultConnFlow is how many connection-level flow control 
42+ 	// maxWriteFrameSize is the maximum possible frame size used to write to server. 
43+ 	maxWriteFrameSize  =  512  <<  10 
44+ 
45+ 	// defaultTransportDefaultConnFlow is how many connection-level flow control 
4346	// tokens we give the server at start-up, past the default 64k. 
44- 	transportDefaultConnFlow  =  1  <<  30 
47+ 	defaultTransportDefaultConnFlow  =  1  <<  30 
4548
46- 	// transportDefaultStreamFlow  is how many stream-level flow 
49+ 	// defaultTransportDefaultStreamFlow  is how many stream-level flow 
4750	// control tokens we announce to the peer, and how many bytes 
4851	// we buffer per stream. 
49- 	transportDefaultStreamFlow  =  4  <<  20 
52+ 	defaultTransportDefaultStreamFlow  =  4  <<  20 
5053
5154	defaultUserAgent  =  "Go-http-client/2.0" 
5255
@@ -124,6 +127,21 @@ type Transport struct {
124127	// Values are bounded in the range 16k to 16M. 
125128	MaxReadFrameSize  uint32 
126129
130+ 	// MaxWriteFrameSize is the maximum frame size that we can a client 
131+ 	// connection can send to a server, even if server advertises a higher value. 
132+ 	// If 0, then a default value is used. 
133+ 	MaxWriteFrameSize  uint32 
134+ 
135+ 	// MaxDownloadBufferPerConnection is the maximum per connection buffer size, 
136+ 	// used for receiving data from the server. 
137+ 	// If 0, then a default value is used. 
138+ 	MaxDownloadBufferPerConnection  uint32 
139+ 
140+ 	// MaxDownloadBufferPerStream is the maximum buffer to use for inflow data sent 
141+ 	// by the server. 
142+ 	// If 0, then a default value is used. 
143+ 	MaxDownloadBufferPerStream  uint32 
144+ 
127145	// MaxDecoderHeaderTableSize optionally specifies the http2 
128146	// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It 
129147	// informs the remote endpoint of the maximum size of the header compression 
@@ -304,6 +322,9 @@ type ClientConn struct {
304322	idleTimeout  time.Duration  // or 0 for never 
305323	idleTimer    * time.Timer 
306324
325+ 	maxWriteFrameSize           uint32 
326+ 	maxDownloadBufferPerStream  uint32 
327+ 
307328	mu               sync.Mutex  // guards following 
308329	cond             * sync.Cond  // hold mu; broadcast on flow/closed changes 
309330	flow             outflow     // our conn-level flow control quota (cs.outflow is per stream) 
@@ -731,25 +752,55 @@ func (t *Transport) maxEncoderHeaderTableSize() uint32 {
731752	return  initialHeaderTableSize 
732753}
733754
755+ func  (t  * Transport ) maxDownloadBufferPerConnection () uint32  {
756+ 	maxWindow  :=  uint32 ((2  <<  31 ) -  1  -  initialWindowSize )
757+ 
758+ 	if  v  :=  t .MaxDownloadBufferPerConnection ; v  >=  initialWindowSize  {
759+ 		if  v  >  maxWindow  {
760+ 			return  maxWindow 
761+ 		} else  {
762+ 			return  v 
763+ 		}
764+ 	}
765+ 
766+ 	return  defaultTransportDefaultConnFlow 
767+ }
768+ 
769+ func  (t  * Transport ) maxDownloadBufferPerStream () uint32  {
770+ 	if  v  :=  t .MaxDownloadBufferPerStream ; v  >  0  {
771+ 		return  v 
772+ 	}
773+ 	return  defaultTransportDefaultStreamFlow 
774+ }
775+ 
776+ func  (t  * Transport ) maxWriteFrameSize () uint32  {
777+ 	if  v  :=  t .MaxWriteFrameSize ; v  >  0  &&  v  <=  maxWriteFrameSize  {
778+ 		return  v 
779+ 	}
780+ 	return  maxWriteFrameSize 
781+ }
782+ 
734783func  (t  * Transport ) NewClientConn (c  net.Conn ) (* ClientConn , error ) {
735784	return  t .newClientConn (c , t .disableKeepAlives ())
736785}
737786
738787func  (t  * Transport ) newClientConn (c  net.Conn , singleUse  bool ) (* ClientConn , error ) {
739788	cc  :=  & ClientConn {
740- 		t :                     t ,
741- 		tconn :                 c ,
742- 		readerDone :            make (chan  struct {}),
743- 		nextStreamID :          1 ,
744- 		maxFrameSize :          16  <<  10 ,                    // spec default 
745- 		initialWindowSize :     65535 ,                       // spec default 
746- 		maxConcurrentStreams :  initialMaxConcurrentStreams , // "infinite", per spec. Use a smaller value until we have received server settings. 
747- 		peerMaxHeaderListSize : 0xffffffffffffffff ,          // "infinite", per spec. Use 2^64-1 instead. 
748- 		streams :               make (map [uint32 ]* clientStream ),
749- 		singleUse :             singleUse ,
750- 		wantSettingsAck :       true ,
751- 		pings :                 make (map [[8 ]byte ]chan  struct {}),
752- 		reqHeaderMu :           make (chan  struct {}, 1 ),
789+ 		t :                          t ,
790+ 		tconn :                      c ,
791+ 		readerDone :                 make (chan  struct {}),
792+ 		nextStreamID :               1 ,
793+ 		maxFrameSize :               16  <<  10 ,                    // spec default 
794+ 		initialWindowSize :          65535 ,                       // spec default 
795+ 		maxConcurrentStreams :       initialMaxConcurrentStreams , // "infinite", per spec. Use a smaller value until we have received server settings. 
796+ 		peerMaxHeaderListSize :      0xffffffffffffffff ,          // "infinite", per spec. Use 2^64-1 instead. 
797+ 		maxWriteFrameSize :          t .maxWriteFrameSize (),
798+ 		maxDownloadBufferPerStream : t .maxDownloadBufferPerStream (),
799+ 		streams :                    make (map [uint32 ]* clientStream ),
800+ 		singleUse :                  singleUse ,
801+ 		wantSettingsAck :            true ,
802+ 		pings :                      make (map [[8 ]byte ]chan  struct {}),
803+ 		reqHeaderMu :                make (chan  struct {}, 1 ),
753804	}
754805	if  d  :=  t .idleConnTimeout (); d  !=  0  {
755806		cc .idleTimeout  =  d 
@@ -796,7 +847,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
796847
797848	initialSettings  :=  []Setting {
798849		{ID : SettingEnablePush , Val : 0 },
799- 		{ID : SettingInitialWindowSize , Val : transportDefaultStreamFlow },
850+ 		{ID : SettingInitialWindowSize , Val : t . maxDownloadBufferPerStream () },
800851	}
801852	if  max  :=  t .maxFrameReadSize (); max  !=  0  {
802853		initialSettings  =  append (initialSettings , Setting {ID : SettingMaxFrameSize , Val : max })
@@ -810,8 +861,8 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
810861
811862	cc .bw .Write (clientPreface )
812863	cc .fr .WriteSettings (initialSettings ... )
813- 	cc .fr .WriteWindowUpdate (0 , transportDefaultConnFlow )
814- 	cc .inflow .init (transportDefaultConnFlow  +  initialWindowSize )
864+ 	cc .fr .WriteWindowUpdate (0 , t . maxDownloadBufferPerConnection () )
865+ 	cc .inflow .init (int32 ( t . maxDownloadBufferPerConnection ())  +  initialWindowSize )
815866	cc .bw .Flush ()
816867	if  cc .werr  !=  nil  {
817868		cc .Close ()
@@ -1660,12 +1711,12 @@ var (
16601711// outgoing request bodies to read/write to/from. 
16611712// 
16621713// It returns max(1, min(peer's advertised max frame size, 
1663- // Request.ContentLength+1, 512KB )). 
1714+ // Request.ContentLength+1, Transport.MaxWriteFrameSize )). 
16641715func  (cs  * clientStream ) frameScratchBufferLen (maxFrameSize  int ) int  {
1665- 	const   max  =  512   <<   10 
1716+ 	var   maxSize  =  int64 ( cs . cc . maxWriteFrameSize ) 
16661717	n  :=  int64 (maxFrameSize )
1667- 	if  n  >  max  {
1668- 		n  =  max 
1718+ 	if  n  >  maxSize  {
1719+ 		n  =  maxSize 
16691720	}
16701721	if  cl  :=  cs .reqBodyContentLength ; cl  !=  - 1  &&  cl + 1  <  n  {
16711722		// Add an extra byte past the declared content-length to 
@@ -2120,7 +2171,8 @@ type resAndError struct {
21202171func  (cc  * ClientConn ) addStreamLocked (cs  * clientStream ) {
21212172	cs .flow .add (int32 (cc .initialWindowSize ))
21222173	cs .flow .setConnFlow (& cc .flow )
2123- 	cs .inflow .init (transportDefaultStreamFlow )
2174+ 	// no need to truncate since max is maxWriteFrameSize 
2175+ 	cs .inflow .init (int32 (cc .maxDownloadBufferPerStream ))
21242176	cs .ID  =  cc .nextStreamID 
21252177	cc .nextStreamID  +=  2 
21262178	cc .streams [cs .ID ] =  cs 
0 commit comments