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 }
121