Gracefully handle uncaught exceptions in user code when possible

This commit is contained in:
Stephen Halter 2015-07-13 15:55:37 -07:00
parent b2289b9a54
commit 4a9515d2e0
2 changed files with 84 additions and 1 deletions

View File

@ -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)

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
/// <summary>
/// Summary description for EngineTests
/// </summary>
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");
}
}
}
}
}