From f60f6c92ca8939f20e9e17c5df3677ddf604af76 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 1 Nov 2015 09:50:24 +0000 Subject: [PATCH] Stop streams on finish Can't use dispose (or close) as can be disposed too early by user code Resolves #263 --- .../Http/Frame.cs | 9 +++++-- .../Http/FrameRequestStream.cs | 21 +++++++++++++++ .../Http/FrameResponseStream.cs | 26 +++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index bf6b821d3e..104fc6c1d9 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -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; diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameRequestStream.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameRequestStream.cs index be3ac5d225..90ebe8601e 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameRequestStream.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameRequestStream.cs @@ -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 ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state) { + if (_stopped) + { + throw new ObjectDisposedException("RequestStream has been disposed"); + } + var tcs = new TaskCompletionSource(state); var task = _body.ReadAsync(new ArraySegment(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; + } } } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs index 631c106045..813ef23ba4 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/FrameResponseStream.cs @@ -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(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(buffer, offset, count), cancellationToken); } + + public void StopAcceptingWrites() + { + _stopped = true; + } } }