aspnetcore: Kestrel doesn't reset KeepAlive timeout on HTTP2 PING frames

Describe the bug

NOTE: This is related, but a separate issue from https://github.com/dotnet/aspnetcore/issues/15104. That one is about server-initiated PING’s to the client to proactively detect zombie connections; whereas this one is about Kestrel not resetting its keepalive timeout in response to client-initiated PING’s.

gRPC clients can be configured to send periodic pings to keep a channel open for prolonged periods of time even when there aren’t any active streams. Kestrel however drops an idle connection after KestrelServerLimits.KeepAliveTimeout elapses. Http2Connection does not reset the TimeoutControl when PING frames are received, resulting in connections that (supposedly) should remain open to be aborted

To Reproduce

Use a gRPC client configured as follows (using gRPC for C#), with the following options:

var options = new List<ChannelOption>()
{
    // ...
    new ChannelOption("grpc.client_idle_timeout_ms", 15 * 60 * 1000),
    new ChannelOption("grpc.keepalive_time_ms", 10 * 1000),
    new ChannelOption("grpc.keepalive_permit_without_calls", 1),
};

This should result in PING frames being sent every 10 seconds, and the channel should remain open up to 15 minutes even when idle. However, Kestrel terminates the connection after its KeepAliveTimeout elapses (2 min by default).

Exceptions

N/A

Further technical details

  • ASP.NET Core 3.1 (code inspection indicates latest master has the same issue)

Suggested fix would be to add a call to TimeoutControl.SetTimeout(Limits.KeepAliveTimeout.Ticks, TimeoutReason.KeepAlive); when processing a PING frame in Http2Connection.ProcessPingFrameAsync.

Is this a legit bug or is it by design?

@JamesNK @Tratcher

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 18 (16 by maintainers)

Most upvoted comments

I want to avoid adding too many Http2Limits. It’s already quite a lot for the majority of people who aren’t intimately familiar with the HTTP/2 protocol. Before adding yet another configurable limit, I’d like to know of a real customer/scenario that needs to make this configurable.

It’s clear we need to fix pings not resetting the keep-alive timeout. That’s just a bug. Really, any frame received while there are not active requests should reset the timeout.