Close LongPolling connection on poll exception (#2701)

This commit is contained in:
BrennanConroy 2018-07-31 09:52:10 -07:00 committed by GitHub
parent 25b826de75
commit 3d6e1e69fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 0 deletions

View File

@ -289,6 +289,13 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
pollAgain = false;
}
}
else if (resultTask.IsFaulted)
{
// transport task was faulted, we should remove the connection
await _manager.DisposeAndRemoveAsync(connection, closeGracefully: false);
pollAgain = false;
}
else if (context.Response.StatusCode == StatusCodes.Status204NoContent)
{
// Don't poll if the transport task was canceled

View File

@ -90,6 +90,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal.Transports
catch (Exception ex)
{
Log.LongPollingTerminated(_logger, ex);
context.Response.ContentType = "text/plain";
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
throw;
}
}

View File

@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http.Connections.Internal;
using Microsoft.AspNetCore.Http.Connections.Internal.Transports;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.SignalR.Tests;
@ -2016,6 +2017,48 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
}
}
[Fact]
public async Task ErrorDuringPollWillCloseConnection()
{
bool ExpectedErrors(WriteContext writeContext)
{
return (writeContext.LoggerName == typeof(LongPollingTransport).FullName &&
writeContext.EventId.Name == "LongPollingTerminated") ||
(writeContext.LoggerName == typeof(HttpConnectionManager).FullName &&
writeContext.EventId.Name == "FailedDispose");
}
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug, expectedErrorsFilter: ExpectedErrors))
{
var manager = CreateConnectionManager(loggerFactory);
var connection = manager.CreateConnection();
connection.TransportType = HttpTransportType.LongPolling;
var dispatcher = new HttpConnectionDispatcher(manager, loggerFactory);
var services = new ServiceCollection();
services.AddSingleton<TestConnectionHandler>();
var builder = new ConnectionBuilder(services.BuildServiceProvider());
builder.UseConnectionHandler<TestConnectionHandler>();
var app = builder.Build();
var options = new HttpConnectionDispatcherOptions();
var context = MakeRequest("/foo", connection);
// Initial poll will complete immediately
await dispatcher.ExecuteAsync(context, options, app).OrTimeout();
var pollContext = MakeRequest("/foo", connection);
var pollTask = dispatcher.ExecuteAsync(pollContext, options, app);
// fail LongPollingTransport ReadAsync
connection.Transport.Output.Complete(new InvalidOperationException());
await pollTask.OrTimeout();
Assert.Equal(StatusCodes.Status500InternalServerError, pollContext.Response.StatusCode);
Assert.False(manager.TryGetConnection(connection.ConnectionId, out var _));
}
}
private class RejectHandler : TestAuthenticationHandler
{
protected override bool ShouldAccept => false;