Wait for frame loop completion to dispose connection stream (#1156).
This commit is contained in:
parent
663b825d97
commit
3177ba0aae
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
public Task StopAsync()
|
public Task StopAsync()
|
||||||
{
|
{
|
||||||
_frame.Stop();
|
_frame.StopAsync();
|
||||||
_frame.SocketInput.CompleteAwaiting();
|
_frame.SocketInput.CompleteAwaiting();
|
||||||
|
|
||||||
return _socketClosedTcs.Task;
|
return _socketClosedTcs.Task;
|
||||||
|
|
@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
if (_filteredStreamAdapter != null)
|
if (_filteredStreamAdapter != null)
|
||||||
{
|
{
|
||||||
_readInputTask.ContinueWith((task, state) =>
|
Task.WhenAll(_readInputTask, _frame.StopAsync()).ContinueWith((task, state) =>
|
||||||
{
|
{
|
||||||
var connection = (Connection)state;
|
var connection = (Connection)state;
|
||||||
connection._filterContext.Connection.Dispose();
|
connection._filterContext.Connection.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
this,
|
this,
|
||||||
default(CancellationToken),
|
default(CancellationToken),
|
||||||
TaskCreationOptions.DenyChildAttach,
|
TaskCreationOptions.DenyChildAttach,
|
||||||
TaskScheduler.Default);
|
TaskScheduler.Default).Unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -374,7 +374,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
/// Stop will be called on all active connections, and Task.WaitAll() will be called on every
|
/// Stop will be called on all active connections, and Task.WaitAll() will be called on every
|
||||||
/// return value.
|
/// return value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task Stop()
|
public Task StopAsync()
|
||||||
{
|
{
|
||||||
if (!_requestProcessingStopping)
|
if (!_requestProcessingStopping)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await httpContext.Response.WriteAsync($"hello, world\r\r", ct);
|
await httpContext.Response.WriteAsync($"hello, world", ct);
|
||||||
await Task.Delay(1000, ct);
|
await Task.Delay(1000, ct);
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (TaskCanceledException)
|
||||||
|
|
@ -136,6 +136,54 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
Assert.False(loggerFactory.ErrorLogger.ObjectDisposedExceptionLogged);
|
Assert.False(loggerFactory.ErrorLogger.ObjectDisposedExceptionLogged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DoesNotThrowObjectDisposedExceptionFromWriteAsyncAfterConnectionIsAborted()
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<object>();
|
||||||
|
var x509Certificate2 = new X509Certificate2(@"TestResources/testCert.pfx", "testPassword");
|
||||||
|
var loggerFactory = new HandshakeErrorLoggerFactory();
|
||||||
|
var hostBuilder = new WebHostBuilder()
|
||||||
|
.UseKestrel(options =>
|
||||||
|
{
|
||||||
|
options.UseHttps(@"TestResources/testCert.pfx", "testPassword");
|
||||||
|
})
|
||||||
|
.UseUrls("https://127.0.0.1:0/")
|
||||||
|
.UseLoggerFactory(loggerFactory)
|
||||||
|
.Configure(app => app.Run(async httpContext =>
|
||||||
|
{
|
||||||
|
httpContext.Abort();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await httpContext.Response.WriteAsync($"hello, world");
|
||||||
|
tcs.SetResult(null);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tcs.SetException(ex);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
using (var host = hostBuilder.Build())
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var socket = await HttpClientSlim.GetSocket(new Uri($"https://127.0.0.1:{host.GetPort()}/")))
|
||||||
|
using (var stream = new NetworkStream(socket, ownsSocket: false))
|
||||||
|
using (var sslStream = new SslStream(stream, true, (sender, certificate, chain, errors) => true))
|
||||||
|
{
|
||||||
|
await sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates: null,
|
||||||
|
enabledSslProtocols: SslProtocols.Tls11 | SslProtocols.Tls12,
|
||||||
|
checkCertificateRevocation: false);
|
||||||
|
|
||||||
|
var request = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n\r\n");
|
||||||
|
await sslStream.WriteAsync(request, 0, request.Length);
|
||||||
|
await sslStream.ReadAsync(new byte[32], 0, 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
|
||||||
|
}
|
||||||
|
|
||||||
private class HandshakeErrorLoggerFactory : ILoggerFactory
|
private class HandshakeErrorLoggerFactory : ILoggerFactory
|
||||||
{
|
{
|
||||||
public HttpsConnectionFilterLogger FilterLogger { get; } = new HttpsConnectionFilterLogger();
|
public HttpsConnectionFilterLogger FilterLogger { get; } = new HttpsConnectionFilterLogger();
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel;
|
using Microsoft.AspNetCore.Server.Kestrel;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal;
|
||||||
|
|
@ -1290,7 +1292,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var expectedKeepAliveTimeout = (long)serviceContext.ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds;
|
var expectedKeepAliveTimeout = (long)serviceContext.ServerOptions.Limits.KeepAliveTimeout.TotalMilliseconds;
|
||||||
connectionControl.Verify(cc => cc.SetTimeout(expectedKeepAliveTimeout, TimeoutAction.CloseConnection));
|
connectionControl.Verify(cc => cc.SetTimeout(expectedKeepAliveTimeout, TimeoutAction.CloseConnection));
|
||||||
|
|
||||||
frame.Stop();
|
frame.StopAsync();
|
||||||
socketInput.IncomingFin();
|
socketInput.IncomingFin();
|
||||||
|
|
||||||
requestProcessingTask.Wait();
|
requestProcessingTask.Wait();
|
||||||
|
|
@ -1464,5 +1466,43 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Throws<InvalidOperationException>(() => frame.Flush());
|
Assert.Throws<InvalidOperationException>(() => frame.Flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestProcessingTaskIsUnwrapped()
|
||||||
|
{
|
||||||
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
using (var pool = new MemoryPool())
|
||||||
|
using (var socketInput = new SocketInput(pool, ltp))
|
||||||
|
{
|
||||||
|
var serviceContext = new ServiceContext
|
||||||
|
{
|
||||||
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
|
Log = trace
|
||||||
|
};
|
||||||
|
var listenerContext = new ListenerContext(serviceContext)
|
||||||
|
{
|
||||||
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
||||||
|
};
|
||||||
|
var connectionContext = new ConnectionContext(listenerContext)
|
||||||
|
{
|
||||||
|
ConnectionControl = Mock.Of<IConnectionControl>(),
|
||||||
|
SocketInput = socketInput
|
||||||
|
};
|
||||||
|
|
||||||
|
var frame = new Frame<HttpContext>(application: null, context: connectionContext);
|
||||||
|
frame.Start();
|
||||||
|
|
||||||
|
var data = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n\r\n");
|
||||||
|
socketInput.IncomingData(data, 0, data.Length);
|
||||||
|
|
||||||
|
var requestProcessingTask = frame.StopAsync();
|
||||||
|
Assert.IsNotType(typeof(Task<Task>), requestProcessingTask);
|
||||||
|
|
||||||
|
await requestProcessingTask.TimeoutAfter(TimeSpan.FromSeconds(10));
|
||||||
|
socketInput.IncomingFin();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue