-
Notifications
You must be signed in to change notification settings - Fork 521
Set StatusCode before disposing HttpContext (#876) #993
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,57 +92,83 @@ public override async Task RequestProcessingAsync() | |
var context = _application.CreateContext(this); | ||
try | ||
{ | ||
await _application.ProcessRequestAsync(context).ConfigureAwait(false); | ||
VerifyResponseContentLength(); | ||
} | ||
catch (Exception ex) | ||
{ | ||
ReportApplicationError(ex); | ||
} | ||
finally | ||
{ | ||
// Trigger OnStarting if it hasn't been called yet and the app hasn't | ||
// already failed. If an OnStarting callback throws we can go through | ||
// our normal error handling in ProduceEnd. | ||
// https://github.com/aspnet/KestrelHttpServer/issues/43 | ||
if (!HasResponseStarted && _applicationException == null && _onStarting != null) | ||
try | ||
{ | ||
await FireOnStarting(); | ||
await _application.ProcessRequestAsync(context).ConfigureAwait(false); | ||
VerifyResponseContentLength(); | ||
} | ||
catch (Exception ex) | ||
{ | ||
ReportApplicationError(ex); | ||
|
||
PauseStreams(); | ||
|
||
if (_onCompleted != null) | ||
if (ex is BadHttpRequestException) | ||
{ | ||
throw; | ||
} | ||
} | ||
finally | ||
{ | ||
await FireOnCompleted(); | ||
// Trigger OnStarting if it hasn't been called yet and the app hasn't | ||
// already failed. If an OnStarting callback throws we can go through | ||
// our normal error handling in ProduceEnd. | ||
// https://github.com/aspnet/KestrelHttpServer/issues/43 | ||
if (!HasResponseStarted && _applicationException == null && _onStarting != null) | ||
{ | ||
await FireOnStarting(); | ||
} | ||
|
||
PauseStreams(); | ||
|
||
if (_onCompleted != null) | ||
{ | ||
await FireOnCompleted(); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be sure to call I mentioned this in a previous iteration, but want to make sure it didn't get lost. |
||
|
||
_application.DisposeContext(context, _applicationException); | ||
} | ||
|
||
// If _requestAbort is set, the connection has already been closed. | ||
if (Volatile.Read(ref _requestAborted) == 0) | ||
{ | ||
ResumeStreams(); | ||
|
||
if (_keepAlive) | ||
// If _requestAbort is set, the connection has already been closed. | ||
if (Volatile.Read(ref _requestAborted) == 0) | ||
{ | ||
// Finish reading the request body in case the app did not. | ||
await messageBody.Consume(); | ||
ResumeStreams(); | ||
|
||
if (_keepAlive) | ||
{ | ||
// Finish reading the request body in case the app did not. | ||
await messageBody.Consume(); | ||
} | ||
|
||
// ProduceEnd() must be called before _application.DisposeContext(), to ensure | ||
// HttpContext.Response.StatusCode is correctly set when | ||
// IHttpContextFactory.Dispose(HttpContext) is called. | ||
await ProduceEnd(); | ||
} | ||
else if (!HasResponseStarted) | ||
{ | ||
// If the request was aborted and no response was sent, there's no | ||
// meaningful status code to log. | ||
StatusCode = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this interact with TryProduceInvalidRequestResponse()? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm thinking I should move |
||
} | ||
|
||
await ProduceEnd(); | ||
} | ||
|
||
StopStreams(); | ||
|
||
if (!_keepAlive) | ||
catch (BadHttpRequestException ex) | ||
{ | ||
// End the connection for non keep alive as data incoming may have been thrown off | ||
return; | ||
// Handle BadHttpRequestException thrown during app execution or remaining message body consumption. | ||
// This has to be caught here so StatusCode is set properly before disposing the HttpContext | ||
// (DisposeContext logs StatusCode). | ||
SetBadRequestState(ex); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add comment that this is for bad request data in the request body (not start line/headers) and SetBadRequestState can't be called later because _application.DisposeContext logs the status code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added comments. |
||
} | ||
finally | ||
{ | ||
_application.DisposeContext(context, _applicationException); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be called even if It will also probably require another finally block because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently, if the app calls What should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 503? Service Unavailable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @benaadams: I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One edge case currently not handled, is an app which calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not changing it to something related to it being aborted might confuse automated log parsing? |
||
} | ||
} | ||
|
||
StopStreams(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think StopStreams() should go in the finally? |
||
|
||
if (!_keepAlive) | ||
{ | ||
// End the connection for non keep alive as data incoming may have been thrown off | ||
return; | ||
} | ||
|
||
// Don't reset frame state if we're exiting the loop. This avoids losing request rejection | ||
// information (for 4xx response), and prevents ObjectDisposedException on HTTPS (ODEs | ||
// will be thrown if PrepareRequest is not null and references objects disposed on connection | ||
|
@@ -155,11 +181,9 @@ public override async Task RequestProcessingAsync() | |
} | ||
catch (BadHttpRequestException ex) | ||
{ | ||
if (!_requestRejected) | ||
{ | ||
// SetBadRequestState logs the error. | ||
SetBadRequestState(ex); | ||
} | ||
// Handle BadHttpRequestException thrown during request line or header parsing. | ||
// SetBadRequestState logs the error. | ||
SetBadRequestState(ex); | ||
} | ||
catch (Exception ex) | ||
{ | ||
|
@@ -169,11 +193,10 @@ public override async Task RequestProcessingAsync() | |
{ | ||
try | ||
{ | ||
await TryProduceInvalidRequestResponse(); | ||
|
||
// If _requestAborted is set, the connection has already been closed. | ||
if (Volatile.Read(ref _requestAborted) == 0) | ||
{ | ||
await TryProduceInvalidRequestResponse(); | ||
ConnectionControl.End(ProduceEndType.SocketShutdown); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't
_requestRejectedException
be set inRejectRequest
?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the appropriate place to set that.
Connection
callsSetBadRequestState()
when a time out occurs, and that will be picked up by later byTryProduceInvalidRequestResponse()
. Besides,_requestRejectedException
is state too.