Merge branch 'benaadams/statemachines' into dev

This commit is contained in:
Stephen Halter 2015-12-07 00:07:14 -08:00
commit 706ff04160
2 changed files with 84 additions and 22 deletions

View File

@ -44,9 +44,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
protected readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders();
private List<KeyValuePair<Func<object, Task>, object>> _onStarting;
protected List<KeyValuePair<Func<object, Task>, object>> _onStarting;
private List<KeyValuePair<Func<object, Task>, object>> _onCompleted;
protected List<KeyValuePair<Func<object, Task>, object>> _onCompleted;
private bool _requestProcessingStarted;
private Task _requestProcessingTask;
@ -144,8 +144,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
// If a request abort token was previously explicitly set, return it.
if (_manuallySetRequestAbortToken.HasValue)
{
return _manuallySetRequestAbortToken.Value;
}
// Otherwise, get the abort CTS. If we have one, which would mean that someone previously
// asked for the RequestAborted token, simply return its token. If we don't,
// check to see whether we've already aborted, in which case just return an
@ -416,7 +417,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
public async Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
public Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationToken)
{
if (!_responseStarted)
{
return WriteAsyncAwaited(data, cancellationToken);
}
if (_autoChunk)
{
if (data.Count == 0)
{
return TaskUtilities.CompletedTask;
}
return WriteChunkedAsync(data, cancellationToken);
}
else
{
return SocketOutput.WriteAsync(data, immediate: true, cancellationToken: cancellationToken);
}
}
public async Task WriteAsyncAwaited(ArraySegment<byte> data, CancellationToken cancellationToken)
{
await ProduceStartAndFireOnStarting(immediate: false);
@ -501,10 +523,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
public async Task ProduceStartAndFireOnStarting(bool immediate = true)
public Task ProduceStartAndFireOnStarting(bool immediate = true)
{
if (_responseStarted) return;
if (_responseStarted) return TaskUtilities.CompletedTask;
if (_onStarting != null)
{
return FireOnStartingProduceStart(immediate: immediate);
}
if (_applicationException != null)
{
throw new ObjectDisposedException(
"The response has been aborted due to an unhandled application exception.",
_applicationException);
}
return ProduceStart(immediate, appCompleted: false);
}
private async Task FireOnStartingProduceStart(bool immediate)
{
await FireOnStarting();
if (_applicationException != null)
@ -527,7 +566,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return CreateResponseHeader(statusBytes, appCompleted, immediate);
}
protected async Task ProduceEnd()
protected Task ProduceEnd()
{
if (_applicationException != null)
{
@ -535,7 +574,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
// We can no longer respond with a 500, so we simply close the connection.
_requestProcessingStopping = true;
return;
return TaskUtilities.CompletedTask;
}
else
{
@ -547,8 +586,26 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
if (!_responseStarted)
{
return ProduceEndAwaited();
}
WriteSuffix();
return TaskUtilities.CompletedTask;
}
private async Task ProduceEndAwaited()
{
await ProduceStart(immediate: true, appCompleted: true);
WriteSuffix();
}
private void WriteSuffix()
{
// _autoChunk should be checked after we are sure ProduceStart() has been called
// since ProduceStart() may set _autoChunk to true.
if (_autoChunk)

View File

@ -40,28 +40,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
try
{
var terminated = false;
while (!terminated && !_requestProcessingStopping)
while (!_requestProcessingStopping)
{
while (!terminated && !_requestProcessingStopping && !TakeStartLine(SocketInput))
while (!_requestProcessingStopping && !TakeStartLine(SocketInput))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
if (SocketInput.RemoteIntakeFin)
{
await SocketInput;
return;
}
await SocketInput;
}
while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
while (!_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
if (SocketInput.RemoteIntakeFin)
{
await SocketInput;
return;
}
await SocketInput;
}
if (!terminated && !_requestProcessingStopping)
if (!_requestProcessingStopping)
{
var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
_keepAlive = messageBody.RequestKeepAlive;
@ -89,12 +88,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
// 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 (!_responseStarted && _applicationException == null)
if (!_responseStarted && _applicationException == null && _onStarting != null)
{
await FireOnStarting();
}
await FireOnCompleted();
if (_onCompleted != null)
{
await FireOnCompleted();
}
_application.DisposeContext(context, _applicationException);
@ -114,7 +116,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_responseBody.StopAcceptingWrites();
}
terminated = !_keepAlive;
if (!_keepAlive)
{
return;
}
}
Reset();