Source file src/net/http/internal/http2/flow.go

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Flow control
     6  
     7  package http2
     8  
     9  // inflowMinRefresh is the minimum number of bytes we'll send for a
    10  // flow control window update.
    11  const inflowMinRefresh = 4 << 10
    12  
    13  // maxFlowWindow is the maximum size of a flow control window.
    14  const maxFlowWindow = (1 << 31) - 1
    15  
    16  // inflow accounts for an inbound flow control window.
    17  // It tracks both the latest window sent to the peer (used for enforcement)
    18  // and the accumulated unsent window.
    19  type inflow struct {
    20  	avail  int32
    21  	unsent int32
    22  }
    23  
    24  // init sets the initial window.
    25  func (f *inflow) init(n int32) {
    26  	f.avail = n
    27  }
    28  
    29  // add adds n bytes to the window, with a maximum window size of max,
    30  // indicating that the peer can now send us more data.
    31  // For example, the user read from a {Request,Response} body and consumed
    32  // some of the buffered data, so the peer can now send more.
    33  // It returns the number of bytes to send in a WINDOW_UPDATE frame to the peer.
    34  // Window updates are accumulated and sent when the unsent capacity
    35  // is at least inflowMinRefresh or will at least double the peer's available window.
    36  func (f *inflow) add(n int) (connAdd int32) {
    37  	if n < 0 {
    38  		panic("negative update")
    39  	}
    40  	unsent := int64(f.unsent) + int64(n)
    41  	// "A sender MUST NOT allow a flow-control window to exceed 2^31-1 octets."
    42  	// RFC 7540 Section 6.9.1.
    43  	const maxWindow = 1<<31 - 1
    44  	if unsent+int64(f.avail) > maxWindow {
    45  		panic("flow control update exceeds maximum window size")
    46  	}
    47  	f.unsent = int32(unsent)
    48  	if f.unsent < inflowMinRefresh && f.unsent < f.avail {
    49  		// If there aren't at least inflowMinRefresh bytes of window to send,
    50  		// and this update won't at least double the window, buffer the update for later.
    51  		return 0
    52  	}
    53  	f.avail += f.unsent
    54  	f.unsent = 0
    55  	return int32(unsent)
    56  }
    57  
    58  // take attempts to take n bytes from the peer's flow control window.
    59  // It reports whether the window has available capacity.
    60  func (f *inflow) take(n uint32) bool {
    61  	if n > uint32(f.avail) {
    62  		return false
    63  	}
    64  	f.avail -= int32(n)
    65  	return true
    66  }
    67  
    68  // takeInflows attempts to take n bytes from two inflows,
    69  // typically connection-level and stream-level flows.
    70  // It reports whether both windows have available capacity.
    71  func takeInflows(f1, f2 *inflow, n uint32) bool {
    72  	if n > uint32(f1.avail) || n > uint32(f2.avail) {
    73  		return false
    74  	}
    75  	f1.avail -= int32(n)
    76  	f2.avail -= int32(n)
    77  	return true
    78  }
    79  
    80  // connOutflow is connection-level outbound flow control.
    81  type connOutflow struct {
    82  	initial int32 // SETTINGS_INITIAL_WINDOW_SIZE, changes with settings updates
    83  	n       int32 // connection-level flow control window
    84  	flowErr bool  // set when a flow control error is encountered
    85  }
    86  
    87  func (f *connOutflow) init() {
    88  	f.initial = initialWindowSize // initial stream window size
    89  	f.n = initialWindowSize       // current connection window size
    90  }
    91  
    92  func (f *connOutflow) changeInitialWindowSize(size int64) bool {
    93  	if size > maxFlowWindow {
    94  		f.flowErr = true
    95  		return false
    96  	}
    97  	f.initial = int32(size)
    98  	return true
    99  }
   100  
   101  func (f *connOutflow) add(n int32) bool {
   102  	sum := int64(f.n) + int64(n)
   103  	if sum > maxFlowWindow {
   104  		f.flowErr = true
   105  		return false
   106  	}
   107  	f.n += n
   108  	return true
   109  }
   110  
   111  // outflow is the stream-level outbound flow control window's size.
   112  type outflow struct {
   113  	_ incomparable
   114  
   115  	// delta is the difference between the stream's flow control window and
   116  	// the connection's initial window size (conn.initial).
   117  	//
   118  	// Another view is that delta is the number of flow control bytes provided to this
   119  	// stream in WINDOW_UPDATE frames, less the number of bytes sent on the stream.
   120  	delta int32
   121  
   122  	// conn points to the shared connection-level outflow that is
   123  	// shared by all streams on that conn.
   124  	conn *connOutflow
   125  }
   126  
   127  func (f *outflow) available() (int32, bool) {
   128  	if f.conn == nil {
   129  		return maxFlowWindow, true // only happens in tests
   130  	}
   131  	if f.conn.flowErr {
   132  		// Block all sending once any stream observes a flow control error.
   133  		return 0, false
   134  	}
   135  	n := int64(f.conn.initial) + int64(f.delta)
   136  	if n > maxFlowWindow {
   137  		f.conn.flowErr = true
   138  		return 0, false
   139  	}
   140  	return min(int32(n), f.conn.n), true
   141  }
   142  
   143  func (f *outflow) take(n int32) {
   144  	if f.conn == nil {
   145  		return // only happens in tests
   146  	}
   147  	avail, _ := f.available()
   148  	if n > avail {
   149  		panic("internal error: took too much")
   150  	}
   151  	f.delta -= n
   152  	f.conn.n -= n
   153  }
   154  
   155  // add adds n bytes (positive or negative) to the flow control window.
   156  // It returns false if the sum would exceed 2^31-1.
   157  func (f *outflow) add(n int32) bool {
   158  	if f.conn == nil {
   159  		return true // only happens in tests
   160  	}
   161  	avail := int64(f.conn.initial) + int64(f.delta)
   162  	if avail > maxFlowWindow {
   163  		// An earlier change to the initial window pushed this stream over the limit.
   164  		// This is a connection-level flow control error.
   165  		f.conn.flowErr = true
   166  		return false
   167  	}
   168  	if avail+int64(n) > maxFlowWindow {
   169  		// This update would push the stream over the limit.
   170  		// This is a stream-level flow control error.
   171  		return false
   172  	}
   173  	f.delta += n
   174  	return true
   175  }
   176  

View as plain text