3.1: Reset KeepAliveTimeout on HTTP/2 ping (#24858)

* Reset KeepAliveTimeout on HTTP/2 ping (#24644)

* Fix flaky keepalive ping test (#24804)

* Fix flaky keepalive ping test

* Clean up stream

* Remove quarantine attribute

* Fix test
This commit is contained in:
James Newton-King 2020-08-14 10:06:02 +12:00 committed by GitHub
parent 9034fa2ee6
commit 229e496966
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 0 deletions

View File

@ -747,6 +747,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorUnexpectedFrameLength(_incomingFrame.Type, 8), Http2ErrorCode.FRAME_SIZE_ERROR);
}
// Incoming ping resets connection keep alive timeout
if (TimeoutControl.TimerReason == TimeoutReason.KeepAlive)
{
TimeoutControl.ResetTimeout(Limits.KeepAliveTimeout.Ticks, TimeoutReason.KeepAlive);
}
if (_incomingFrame.PingAck)
{
// TODO: verify that payload is equal to the outgoing PING frame

View File

@ -120,6 +120,76 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_mockTimeoutHandler.VerifyNoOtherCalls();
}
[Fact]
public async Task PING_WithinKeepAliveTimeout_ResetKeepAliveTimeout()
{
var mockSystemClock = _serviceContext.MockSystemClock;
var limits = _serviceContext.ServerOptions.Limits;
_timeoutControl.Initialize(mockSystemClock.UtcNow.Ticks);
CreateConnection();
await InitializeConnectionAsync(_noopApplication);
// Connection starts and sets keep alive timeout
_mockTimeoutControl.Verify(c => c.SetTimeout(It.IsAny<long>(), TimeoutReason.KeepAlive), Times.Once);
_mockTimeoutControl.Verify(c => c.ResetTimeout(It.IsAny<long>(), TimeoutReason.KeepAlive), Times.Never);
await SendPingAsync(Http2PingFrameFlags.NONE);
await ExpectAsync(Http2FrameType.PING,
withLength: 8,
withFlags: (byte)Http2PingFrameFlags.ACK,
withStreamId: 0);
// Server resets keep alive timeout
_mockTimeoutControl.Verify(c => c.ResetTimeout(It.IsAny<long>(), TimeoutReason.KeepAlive), Times.Once);
}
[Fact]
public async Task PING_NoKeepAliveTimeout_DoesNotResetKeepAliveTimeout()
{
var mockSystemClock = _serviceContext.MockSystemClock;
var limits = _serviceContext.ServerOptions.Limits;
_timeoutControl.Initialize(mockSystemClock.UtcNow.Ticks);
CreateConnection();
await InitializeConnectionAsync(_echoApplication);
// Connection starts and sets keep alive timeout
_mockTimeoutControl.Verify(c => c.SetTimeout(It.IsAny<long>(), TimeoutReason.KeepAlive), Times.Once);
_mockTimeoutControl.Verify(c => c.ResetTimeout(It.IsAny<long>(), TimeoutReason.KeepAlive), Times.Never);
_mockTimeoutControl.Verify(c => c.CancelTimeout(), Times.Never);
// Stream will stay open because it is waiting for request body to end
await StartStreamAsync(1, _browserRequestHeaders, endStream: false);
// Starting a stream cancels the keep alive timeout
_mockTimeoutControl.Verify(c => c.CancelTimeout(), Times.Once);
await SendPingAsync(Http2PingFrameFlags.NONE);
await ExpectAsync(Http2FrameType.PING,
withLength: 8,
withFlags: (byte)Http2PingFrameFlags.ACK,
withStreamId: 0);
// Server doesn't reset keep alive timeout because it isn't running
_mockTimeoutControl.Verify(c => c.ResetTimeout(It.IsAny<long>(), TimeoutReason.KeepAlive), Times.Never);
// End stream
await SendDataAsync(1, _helloWorldBytes, endStream: true);
await ExpectAsync(Http2FrameType.HEADERS,
withLength: 37,
withFlags: (byte)Http2HeadersFrameFlags.END_HEADERS,
withStreamId: 1);
await ExpectAsync(Http2FrameType.DATA,
withLength: _helloWorldBytes.Length,
withFlags: (byte)Http2DataFrameFlags.NONE,
withStreamId: 1);
}
[Fact]
public async Task HEADERS_ReceivedWithoutAllCONTINUATIONs_WithinRequestHeadersTimeout_AbortsConnection()
{