http2: calculate a correct window increment size for a stream

CL 432038 reduces sending WindowUpdates by introducing a threshold. Once
the remaining bytes are below the threshold, a single WindowUpdate is
sent to reset the amount back to the maximum amount configured.

The window increment size for a stream is calculated from:

    sc.srv.initialStreamRecvWindowSize() - st.inflow.available()

Where (*flow).available is defined as:

    func (f *flow) available() int32 {
    	n := f.n
    	if f.conn != nil && f.conn.n < n {
    		n = f.conn.n
    	}
    	return n
    }

When f.conn.c < f.n, it gets a bigger increment size. It should be
calculated from:

    sc.srv.initialStreamRecvWindowSize() - st.inflow.n

While we're here, remove an unnecessary type conversion too.

Updates golang/go#56315.

Change-Id: I4b26b27e4c5c5cd66e6a32b152d68f304adc65d8
GitHub-Last-Rev: 02fc09c1e7
GitHub-Pull-Request: golang/net#155
Reviewed-on: https://go-review.googlesource.com/c/net/+/444816
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
This commit is contained in:
Zeke Lu
2022-10-27 02:15:54 +00:00
committed by Gopher Robot
parent 84c13af5f4
commit 0c1aede73a
2 changed files with 42 additions and 4 deletions

View File

@@ -2336,13 +2336,13 @@ func (sc *serverConn) sendWindowUpdate(st *stream) {
var n int32
if st == nil {
if avail, windowSize := sc.inflow.available(), sc.srv.initialConnRecvWindowSize(); avail > windowSize/2 {
if avail, windowSize := sc.inflow.n, sc.srv.initialConnRecvWindowSize(); avail > windowSize/2 {
return
} else {
n = windowSize - avail
}
} else {
if avail, windowSize := st.inflow.available(), sc.srv.initialStreamRecvWindowSize(); avail > windowSize/2 {
if avail, windowSize := st.inflow.n, sc.srv.initialStreamRecvWindowSize(); avail > windowSize/2 {
return
} else {
n = windowSize - avail
@@ -2358,7 +2358,7 @@ func (sc *serverConn) sendWindowUpdate(st *stream) {
sc.sendWindowUpdate32(st, maxUint31)
n -= maxUint31
}
sc.sendWindowUpdate32(st, int32(n))
sc.sendWindowUpdate32(st, n)
}
// st may be nil for conn-level

View File

@@ -315,7 +315,7 @@ func (st *serverTester) greetAndCheckSettings(checkSetting func(s Setting) error
if f.FrameHeader.StreamID != 0 {
st.t.Fatalf("WindowUpdate StreamID = %d; want 0", f.FrameHeader.StreamID)
}
incr := uint32((&Server{}).initialConnRecvWindowSize() - initialWindowSize)
incr := uint32(st.sc.srv.initialConnRecvWindowSize() - initialWindowSize)
if f.Increment != incr {
st.t.Fatalf("WindowUpdate increment = %d; want %d", f.Increment, incr)
}
@@ -1326,6 +1326,44 @@ func TestServer_Handler_Sends_WindowUpdate_Padding(t *testing.T) {
puppet.do(readBodyHandler(t, "def"))
}
// This is a regression test to make sure the correct window increment size is
// calculated for a stream.
// See https://go.dev/issue/56315#issuecomment-1287642591.
func TestServer_Handler_Sends_WindowUpdate_IncrementSize(t *testing.T) {
maxSizePerConn := initialWindowSize * 2
maxSizePerStream := maxSizePerConn*2 + 100
puppet := newHandlerPuppet()
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
puppet.act(w, r)
}, func(s *Server) {
s.MaxUploadBufferPerConnection = int32(maxSizePerConn)
s.MaxUploadBufferPerStream = int32(maxSizePerStream)
})
defer st.Close()
defer puppet.done()
st.greet()
st.writeHeaders(HeadersFrameParam{
StreamID: 1,
BlockFragment: st.encodeHeader(":method", "POST"),
EndStream: false,
EndHeaders: true,
})
st.writeData(1, false, bytes.Repeat([]byte("a"), maxSizePerConn/2))
puppet.do(readBodyHandler(t, strings.Repeat("a", maxSizePerConn/2)))
st.wantWindowUpdate(0, uint32(maxSizePerConn/2))
st.writeData(1, false, bytes.Repeat([]byte("b"), maxSizePerConn/2+100))
puppet.do(readBodyHandler(t, strings.Repeat("b", maxSizePerConn/2+100)))
st.wantWindowUpdate(0, uint32(maxSizePerConn/2+100))
st.wantWindowUpdate(1, uint32(maxSizePerConn+100))
st.writeData(1, true, nil) // END_STREAM here
}
func TestServer_Send_GoAway_After_Bogus_WindowUpdate(t *testing.T) {
st := newServerTester(t, nil)
defer st.Close()