Wait for input writer to complete before calling OnConnectionClosed (#2566)

This commit is contained in:
Stephen Halter 2018-05-14 11:51:49 -07:00 committed by GitHub
parent c52a3bf534
commit 514917b9a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 20 deletions

View File

@ -238,10 +238,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
}); });
} }
public void OnConnectionClosed(Exception ex) public void OnConnectionClosed()
{ {
Abort(ex);
_socketClosedTcs.TrySetResult(null); _socketClosedTcs.TrySetResult(null);
} }

View File

@ -1,11 +1,12 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
_connectionAdapters = adapters; _connectionAdapters = adapters;
} }
public Task OnConnectionAsync(ConnectionContext connectionContext) public async Task OnConnectionAsync(ConnectionContext connectionContext)
{ {
// We need the transport feature so that we can cancel the output reader that the transport is using // We need the transport feature so that we can cancel the output reader that the transport is using
// This is a bit of a hack but it preserves the existing semantics // This is a bit of a hack but it preserves the existing semantics
@ -69,22 +70,46 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
} }
var connection = new HttpConnection(httpConnectionContext); var connection = new HttpConnection(httpConnectionContext);
var inputCompletionState = new PipeCompletionState(connection);
var outputCompletionState = new PipeCompletionState(connection);
var processingTask = connection.StartRequestProcessing(_application); var processingTask = connection.StartRequestProcessing(_application);
connectionContext.Transport.Input.OnWriterCompleted((error, state) => connectionContext.Transport.Input.OnWriterCompleted(
{ (error, state) => ((PipeCompletionState)state).CompletionCallback(error),
((HttpConnection)state).Abort(error); inputCompletionState);
},
connection);
connectionContext.Transport.Output.OnReaderCompleted((error, state) => connectionContext.Transport.Output.OnReaderCompleted(
{ (error, state) => ((PipeCompletionState)state).CompletionCallback(error),
((HttpConnection)state).OnConnectionClosed(error); outputCompletionState);
},
connection);
return processingTask; await inputCompletionState.CompletionTask;
await outputCompletionState.CompletionTask;
connection.OnConnectionClosed();
await processingTask;
}
private class PipeCompletionState
{
private readonly HttpConnection _connection;
private readonly TaskCompletionSource<object> _completionTcs = new TaskCompletionSource<object>();
public PipeCompletionState(HttpConnection connection)
{
_connection = connection;
CompletionTask = _completionTcs.Task;
}
public Task CompletionTask { get; }
public void CompletionCallback(Exception error)
{
_connection.Abort(error);
_completionTcs.SetResult(null);
}
} }
} }
} }

View File

@ -1266,7 +1266,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
}; };
var scratchBuffer = new byte[maxRequestBufferSize * 2 + 1]; var scratchBuffer = new byte[maxRequestBufferSize * 8];
using (var server = new TestServer(async context => using (var server = new TestServer(async context =>
{ {

View File

@ -2381,7 +2381,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
}; };
var scratchBuffer = new byte[maxRequestBufferSize * 2 + 1]; var scratchBuffer = new byte[maxRequestBufferSize * 8];
using (var server = new TestServer(async context => using (var server = new TestServer(async context =>
{ {