Skip to content

Commit 0c5f7d5

Browse files
committed
Return false instead of throwing InvalidOperationException on read of a gRPC server stream after the connection was closed
1 parent ac3b3f4 commit 0c5f7d5

File tree

2 files changed

+13
-12
lines changed

2 files changed

+13
-12
lines changed

src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ async Task<bool> MoveNextAsync(ValueTask<TRequest?> readStreamTask)
5858

5959
if (_completed || _serverCallContext.CancellationToken.IsCancellationRequested)
6060
{
61-
return Task.FromException<bool>(new InvalidOperationException("Can't read messages after the request is complete."));
61+
// gRPC specification indicates that MoveNext() should not throw. Simply return false.
62+
return CommonGrpcProtocolHelpers.FalseTask;
6263
}
6364

6465
var request = _serverCallContext.HttpContext.Request.BodyReader.ReadStreamMessageAsync(_serverCallContext, _deserializer, cancellationToken);

test/FunctionalTests/Client/StreamingTests.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace Grpc.AspNetCore.FunctionalTests.Client
4242
public class StreamingTests : FunctionalTestBase
4343
{
4444
[Test]
45-
public async Task DuplexStream_SendLargeFileBatchedAndRecieveLargeFileBatched_Success()
45+
public async Task DuplexStream_SendLargeFileBatchedAndReceiveLargeFileBatched_Success()
4646
{
4747
// Arrange
4848
var data = CreateTestData(1024 * 1024 * 1); // 1 MB
@@ -306,7 +306,7 @@ await call.RequestStream.WriteAsync(new DataMessage
306306
[TestCase(1)]
307307
[TestCase(5)]
308308
[TestCase(20)]
309-
public async Task DuplexStreaming_SimultaniousSendAndReceiveInParallel_Success(int tasks)
309+
public async Task DuplexStreaming_SimultaneousSendAndReceiveInParallel_Success(int tasks)
310310
{
311311
// Arrange
312312
const int total = 1024 * 1024 * 1;
@@ -316,7 +316,7 @@ public async Task DuplexStreaming_SimultaniousSendAndReceiveInParallel_Success(i
316316

317317
var client = new StreamService.StreamServiceClient(Channel);
318318

319-
await TestHelpers.RunParallel(tasks, async taskIndex =>
319+
await TestHelpers.RunParallel(tasks, async _ =>
320320
{
321321
var (sent, received) = await EchoData(total, data, client).DefaultTimeout();
322322

@@ -421,7 +421,7 @@ await TestHelpers.AssertIsTrueRetryAsync(
421421
[Test]
422422
public async Task DuplexStreaming_ParallelCallsFromOneChannel_Success()
423423
{
424-
async Task UnaryDeadlineExceeded(IAsyncStreamReader<DataMessage> requestStream, IServerStreamWriter<DataMessage> responseStream, ServerCallContext context)
424+
static async Task UnaryDeadlineExceeded(IAsyncStreamReader<DataMessage> requestStream, IServerStreamWriter<DataMessage> responseStream, ServerCallContext context)
425425
{
426426
await foreach (var message in requestStream.ReadAllAsync())
427427
{
@@ -460,7 +460,7 @@ async Task UnaryDeadlineExceeded(IAsyncStreamReader<DataMessage> requestStream,
460460
[Test]
461461
public async Task ServerStreaming_GetTrailersAndStatus_Success()
462462
{
463-
async Task ServerStreamingWithTrailers(DataMessage request, IServerStreamWriter<DataMessage> responseStream, ServerCallContext context)
463+
static async Task ServerStreamingWithTrailers(DataMessage request, IServerStreamWriter<DataMessage> responseStream, ServerCallContext context)
464464
{
465465
await responseStream.WriteAsync(new DataMessage());
466466
context.ResponseTrailers.Add("my-trailer", "value");
@@ -625,7 +625,7 @@ async Task ServerStreamingWithTrailers(DataMessage request, IServerStreamWriter<
625625

626626
[TestCase(true)]
627627
[TestCase(false)]
628-
public async Task ClientStreaming_ReadAfterMethodComplete_Error(bool readBeforeExit)
628+
public async Task ClientStreaming_ReadAfterMethodComplete_False(bool readBeforeExit)
629629
{
630630
SetExpectedErrorsFilter(writeContext =>
631631
{
@@ -641,7 +641,7 @@ public async Task ClientStreaming_ReadAfterMethodComplete_Error(bool readBeforeE
641641
var tcs = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);
642642
var readTcs = new TaskCompletionSource<Task>(TaskCreationOptions.RunContinuationsAsynchronously);
643643
var syncPoint = new SyncPoint(runContinuationsAsynchronously: true);
644-
async Task<DataMessage> ClientStreamingWithTrailers(IAsyncStreamReader<DataMessage> requestStream, ServerCallContext context)
644+
async Task<DataMessage> ClientStreamingWithTrailersAsync(IAsyncStreamReader<DataMessage> requestStream, ServerCallContext context)
645645
{
646646
var readTask = Task.Run(async () =>
647647
{
@@ -661,7 +661,7 @@ async Task<DataMessage> ClientStreamingWithTrailers(IAsyncStreamReader<DataMessa
661661
}
662662

663663
// Arrange
664-
var method = Fixture.DynamicGrpc.AddClientStreamingMethod<DataMessage, DataMessage>(ClientStreamingWithTrailers);
664+
var method = Fixture.DynamicGrpc.AddClientStreamingMethod<DataMessage, DataMessage>(ClientStreamingWithTrailersAsync);
665665

666666
var channel = CreateChannel();
667667

@@ -680,13 +680,13 @@ async Task<DataMessage> ClientStreamingWithTrailers(IAsyncStreamReader<DataMessa
680680

681681
tcs.SetResult(null);
682682

683-
var response = await call;
683+
DataMessage response = await call;
684+
Assert.IsNotNull(response);
684685

685686
syncPoint.Continue();
686687

687688
var readTask = await readTcs.Task.DefaultTimeout();
688-
var ex = await ExceptionAssert.ThrowsAsync<InvalidOperationException>(() => readTask).DefaultTimeout();
689-
Assert.AreEqual("Can't read messages after the request is complete.", ex.Message);
689+
await readTask.DefaultTimeout();
690690

691691
var clientException = await ExceptionAssert.ThrowsAsync<RpcException>(() => call.RequestStream.WriteAsync(new DataMessage())).DefaultTimeout();
692692
Assert.AreEqual(StatusCode.OK, clientException.StatusCode);

0 commit comments

Comments
 (0)