Stop streams on finish

Can't use dispose (or close) as can be disposed too early by user code

Resolves #263
This commit is contained in:
Ben Adams 2015-11-01 09:50:24 +00:00 committed by Stephen Halter
parent 8c0a1701cd
commit f60f6c92ca
3 changed files with 54 additions and 2 deletions

View File

@ -204,8 +204,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
MessageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
_keepAlive = MessageBody.RequestKeepAlive;
RequestBody = new FrameRequestStream(MessageBody);
ResponseBody = new FrameResponseStream(this);
var requestBody = new FrameRequestStream(MessageBody);
RequestBody = requestBody;
var responseBody = new FrameResponseStream(this);
ResponseBody = responseBody;
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
var httpContext = HttpContextFactory.Create(this);
@ -236,6 +238,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
// Finish reading the request body in case the app did not.
await MessageBody.Consume();
requestBody.StopAcceptingReads();
responseBody.StopAcceptingWrites();
}
terminated = !_keepAlive;

View File

@ -11,6 +11,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public class FrameRequestStream : Stream
{
private readonly MessageBody _body;
private bool _stopped;
public FrameRequestStream(MessageBody body)
{
@ -50,12 +51,22 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public override int Read(byte[] buffer, int offset, int count)
{
if (_stopped)
{
throw new ObjectDisposedException("RequestStream has been disposed");
}
return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
}
#if NET451
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
if (_stopped)
{
throw new ObjectDisposedException("RequestStream has been disposed");
}
var task = ReadAsync(buffer, offset, count, CancellationToken.None, state);
if (callback != null)
{
@ -71,6 +82,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
{
if (_stopped)
{
throw new ObjectDisposedException("RequestStream has been disposed");
}
var tcs = new TaskCompletionSource<int>(state);
var task = _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken);
task.ContinueWith((task2, state2) =>
@ -102,5 +118,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
throw new NotImplementedException();
}
public void StopAcceptingReads()
{
_stopped = true;
}
}
}

View File

@ -11,6 +11,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
class FrameResponseStream : Stream
{
private readonly FrameContext _context;
private bool _stopped;
public FrameResponseStream(FrameContext context)
{
@ -35,11 +36,21 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public override void Flush()
{
if (_stopped)
{
throw new ObjectDisposedException("ResponseStream has been disposed");
}
_context.FrameControl.Flush();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
if (_stopped)
{
throw new ObjectDisposedException("ResponseStream has been disposed");
}
return _context.FrameControl.FlushAsync(cancellationToken);
}
@ -60,12 +71,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public override void Write(byte[] buffer, int offset, int count)
{
if (_stopped)
{
throw new ObjectDisposedException("ResponseStream has been disposed");
}
_context.FrameControl.Write(new ArraySegment<byte>(buffer, offset, count));
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
if (_stopped)
{
throw new ObjectDisposedException("ResponseStream has been disposed");
}
return _context.FrameControl.WriteAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken);
}
public void StopAcceptingWrites()
{
_stopped = true;
}
}
}