golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/http2/flow.go (about)

     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  // inflow accounts for an inbound flow control window.
    14  // It tracks both the latest window sent to the peer (used for enforcement)
    15  // and the accumulated unsent window.
    16  type inflow struct {
    17  	avail  int32
    18  	unsent int32
    19  }
    20  
    21  // init sets the initial window.
    22  func (f *inflow) init(n int32) {
    23  	f.avail = n
    24  }
    25  
    26  // add adds n bytes to the window, with a maximum window size of max,
    27  // indicating that the peer can now send us more data.
    28  // For example, the user read from a {Request,Response} body and consumed
    29  // some of the buffered data, so the peer can now send more.
    30  // It returns the number of bytes to send in a WINDOW_UPDATE frame to the peer.
    31  // Window updates are accumulated and sent when the unsent capacity
    32  // is at least inflowMinRefresh or will at least double the peer's available window.
    33  func (f *inflow) add(n int) (connAdd int32) {
    34  	if n < 0 {
    35  		panic("negative update")
    36  	}
    37  	unsent := int64(f.unsent) + int64(n)
    38  	// "A sender MUST NOT allow a flow-control window to exceed 2^31-1 octets."
    39  	// RFC 7540 Section 6.9.1.
    40  	const maxWindow = 1<<31 - 1
    41  	if unsent+int64(f.avail) > maxWindow {
    42  		panic("flow control update exceeds maximum window size")
    43  	}
    44  	f.unsent = int32(unsent)
    45  	if f.unsent < inflowMinRefresh && f.unsent < f.avail {
    46  		// If there aren't at least inflowMinRefresh bytes of window to send,
    47  		// and this update won't at least double the window, buffer the update for later.
    48  		return 0
    49  	}
    50  	f.avail += f.unsent
    51  	f.unsent = 0
    52  	return int32(unsent)
    53  }
    54  
    55  // take attempts to take n bytes from the peer's flow control window.
    56  // It reports whether the window has available capacity.
    57  func (f *inflow) take(n uint32) bool {
    58  	if n > uint32(f.avail) {
    59  		return false
    60  	}
    61  	f.avail -= int32(n)
    62  	return true
    63  }
    64  
    65  // takeInflows attempts to take n bytes from two inflows,
    66  // typically connection-level and stream-level flows.
    67  // It reports whether both windows have available capacity.
    68  func takeInflows(f1, f2 *inflow, n uint32) bool {
    69  	if n > uint32(f1.avail) || n > uint32(f2.avail) {
    70  		return false
    71  	}
    72  	f1.avail -= int32(n)
    73  	f2.avail -= int32(n)
    74  	return true
    75  }
    76  
    77  // outflow is the outbound flow control window's size.
    78  type outflow struct {
    79  	_ incomparable
    80  
    81  	// n is the number of DATA bytes we're allowed to send.
    82  	// An outflow is kept both on a conn and a per-stream.
    83  	n int32
    84  
    85  	// conn points to the shared connection-level outflow that is
    86  	// shared by all streams on that conn. It is nil for the outflow
    87  	// that's on the conn directly.
    88  	conn *outflow
    89  }
    90  
    91  func (f *outflow) setConnFlow(cf *outflow) { f.conn = cf }
    92  
    93  func (f *outflow) available() int32 {
    94  	n := f.n
    95  	if f.conn != nil && f.conn.n < n {
    96  		n = f.conn.n
    97  	}
    98  	return n
    99  }
   100  
   101  func (f *outflow) take(n int32) {
   102  	if n > f.available() {
   103  		panic("internal error: took too much")
   104  	}
   105  	f.n -= n
   106  	if f.conn != nil {
   107  		f.conn.n -= n
   108  	}
   109  }
   110  
   111  // add adds n bytes (positive or negative) to the flow control window.
   112  // It returns false if the sum would exceed 2^31-1.
   113  func (f *outflow) add(n int32) bool {
   114  	sum := f.n + n
   115  	if (sum > n) == (f.n > 0) {
   116  		f.n = sum
   117  		return true
   118  	}
   119  	return false
   120  }