Skip to content

HTTP2: Client and server disagree on active stream count #1586

@Tratcher

Description

@Tratcher

From @JamesNK on Saturday, August 24, 2019 2:24:08 AM

Issue found during HTTP2 stress testing. One HttpClient is sending multiple requests in parallel, then canceling them via RST_STREAM sent to the server. For an unknown reason the server and client disagree on the active stream count, and the sever eventually sends RST_STREAM (REFUSED_STREAM) and GOAWAY (STREAM_CLOSED). This issue eventually leads to dotnet/aspnetcore#13405.

Client and server should agree on the active stream count and the client should wait to send new requests, without error.

Wireshark log: https://www.dropbox.com/s/5ndspth4t0qjyj6/clientreset-error.zip?dl=0

Exception on the client:

Unhandled exception. System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.IO.IOException: The request was aborted.
---> System.IO.IOException: The response ended prematurely, with at least 9 additional bytes expected.
   at System.Net.Http.Http2Connection.ReadAtLeastAsync(Stream stream, Memory`1 buffer, Int32 minReadBytes)
   at System.Net.Http.Http2Connection.EnsureIncomingBytesAsync(Int32 minReadBytes)
   at System.Net.Http.Http2Connection.ReadFrameAsync(Boolean initialFrame)
   at System.Net.Http.Http2Connection.ProcessIncomingFramesAsync()
   --- End of inner exception stack trace ---
   at System.Net.Http.Http2Connection.Http2Stream.CheckResponseBodyState()
   at System.Net.Http.Http2Connection.Http2Stream.TryEnsureHeaders()
   at System.Net.Http.Http2Connection.Http2Stream.ReadResponseHeadersAsync(CancellationToken cancellationToken)
   at System.Net.Http.Http2Connection.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.Http2Connection.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Grpc.Net.Client.Internal.GrpcCall`2.SendAsync(HttpClient client, HttpRequestMessage message)
   at Grpc.Net.Client.Internal.GrpcCall`2.GetResponseHeadersAsync()

Repo is currently not public. Contact @JamesNK or @Tratcher for the repo source code and instruction.

Copied from original issue: dotnet/aspnetcore#13406

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions