Throw IOExceptions instead of ODEs after a request is aborted

This commit is contained in:
Stephen Halter 2015-11-03 14:02:28 -08:00
parent 062caf16be
commit 874bd29ce1
4 changed files with 59 additions and 2 deletions

View File

@ -183,8 +183,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_requestProcessingStopping = true; _requestProcessingStopping = true;
_requestAborted = true; _requestAborted = true;
_requestBody?.StopAcceptingReads(); _requestBody?.Abort();
_responseBody?.StopAcceptingWrites(); _responseBody?.Abort();
try try
{ {

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
private readonly MessageBody _body; private readonly MessageBody _body;
private bool _stopped; private bool _stopped;
private bool _aborted;
public FrameRequestStream(MessageBody body) public FrameRequestStream(MessageBody body)
{ {
@ -55,6 +56,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameRequestStream)); throw new ObjectDisposedException(nameof(FrameRequestStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
return ReadAsync(buffer, offset, count).GetAwaiter().GetResult(); return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
} }
@ -66,6 +71,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameRequestStream)); throw new ObjectDisposedException(nameof(FrameRequestStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
var task = ReadAsync(buffer, offset, count, CancellationToken.None, state); var task = ReadAsync(buffer, offset, count, CancellationToken.None, state);
if (callback != null) if (callback != null)
@ -86,6 +95,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameRequestStream)); throw new ObjectDisposedException(nameof(FrameRequestStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
var tcs = new TaskCompletionSource<int>(state); var tcs = new TaskCompletionSource<int>(state);
var task = _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken); var task = _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken);
@ -111,6 +124,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{ {
if (_stopped)
{
throw new ObjectDisposedException(nameof(FrameRequestStream));
}
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
return _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken); return _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken);
} }
@ -125,5 +147,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
// As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes // As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
_stopped = true; _stopped = true;
} }
public void Abort()
{
// We don't want to throw an ODE until the app func actually completes.
// If the request is aborted, we throw an IOException instead.
_aborted = true;
}
} }
} }

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
private readonly FrameContext _context; private readonly FrameContext _context;
private bool _stopped; private bool _stopped;
private bool _aborted;
public FrameResponseStream(FrameContext context) public FrameResponseStream(FrameContext context)
{ {
@ -40,6 +41,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameResponseStream)); throw new ObjectDisposedException(nameof(FrameResponseStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
_context.FrameControl.Flush(); _context.FrameControl.Flush();
} }
@ -50,6 +55,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameResponseStream)); throw new ObjectDisposedException(nameof(FrameResponseStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
return _context.FrameControl.FlushAsync(cancellationToken); return _context.FrameControl.FlushAsync(cancellationToken);
} }
@ -75,6 +84,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameResponseStream)); throw new ObjectDisposedException(nameof(FrameResponseStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
_context.FrameControl.Write(new ArraySegment<byte>(buffer, offset, count)); _context.FrameControl.Write(new ArraySegment<byte>(buffer, offset, count));
} }
@ -85,6 +98,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
throw new ObjectDisposedException(nameof(FrameResponseStream)); throw new ObjectDisposedException(nameof(FrameResponseStream));
} }
if (_aborted)
{
throw new IOException("The request has been aborted.");
}
return _context.FrameControl.WriteAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken); return _context.FrameControl.WriteAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken);
} }
@ -95,5 +112,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
// As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes // As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
_stopped = true; _stopped = true;
} }
public void Abort()
{
// We don't want to throw an ODE until the app func actually completes.
// If the request is aborted, we throw an IOException instead.
_aborted = true;
}
} }
} }

View File

@ -51,6 +51,10 @@ namespace Microsoft.AspNet.Server.KestrelTests
{ {
} }
public void Abort()
{
}
public void Write(ArraySegment<byte> data, Action<Exception, object> callback, object state) public void Write(ArraySegment<byte> data, Action<Exception, object> callback, object state)
{ {
} }