Gracefully handle uncaught exceptions in user code when possible
This commit is contained in:
parent
b2289b9a54
commit
4a9515d2e0
|
|
@ -317,6 +317,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
public void ProduceEnd(Exception ex)
|
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();
|
ProduceStart();
|
||||||
|
|
||||||
if (!_keepAlive)
|
if (!_keepAlive)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Summary description for EngineTests
|
/// Summary description for EngineTests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class EngineTests
|
public class EngineTests
|
||||||
{
|
{
|
||||||
private async Task App(Frame frame)
|
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)
|
private async Task AppChunked(Frame frame)
|
||||||
{
|
{
|
||||||
var data = new MemoryStream();
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue