Harden framing epilog
* Connection no longer needes Frame's processing Task * Any exceptions from unusual processing is logged
This commit is contained in:
parent
28250d9981
commit
30ec2cb0b1
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
SocketInput = new SocketInput(Memory2);
|
SocketInput = new SocketInput(Memory2);
|
||||||
SocketOutput = new SocketOutput(Thread, _socket, _connectionId, Log);
|
SocketOutput = new SocketOutput(Thread, _socket, _connectionId, Log);
|
||||||
_frame = new Frame(this);
|
_frame = new Frame(this);
|
||||||
_frameTask = Task.Run(_frame.ProcessFraming);
|
Task.Run(_frame.ProcessFraming);
|
||||||
_socket.ReadStart(_allocCallback, _readCallback, this);
|
_socket.ReadStart(_allocCallback, _readCallback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
|
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
|
||||||
|
using Microsoft.Framework.Logging;
|
||||||
using Microsoft.Framework.Primitives;
|
using Microsoft.Framework.Primitives;
|
||||||
|
|
||||||
// ReSharper disable AccessToModifiedClosure
|
// ReSharper disable AccessToModifiedClosure
|
||||||
|
|
@ -98,73 +99,90 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
_responseHeaders.HeaderDate = DateTime.UtcNow.ToString("r");
|
_responseHeaders.HeaderDate = DateTime.UtcNow.ToString("r");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ProcessFraming()
|
public async void ProcessFraming()
|
||||||
{
|
{
|
||||||
var terminated = false;
|
try
|
||||||
while (!terminated)
|
|
||||||
{
|
{
|
||||||
while (!terminated && !TakeStartLine(SocketInput))
|
var terminated = false;
|
||||||
|
while (!terminated)
|
||||||
{
|
{
|
||||||
terminated = SocketInput.RemoteIntakeFin;
|
while (!terminated && !TakeStartLine(SocketInput))
|
||||||
if (!terminated)
|
|
||||||
{
|
{
|
||||||
await SocketInput;
|
terminated = SocketInput.RemoteIntakeFin;
|
||||||
}
|
if (!terminated)
|
||||||
}
|
|
||||||
|
|
||||||
while (!terminated && !TakeMessageHeaders(SocketInput))
|
|
||||||
{
|
|
||||||
terminated = SocketInput.RemoteIntakeFin;
|
|
||||||
if (!terminated)
|
|
||||||
{
|
|
||||||
await SocketInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!terminated)
|
|
||||||
{
|
|
||||||
MessageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
|
|
||||||
_keepAlive = MessageBody.RequestKeepAlive;
|
|
||||||
RequestBody = new FrameRequestStream(MessageBody);
|
|
||||||
ResponseBody = new FrameResponseStream(this);
|
|
||||||
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
|
|
||||||
|
|
||||||
Exception error = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Application.Invoke(this).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// Trigger FireOnStarting if ProduceStart hasn't been called yet.
|
|
||||||
// We call it here, so it can go through our normal error handling
|
|
||||||
// and respond with a 500 if an OnStarting callback throws.
|
|
||||||
if (!_responseStarted)
|
|
||||||
{
|
{
|
||||||
FireOnStarting();
|
await SocketInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
while (!terminated && !TakeMessageHeaders(SocketInput))
|
||||||
{
|
{
|
||||||
error = ex;
|
terminated = SocketInput.RemoteIntakeFin;
|
||||||
}
|
if (!terminated)
|
||||||
finally
|
{
|
||||||
{
|
await SocketInput;
|
||||||
FireOnCompleted();
|
}
|
||||||
ProduceEnd(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
terminated = !_keepAlive;
|
if (!terminated)
|
||||||
|
{
|
||||||
|
MessageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
|
||||||
|
_keepAlive = MessageBody.RequestKeepAlive;
|
||||||
|
RequestBody = new FrameRequestStream(MessageBody);
|
||||||
|
ResponseBody = new FrameResponseStream(this);
|
||||||
|
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
|
||||||
|
|
||||||
|
Exception error = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Application.Invoke(this).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Trigger FireOnStarting if ProduceStart hasn't been called yet.
|
||||||
|
// We call it here, so it can go through our normal error handling
|
||||||
|
// and respond with a 500 if an OnStarting callback throws.
|
||||||
|
if (!_responseStarted)
|
||||||
|
{
|
||||||
|
FireOnStarting();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
error = ex;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FireOnCompleted();
|
||||||
|
ProduceEnd(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
terminated = !_keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Reset();
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.LogVerbose("Connection processing ended abnormally", ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Inform client no more data will ever arrive
|
||||||
|
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
|
||||||
|
|
||||||
// Connection Terminated!
|
// Wait for client to either disconnect or send unexpected data
|
||||||
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
|
await SocketInput;
|
||||||
|
|
||||||
// Wait for client to disconnect, or to receive unexpected data
|
// Dispose socket
|
||||||
await SocketInput;
|
ConnectionControl.End(ProduceEndType.SocketDisconnect);
|
||||||
|
}
|
||||||
ConnectionControl.End(ProduceEndType.SocketDisconnect);
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Log.LogVerbose("Connection shutdown abnormally", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnStarting(Func<object, Task> callback, object state)
|
public void OnStarting(Func<object, Task> callback, object state)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue