MockConnection Abort

This commit is contained in:
Ben Adams 2016-01-22 13:59:46 +00:00
parent 73bb0ab5b8
commit a97cb81f92
4 changed files with 38 additions and 9 deletions

View File

@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
} }
public void Abort() public virtual void Abort()
{ {
if (_frame != null) if (_frame != null)
{ {

View File

@ -45,6 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
// The number of write operations that have been scheduled so far // The number of write operations that have been scheduled so far
// but have not completed. // but have not completed.
private bool _writePending = false; private bool _writePending = false;
private bool _cancelled = false;
private int _numBytesPreCompleted = 0; private int _numBytesPreCompleted = 0;
private Exception _lastWriteError; private Exception _lastWriteError;
private WriteContext _nextWriteContext; private WriteContext _nextWriteContext;
@ -90,7 +91,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
lock (_contextLock) lock (_contextLock)
{ {
if (_lastWriteError != null || _socket.IsClosed) if (_socket.IsClosed)
{ {
_log.ConnectionDisconnectedWrite(_connectionId, buffer.Count, _lastWriteError); _log.ConnectionDisconnectedWrite(_connectionId, buffer.Count, _lastWriteError);
@ -164,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
_connection.Abort(); _connection.Abort();
_cancelled = true;
return TaskUtilities.GetCancelledTask(cancellationToken); return TaskUtilities.GetCancelledTask(cancellationToken);
} }
else else
@ -295,7 +296,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{ {
// Abort the connection for any failed write // Abort the connection for any failed write
// Queued on threadpool so get it in as first op. // Queued on threadpool so get it in as first op.
_connection?.Abort(); _connection.Abort();
_cancelled = true;
CompleteAllWrites(); CompleteAllWrites();
} }
@ -346,9 +348,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
} }
// This may called on the libuv event loop // This may called on the libuv event loop
// This is always called with the _contextLock already acquired
private void OnWriteCompleted(WriteContext writeContext) private void OnWriteCompleted(WriteContext writeContext)
{ {
// Called inside _contextLock
var bytesWritten = writeContext.ByteCount; var bytesWritten = writeContext.ByteCount;
var status = writeContext.WriteStatus; var status = writeContext.WriteStatus;
var error = writeContext.WriteError; var error = writeContext.WriteError;
@ -358,6 +360,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
// Abort the connection for any failed write // Abort the connection for any failed write
// Queued on threadpool so get it in as first op. // Queued on threadpool so get it in as first op.
_connection.Abort(); _connection.Abort();
_cancelled = true;
_lastWriteError = error; _lastWriteError = error;
} }
@ -381,6 +384,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
private void CompleteNextWrite(ref int bytesLeftToBuffer) private void CompleteNextWrite(ref int bytesLeftToBuffer)
{ {
// Called inside _contextLock
var waitingTask = _tasksPending.Dequeue(); var waitingTask = _tasksPending.Dequeue();
var bytesToWrite = waitingTask.BytesToWrite; var bytesToWrite = waitingTask.BytesToWrite;
@ -416,6 +420,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
private void CompleteFinishedWrites(int status) private void CompleteFinishedWrites(int status)
{ {
// Called inside _contextLock
// bytesLeftToBuffer can be greater than _maxBytesPreCompleted // bytesLeftToBuffer can be greater than _maxBytesPreCompleted
// This allows large writes to complete once they've actually finished. // This allows large writes to complete once they've actually finished.
var bytesLeftToBuffer = _maxBytesPreCompleted - _numBytesPreCompleted; var bytesLeftToBuffer = _maxBytesPreCompleted - _numBytesPreCompleted;
@ -428,6 +433,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
private void CompleteAllWrites() private void CompleteAllWrites()
{ {
// Called inside _contextLock
var writesToComplete = _tasksPending.Count > 0; var writesToComplete = _tasksPending.Count > 0;
var bytesLeftToBuffer = _maxBytesPreCompleted - _numBytesPreCompleted; var bytesLeftToBuffer = _maxBytesPreCompleted - _numBytesPreCompleted;
while (_tasksPending.Count > 0) while (_tasksPending.Count > 0)
@ -468,7 +474,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
private void PoolWriteContext(WriteContext writeContext) private void PoolWriteContext(WriteContext writeContext)
{ {
// called inside _contextLock // Called inside _contextLock
if (_writeContextPool.Count < _maxPooledWriteContexts) if (_writeContextPool.Count < _maxPooledWriteContexts)
{ {
writeContext.Reset(); writeContext.Reset();
@ -485,9 +491,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
_connection?.Abort(); _connection.Abort();
_cancelled = true;
return TaskUtilities.GetCancelledTask(cancellationToken); return TaskUtilities.GetCancelledTask(cancellationToken);
} }
else if (_cancelled)
{
return TaskUtilities.CompletedTask;
}
return WriteAsync(buffer, cancellationToken, immediate, chunk); return WriteAsync(buffer, cancellationToken, immediate, chunk);
} }

View File

@ -0,0 +1,18 @@
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Networking;
namespace Microsoft.AspNet.Server.KestrelTests.TestHelpers
{
public class MockConnection : Connection
{
public MockConnection(UvStreamHandle socket)
: base (new ListenerContext(), socket)
{
}
public override void Abort()
{
}
}
}

View File

@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace()); var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
var trace = new KestrelTrace(new TestKestrelTrace()); var trace = new KestrelTrace(new TestKestrelTrace());
var ltp = new LoggingThreadPool(trace); var ltp = new LoggingThreadPool(trace);
ISocketOutput socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>()); ISocketOutput socketOutput = new SocketOutput(kestrelThread, socket, memory, new MockConnection(socket), 0, trace, ltp, new Queue<UvWriteReq>());
var bufferSize = maxBytesPreCompleted; var bufferSize = maxBytesPreCompleted;
@ -302,7 +302,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
Assert.False(task6Throw.IsCanceled); Assert.False(task6Throw.IsCanceled);
Assert.False(task6Throw.IsFaulted); Assert.False(task6Throw.IsFaulted);
Assert.Throws<TaskCanceledException>(() => task6Throw.GetAwaiter().GetResult()); task6Throw.GetAwaiter().GetResult();
Assert.True(true); Assert.True(true);
} }