Skip to content

Commit b934e46

Browse files
authored
Complete the transport pipes after connection middleware runs (#2735)
1 parent a44007a commit b934e46

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/Kestrel.Core/Internal/ConnectionDispatcher.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ private async Task Execute(ConnectionContext connectionContext)
5959
{
6060
Log.LogCritical(0, ex, $"{nameof(ConnectionDispatcher)}.{nameof(Execute)}() {connectionContext.ConnectionId}");
6161
}
62+
finally
63+
{
64+
// Complete the transport PipeReader and PipeWriter after calling into application code
65+
connectionContext.Transport.Input.Complete();
66+
connectionContext.Transport.Output.Complete();
67+
}
6268
}
6369
}
6470

test/Kestrel.Core.Tests/ConnectionDispatcherTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
6+
using System.IO.Pipelines;
57
using System.Linq;
68
using System.Threading.Tasks;
79
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
@@ -42,5 +44,27 @@ public void OnConnectionCreatesLogScopeWithConnectionId()
4244
// Verify the scope was disposed after request processing completed
4345
Assert.True(((TestKestrelTrace)serviceContext.Log).Logger.Scopes.IsEmpty);
4446
}
47+
48+
[Fact]
49+
public async Task OnConnectionCompletesTransportPipesAfterReturning()
50+
{
51+
var serviceContext = new TestServiceContext();
52+
var tcs = new TaskCompletionSource<object>();
53+
var dispatcher = new ConnectionDispatcher(serviceContext, _ => Task.CompletedTask);
54+
55+
var mockConnection = new Mock<TransportConnection>();
56+
var mockPipeReader = new Mock<PipeReader>();
57+
var mockPipeWriter = new Mock<PipeWriter>();
58+
var mockPipe = new Mock<IDuplexPipe>();
59+
mockPipe.Setup(m => m.Input).Returns(mockPipeReader.Object);
60+
mockPipe.Setup(m => m.Output).Returns(mockPipeWriter.Object);
61+
mockConnection.Setup(m => m.Transport).Returns(mockPipe.Object);
62+
var connection = mockConnection.Object;
63+
64+
await dispatcher.OnConnection(connection);
65+
66+
mockPipeWriter.Verify(m => m.Complete(It.IsAny<Exception>()), Times.Once());
67+
mockPipeReader.Verify(m => m.Complete(It.IsAny<Exception>()), Times.Once());
68+
}
4569
}
4670
}

0 commit comments

Comments
 (0)