Fixed race in sockets transport (#2279) (#2322)

This commit is contained in:
Stephen Halter 2018-02-15 14:05:45 -08:00 committed by GitHub
parent 0608de37dc
commit d78e7ea80d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 11 additions and 5 deletions

View File

@ -57,13 +57,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
public async Task StartAsync(IConnectionHandler connectionHandler) public async Task StartAsync(IConnectionHandler connectionHandler)
{ {
Exception sendError = null;
try try
{ {
connectionHandler.OnConnection(this); connectionHandler.OnConnection(this);
// Spawn send and receive logic // Spawn send and receive logic
Task receiveTask = DoReceive(); Task receiveTask = DoReceive();
Task sendTask = DoSend(); Task<Exception> sendTask = DoSend();
// If the sending task completes then close the receive // If the sending task completes then close the receive
// We don't need to do this in the other direction because the kestrel // We don't need to do this in the other direction because the kestrel
@ -76,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
// Now wait for both to complete // Now wait for both to complete
await receiveTask; await receiveTask;
await sendTask; sendError = await sendTask;
// Dispose the socket(should noop if already called) // Dispose the socket(should noop if already called)
_socket.Dispose(); _socket.Dispose();
@ -85,6 +86,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{ {
_trace.LogError(0, ex, $"Unexpected exception in {nameof(SocketConnection)}.{nameof(StartAsync)}."); _trace.LogError(0, ex, $"Unexpected exception in {nameof(SocketConnection)}.{nameof(StartAsync)}.");
} }
finally
{
// Complete the output after disposing the socket
Output.Complete(sendError);
}
} }
private async Task DoReceive() private async Task DoReceive()
@ -181,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
} }
} }
private async Task DoSend() private async Task<Exception> DoSend()
{ {
Exception error = null; Exception error = null;
@ -233,8 +239,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
} }
finally finally
{ {
Output.Complete(error);
// Make sure to close the connection only after the _aborted flag is set. // Make sure to close the connection only after the _aborted flag is set.
// Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when // Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when
// a BadHttpRequestException is thrown instead of a TaskCanceledException. // a BadHttpRequestException is thrown instead of a TaskCanceledException.
@ -242,6 +246,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
_trace.ConnectionWriteFin(ConnectionId); _trace.ConnectionWriteFin(ConnectionId);
_socket.Shutdown(SocketShutdown.Both); _socket.Shutdown(SocketShutdown.Both);
} }
return error;
} }
} }
} }