Address PR feedback
This commit is contained in:
parent
7b315d2470
commit
8e818e3549
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
private bool _responseStarted;
|
private bool _responseStarted;
|
||||||
private bool _keepAlive;
|
private bool _keepAlive;
|
||||||
private bool _autoChunk;
|
private bool _autoChunk;
|
||||||
private bool _applicationFailed;
|
private Exception _applicationException;
|
||||||
|
|
||||||
public Frame(ConnectionContext context) : base(context)
|
public Frame(ConnectionContext context) : base(context)
|
||||||
{
|
{
|
||||||
|
|
@ -79,6 +79,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
_responseStarted = false;
|
_responseStarted = false;
|
||||||
_keepAlive = false;
|
_keepAlive = false;
|
||||||
_autoChunk = false;
|
_autoChunk = false;
|
||||||
|
_applicationException = null;
|
||||||
|
|
||||||
_requestHeaders.Reset();
|
_requestHeaders.Reset();
|
||||||
ResetResponseHeaders();
|
ResetResponseHeaders();
|
||||||
|
|
@ -183,10 +184,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Trigger FireOnStarting if ProduceStart hasn't been called yet.
|
// Trigger OnStarting if it hasn't been called yet and the app hasn't
|
||||||
// We call it here, so it can go through our normal error handling
|
// already failed. If an OnStarting callback throws we can go through
|
||||||
// and respond with a 500 if an OnStarting callback throws.
|
// our normal error handling in ProduceEnd.
|
||||||
if (!_responseStarted)
|
// https://github.com/aspnet/KestrelHttpServer/issues/43
|
||||||
|
if (!_responseStarted && _applicationException == null)
|
||||||
{
|
{
|
||||||
await FireOnStarting();
|
await FireOnStarting();
|
||||||
}
|
}
|
||||||
|
|
@ -260,16 +262,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
if (onStarting != null)
|
if (onStarting != null)
|
||||||
{
|
{
|
||||||
foreach (var entry in onStarting)
|
try
|
||||||
{
|
{
|
||||||
try
|
foreach (var entry in onStarting)
|
||||||
{
|
{
|
||||||
await entry.Key.Invoke(entry.Value);
|
await entry.Key.Invoke(entry.Value);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
catch (Exception ex)
|
||||||
ReportApplicationError(ex);
|
{
|
||||||
}
|
ReportApplicationError(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -419,9 +421,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
await FireOnStarting();
|
await FireOnStarting();
|
||||||
|
|
||||||
if (_applicationFailed)
|
if (_applicationException != null)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException(typeof(Frame).FullName);
|
throw new ObjectDisposedException(
|
||||||
|
"The response has been aborted due to an unhandled application exception.",
|
||||||
|
_applicationException);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ProduceStart(immediate, appCompleted: false);
|
await ProduceStart(immediate, appCompleted: false);
|
||||||
|
|
@ -444,12 +448,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
private async Task ProduceEnd()
|
private async Task ProduceEnd()
|
||||||
{
|
{
|
||||||
if (_applicationFailed)
|
if (_applicationException != null)
|
||||||
{
|
{
|
||||||
if (_responseStarted)
|
if (_responseStarted)
|
||||||
{
|
{
|
||||||
// We can no longer respond with a 500, so we simply close the connection.
|
// We can no longer respond with a 500, so we simply close the connection.
|
||||||
_keepAlive = false;
|
_requestProcessingStopping = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -457,10 +461,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
StatusCode = 500;
|
StatusCode = 500;
|
||||||
ReasonPhrase = null;
|
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;
|
|
||||||
|
|
||||||
ResetResponseHeaders();
|
ResetResponseHeaders();
|
||||||
_responseHeaders.HeaderContentLength = "0";
|
_responseHeaders.HeaderContentLength = "0";
|
||||||
}
|
}
|
||||||
|
|
@ -750,7 +750,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
private void ReportApplicationError(Exception ex)
|
private void ReportApplicationError(Exception ex)
|
||||||
{
|
{
|
||||||
_applicationFailed = true;
|
_applicationException = ex;
|
||||||
Log.ApplicationError(ex);
|
Log.ApplicationError(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -550,7 +550,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
[MemberData(nameof(ConnectionFilterData))]
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
public async Task ThrowingResultsIn500Response(ServiceContext testContext)
|
public async Task ThrowingResultsIn500Response(ServiceContext testContext)
|
||||||
{
|
{
|
||||||
var onStartingCallCount = 0;
|
bool onStartingCalled = false;
|
||||||
|
|
||||||
var testLogger = new TestApplicationErrorLogger();
|
var testLogger = new TestApplicationErrorLogger();
|
||||||
testContext.Log = new KestrelTrace(testLogger);
|
testContext.Log = new KestrelTrace(testLogger);
|
||||||
|
|
@ -560,7 +560,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
var response = frame.Get<IHttpResponseFeature>();
|
var response = frame.Get<IHttpResponseFeature>();
|
||||||
response.OnStarting(_ =>
|
response.OnStarting(_ =>
|
||||||
{
|
{
|
||||||
onStartingCallCount++;
|
onStartingCalled = true;
|
||||||
return Task.FromResult<object>(null);
|
return Task.FromResult<object>(null);
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
|
|
@ -597,7 +597,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
"",
|
"",
|
||||||
"");
|
"");
|
||||||
|
|
||||||
Assert.Equal(2, onStartingCallCount);
|
Assert.False(onStartingCalled);
|
||||||
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
|
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -760,7 +760,8 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
[MemberData(nameof(ConnectionFilterData))]
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
public async Task ThrowingInOnStartingResultsInFailedWritesAnd500Response(ServiceContext testContext)
|
public async Task ThrowingInOnStartingResultsInFailedWritesAnd500Response(ServiceContext testContext)
|
||||||
{
|
{
|
||||||
var onStartingCallCount = 0;
|
var onStartingCallCount1 = 0;
|
||||||
|
var onStartingCallCount2 = 0;
|
||||||
var failedWriteCount = 0;
|
var failedWriteCount = 0;
|
||||||
|
|
||||||
var testLogger = new TestApplicationErrorLogger();
|
var testLogger = new TestApplicationErrorLogger();
|
||||||
|
|
@ -768,19 +769,28 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
|
|
||||||
using (var server = new TestServer(async frame =>
|
using (var server = new TestServer(async frame =>
|
||||||
{
|
{
|
||||||
|
var onStartingException = new Exception();
|
||||||
|
|
||||||
var response = frame.Get<IHttpResponseFeature>();
|
var response = frame.Get<IHttpResponseFeature>();
|
||||||
response.OnStarting(_ =>
|
response.OnStarting(_ =>
|
||||||
{
|
{
|
||||||
onStartingCallCount++;
|
onStartingCallCount1++;
|
||||||
throw new Exception();
|
throw onStartingException;
|
||||||
|
}, null);
|
||||||
|
response.OnStarting(_ =>
|
||||||
|
{
|
||||||
|
onStartingCallCount2++;
|
||||||
|
throw onStartingException;
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
response.Headers.Clear();
|
response.Headers.Clear();
|
||||||
response.Headers["Content-Length"] = new[] { "11" };
|
response.Headers["Content-Length"] = new[] { "11" };
|
||||||
|
|
||||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () =>
|
var writeException = await Assert.ThrowsAsync<ObjectDisposedException>(async () =>
|
||||||
await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11));
|
await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11));
|
||||||
|
|
||||||
|
Assert.Same(onStartingException, writeException.InnerException);
|
||||||
|
|
||||||
failedWriteCount++;
|
failedWriteCount++;
|
||||||
}, testContext))
|
}, testContext))
|
||||||
{
|
{
|
||||||
|
|
@ -811,7 +821,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
"",
|
"",
|
||||||
"");
|
"");
|
||||||
|
|
||||||
Assert.Equal(2, onStartingCallCount);
|
Assert.Equal(2, onStartingCallCount1);
|
||||||
|
// The second OnStarting callback should not be called since the first failed.
|
||||||
|
Assert.Equal(0, onStartingCallCount2);
|
||||||
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
|
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -820,6 +832,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
[MemberData(nameof(ConnectionFilterData))]
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
public async Task ThrowingInOnCompletedIsLoggedAndClosesConnection(ServiceContext testContext)
|
public async Task ThrowingInOnCompletedIsLoggedAndClosesConnection(ServiceContext testContext)
|
||||||
{
|
{
|
||||||
|
var onCompletedCalled1 = false;
|
||||||
|
var onCompletedCalled2 = false;
|
||||||
|
|
||||||
var testLogger = new TestApplicationErrorLogger();
|
var testLogger = new TestApplicationErrorLogger();
|
||||||
testContext.Log = new KestrelTrace(testLogger);
|
testContext.Log = new KestrelTrace(testLogger);
|
||||||
|
|
||||||
|
|
@ -828,6 +843,12 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
var response = frame.Get<IHttpResponseFeature>();
|
var response = frame.Get<IHttpResponseFeature>();
|
||||||
response.OnCompleted(_ =>
|
response.OnCompleted(_ =>
|
||||||
{
|
{
|
||||||
|
onCompletedCalled1 = true;
|
||||||
|
throw new Exception();
|
||||||
|
}, null);
|
||||||
|
response.OnCompleted(_ =>
|
||||||
|
{
|
||||||
|
onCompletedCalled2 = true;
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
|
|
@ -850,7 +871,10 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
"Hello World");
|
"Hello World");
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal(1, testLogger.ApplicationErrorsLogged);
|
// All OnCompleted callbacks should be called even if they throw.
|
||||||
|
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
|
||||||
|
Assert.True(onCompletedCalled1);
|
||||||
|
Assert.True(onCompletedCalled2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue