Skip to content

Commit 0c39914

Browse files
author
ladeak
committed
review comments
1 parent e316060 commit 0c39914

File tree

2 files changed

+56
-19
lines changed

2 files changed

+56
-19
lines changed

src/Servers/Kestrel/Core/src/Internal/Http2/FlowControl/InputFlowControl.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ private struct FlowControlState
2424
private const long AbortedBitMask = 1L << 32; // uint MaxValue + 1
2525
internal long _state;
2626

27-
public FlowControlState(uint initialWindowSize, bool isAborted)
27+
public FlowControlState(int size, bool isAborted)
2828
{
29-
_state = initialWindowSize;
29+
_state = (uint)size; // Casted first to uint before assigning it to a long field to the address negative values
3030
if (isAborted)
3131
{
3232
_state |= AbortedBitMask;
3333
}
3434
}
3535

36-
public uint Available => (uint)_state;
36+
public int Available => (int)_state;
3737

3838
public bool IsAborted => _state > uint.MaxValue;
3939
}
@@ -49,19 +49,20 @@ public InputFlowControl(uint initialWindowSize, uint minWindowSizeIncrement)
4949
{
5050
Debug.Assert(initialWindowSize >= minWindowSizeIncrement, "minWindowSizeIncrement is greater than the window size.");
5151

52-
_flow = new FlowControlState(initialWindowSize, false);
52+
_flow = new FlowControlState((int)initialWindowSize, isAborted: false);
5353
_initialWindowSize = initialWindowSize;
5454
_minWindowSizeIncrement = (int)minWindowSizeIncrement;
5555
}
5656

5757
public bool IsAvailabilityLow => _flow.Available < _minWindowSizeIncrement;
5858

59-
// Test hook, not participating in mutual exclusion
60-
internal uint Available => _flow.Available;
59+
// Test hook
60+
internal int Available => _flow.Available;
61+
internal bool IsAborted => _flow.IsAborted;
6162

6263
public void Reset()
6364
{
64-
_flow = new FlowControlState(_initialWindowSize, false);
65+
_flow = new FlowControlState((int)_initialWindowSize, isAborted: false);
6566
_pendingUpdateSize = 0;
6667
_windowUpdatesDisabled = false;
6768
}
@@ -72,6 +73,7 @@ public bool TryAdvance(int bytes)
7273
do
7374
{
7475
currentFlow = _flow; // Copy
76+
7577
// Even if the stream is aborted, the client should never send more data than was available in the
7678
// flow-control window at the time of the abort.
7779
if (bytes > currentFlow.Available)
@@ -84,7 +86,7 @@ public bool TryAdvance(int bytes)
8486
return false;
8587
}
8688

87-
computedFlow = new FlowControlState(currentFlow.Available - (uint)bytes, isAborted: false);
89+
computedFlow = new FlowControlState(currentFlow.Available - bytes, isAborted: false);
8890
} while (currentFlow._state != Interlocked.CompareExchange(ref _flow._state, computedFlow._state, currentFlow._state));
8991

9092
return true;
@@ -103,14 +105,12 @@ public bool TryUpdateWindow(int bytes, out int updateSize)
103105
return false;
104106
}
105107

106-
var maxUpdate = int.MaxValue - currentFlow.Available;
107-
if (bytes > maxUpdate)
108-
{
109-
// We only try to update the window back to its initial size after the app consumes data.
110-
// It shouldn't be possible for the window size to ever exceed Http2PeerSettings.MaxWindowSize.
111-
Debug.Assert(false, $"{nameof(TryUpdateWindow)} attempted to grow window past max size.");
112-
}
113-
computedFlow = new FlowControlState(currentFlow.Available + (uint)bytes, isAborted: false);
108+
var maxUpdate = Http2PeerSettings.MaxWindowSize - currentFlow.Available;
109+
110+
// We only try to update the window back to its initial size after the app consumes data.
111+
// It shouldn't be possible for the window size to ever exceed Http2PeerSettings.MaxWindowSize.
112+
Debug.Assert(bytes <= maxUpdate, $"{nameof(TryUpdateWindow)} attempted to grow window past max size.");
113+
computedFlow = new FlowControlState(currentFlow.Available + bytes, isAborted: false);
114114
} while (currentFlow._state != Interlocked.CompareExchange(ref _flow._state, computedFlow._state, currentFlow._state));
115115

116116
if (_windowUpdatesDisabled)

src/Servers/Kestrel/Core/test/Http2/FlowControl/InputFlowControlTests.cs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,43 @@ public class InputFlowControlTests
1010
{
1111
private const int IterationCount = 1;
1212

13+
[Theory]
14+
[InlineData(-100, -100)]
15+
[InlineData(100, 100)]
16+
[InlineData(int.MaxValue, int.MaxValue)]
17+
[InlineData(int.MinValue, int.MinValue)]
18+
public void ValuesCanBeUpdatedToBoundaries(int update, int expected)
19+
{
20+
var sut = new InputFlowControl(0, 0);
21+
sut.TryUpdateWindow(update, out _);
22+
Assert.Equal(expected, sut.Available);
23+
}
24+
25+
[Fact]
26+
public void Available_CanBecomeNegative()
27+
{
28+
var sut = new InputFlowControl(10, 1);
29+
sut.TryUpdateWindow(-100, out _);
30+
Assert.Equal(-90, sut.Available);
31+
sut.TryUpdateWindow(100, out _);
32+
Assert.Equal(10, sut.Available);
33+
}
34+
35+
[Theory]
36+
[InlineData(0)]
37+
[InlineData(1)]
38+
[InlineData(-1)]
39+
[InlineData(int.MaxValue)]
40+
[InlineData(int.MinValue)]
41+
public void IsAborted(int value)
42+
{
43+
var sut = new InputFlowControl(uint.MaxValue, 1);
44+
sut.TryUpdateWindow(value, out _);
45+
Assert.False(sut.IsAborted);
46+
sut.Abort();
47+
Assert.True(sut.IsAborted);
48+
}
49+
1350
[Fact]
1451
public async Task Threads1_Advance()
1552
{
@@ -82,7 +119,7 @@ public async Task Threads3_WindowUpdates()
82119
var t2 = Task.Run(() => WindowUpdate(sut));
83120
var t3 = Task.Run(() => WindowUpdate(sut));
84121
await Task.WhenAll(t1, t2, t3);
85-
Assert.Equal((uint)15000 + 5000 * 3, sut.Available);
122+
Assert.Equal(15000 + 5000 * 3, sut.Available);
86123
}
87124

88125
static void WindowUpdate(InputFlowControl sut)
@@ -331,7 +368,7 @@ public async Task Threads3Advance_WindowUpdates()
331368
var t2 = Task.Run(() => Advance(sut));
332369
var t3 = Task.Run(() => Advance(sut));
333370
await Task.WhenAll(t0, t1, t2, t3);
334-
Assert.Equal((uint)10000, sut.Available);
371+
Assert.Equal(10000, sut.Available);
335372
}
336373

337374
static void WindowUpdate(InputFlowControl sut)
@@ -364,7 +401,7 @@ public async Task Threads3WindowUpdates_AssertSize()
364401
var t2 = Task.Run(() => WindowUpdate(ref sizeSum, sut));
365402
var t3 = Task.Run(() => WindowUpdate(ref sizeSum, sut));
366403
await Task.WhenAll(t1, t2, t3);
367-
Assert.Equal((uint)15000 + 5000 * 3, sut.Available);
404+
Assert.Equal(15000 + 5000 * 3, sut.Available);
368405
sut.TryUpdateWindow(11, out var size); // To trigger anything less then 10 included
369406
sizeSum += size;
370407
Assert.Equal(5000 * 3 + 11, sizeSum);

0 commit comments

Comments
 (0)