Source File
flow.go
Belonging Package
net/http/internal/http2
// Copyright 2014 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Flow controlpackage http2// inflowMinRefresh is the minimum number of bytes we'll send for a// flow control window update.const inflowMinRefresh = 4 << 10// maxFlowWindow is the maximum size of a flow control window.const maxFlowWindow = (1 << 31) - 1// inflow accounts for an inbound flow control window.// It tracks both the latest window sent to the peer (used for enforcement)// and the accumulated unsent window.type inflow struct {avail int32unsent int32}// init sets the initial window.func ( *inflow) ( int32) {.avail =}// add adds n bytes to the window, with a maximum window size of max,// indicating that the peer can now send us more data.// For example, the user read from a {Request,Response} body and consumed// some of the buffered data, so the peer can now send more.// It returns the number of bytes to send in a WINDOW_UPDATE frame to the peer.// Window updates are accumulated and sent when the unsent capacity// is at least inflowMinRefresh or will at least double the peer's available window.func ( *inflow) ( int) ( int32) {if < 0 {panic("negative update")}:= int64(.unsent) + int64()// "A sender MUST NOT allow a flow-control window to exceed 2^31-1 octets."// RFC 7540 Section 6.9.1.const = 1<<31 - 1if +int64(.avail) > {panic("flow control update exceeds maximum window size")}.unsent = int32()if .unsent < inflowMinRefresh && .unsent < .avail {// If there aren't at least inflowMinRefresh bytes of window to send,// and this update won't at least double the window, buffer the update for later.return 0}.avail += .unsent.unsent = 0return int32()}// take attempts to take n bytes from the peer's flow control window.// It reports whether the window has available capacity.func ( *inflow) ( uint32) bool {if > uint32(.avail) {return false}.avail -= int32()return true}// takeInflows attempts to take n bytes from two inflows,// typically connection-level and stream-level flows.// It reports whether both windows have available capacity.func (, *inflow, uint32) bool {if > uint32(.avail) || > uint32(.avail) {return false}.avail -= int32().avail -= int32()return true}// connOutflow is connection-level outbound flow control.type connOutflow struct {initial int32 // SETTINGS_INITIAL_WINDOW_SIZE, changes with settings updatesn int32 // connection-level flow control windowflowErr bool // set when a flow control error is encountered}func ( *connOutflow) () {.initial = initialWindowSize // initial stream window size.n = initialWindowSize // current connection window size}func ( *connOutflow) ( int64) bool {if > maxFlowWindow {.flowErr = truereturn false}.initial = int32()return true}func ( *connOutflow) ( int32) bool {:= int64(.n) + int64()if > maxFlowWindow {.flowErr = truereturn false}.n +=return true}// outflow is the stream-level outbound flow control window's size.type outflow struct {_ incomparable// delta is the difference between the stream's flow control window and// the connection's initial window size (conn.initial).//// Another view is that delta is the number of flow control bytes provided to this// stream in WINDOW_UPDATE frames, less the number of bytes sent on the stream.delta int32// conn points to the shared connection-level outflow that is// shared by all streams on that conn.conn *connOutflow}func ( *outflow) () (int32, bool) {if .conn == nil {return maxFlowWindow, true // only happens in tests}if .conn.flowErr {// Block all sending once any stream observes a flow control error.return 0, false}:= int64(.conn.initial) + int64(.delta)if > maxFlowWindow {.conn.flowErr = truereturn 0, false}return min(int32(), .conn.n), true}func ( *outflow) ( int32) {if .conn == nil {return // only happens in tests}, := .available()if > {panic("internal error: took too much")}.delta -=.conn.n -=}// add adds n bytes (positive or negative) to the flow control window.// It returns false if the sum would exceed 2^31-1.func ( *outflow) ( int32) bool {if .conn == nil {return true // only happens in tests}:= int64(.conn.initial) + int64(.delta)if > maxFlowWindow {// An earlier change to the initial window pushed this stream over the limit.// This is a connection-level flow control error..conn.flowErr = truereturn false}if +int64() > maxFlowWindow {// This update would push the stream over the limit.// This is a stream-level flow control error.return false}.delta +=return true}
The pages are generated with Golds v0.8.4. (GOOS=linux GOARCH=amd64)