diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index c21f6b7b84..4f66998345 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -317,6 +317,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Http public void ProduceEnd(Exception ex) { + if (ex != null) + { + if (_resultStarted) + { + // We can no longer respond with a 500, so we simply close the connection. + ConnectionControl.End(ProduceEndType.SocketDisconnect); + return; + } + else + { + StatusCode = 500; + ReasonPhrase = null; + + // If OnStarting hasn't been triggered yet, we don't want to trigger it now that + // the app func has failed. https://github.com/aspnet/KestrelHttpServer/issues/43 + _onStarting = null; + + ResponseHeaders.Clear(); + ResponseHeaders["Content-Length"] = new[] { "0" }; + } + } + ProduceStart(); if (!_keepAlive) diff --git a/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs index 6b9ed7c728..9c65ea36c1 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/EngineTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Server.KestrelTests /// /// Summary description for EngineTests /// - internal class EngineTests + public class EngineTests { private async Task App(Frame frame) { @@ -57,6 +57,20 @@ namespace Microsoft.AspNet.Server.KestrelTests } } + private async Task AppThatThrows(Frame frame) + { + // Anything added to the ResponseHeaders dictionary is ignored + frame.ResponseHeaders["Content-Length"] = new[] { "11" }; + throw new Exception(); + } + + private async Task AppThatThrowsAfterWrite(Frame frame) + { + frame.ResponseHeaders["Content-Length"] = new[] { "11" }; + await frame.ResponseBody.WriteAsync(Encoding.UTF8.GetBytes("Hello World"), 0, 11); + throw new Exception(); + } + private async Task AppChunked(Frame frame) { var data = new MemoryStream(); @@ -343,5 +357,52 @@ namespace Microsoft.AspNet.Server.KestrelTests } } } + + [Fact] + public async Task ThrowingResultsIn500Response() + { + using (var server = new TestServer(AppThatThrows)) + { + using (var connection = new TestConnection()) + { + await connection.SendEnd( + "GET / HTTP/1.1", + "", + "GET / HTTP/1.1", + "Connection: close", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 500 Internal Server Error", + "Content-Length: 0", + "", + "HTTP/1.1 500 Internal Server Error", + "Content-Length: 0", + "Connection: close", + "", + ""); + } + } + } + + [Fact] + public async Task ThrowingAfterWritingKillsConnection() + { + using (var server = new TestServer(AppThatThrowsAfterWrite)) + { + using (var connection = new TestConnection()) + { + await connection.Send( + "GET / HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + "Content-Length: 11", + "", + "Hello World"); + } + } + } } }