Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class Connection : ConnectionContext, IConnectionControl
{
private static readonly Action<UvStreamHandle, int, object> _readCallback = ReadCallback;
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
private static readonly Action<UvStreamHandle, int, object> _readCallback = (handle, status, state) => ReadCallback(handle, status, state);
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = (handle, size, state) => AllocCallback(handle, size, state);

private static long _lastConnectionId;

Expand Down Expand Up @@ -72,12 +72,12 @@ public void Start()
if (task.IsFaulted)
{
connection.Log.LogError("ConnectionFilter.OnConnection", task.Exception);
ConnectionControl.End(ProduceEndType.SocketDisconnect);
connection.ConnectionControl.End(ProduceEndType.SocketDisconnect);
}
else if (task.IsCanceled)
{
connection.Log.LogError("ConnectionFilter.OnConnection Canceled");
ConnectionControl.End(ProduceEndType.SocketDisconnect);
connection.ConnectionControl.End(ProduceEndType.SocketDisconnect);
}
else
{
Expand Down
28 changes: 22 additions & 6 deletions src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public async Task RequestProcessingAsync()
}
}

while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput))
while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
Expand Down Expand Up @@ -196,6 +196,9 @@ public async Task RequestProcessingAsync()
await FireOnCompleted();

await ProduceEnd();

// Finish reading the request body in case the app did not.
await RequestBody.CopyToAsync(Stream.Null);
}

terminated = !_keepAlive;
Expand Down Expand Up @@ -654,7 +657,7 @@ static string GetString(ArraySegment<byte> range, int startIndex, int endIndex)
return Encoding.UTF8.GetString(range.Array, range.Offset + startIndex, endIndex - startIndex);
}

private bool TakeMessageHeaders(SocketInput input)
public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders requestHeaders)
{
var scan = input.ConsumingStart();
var consumed = scan;
Expand Down Expand Up @@ -692,6 +695,22 @@ private bool TakeMessageHeaders(SocketInput input)
chSecond == '\r' ||
chSecond == '\n')
{
if (chSecond == '\r')
{
var scanAhead = scan;
var chAhead = scanAhead.Take();
if (chAhead == '\n')
{
chAhead = scanAhead.Take();
// If the "\r\n" isn't part of "linear whitespace",
// then this header has no value.
if (chAhead != ' ' && chAhead != '\t')
{
break;
}
}
}

beginValue = scan;
chSecond = scan.Take();
}
Expand Down Expand Up @@ -729,17 +748,14 @@ private bool TakeMessageHeaders(SocketInput input)
}

var name = beginName.GetArraySegment(endName);
#if DEBUG
var nameString = beginName.GetString(endName);
#endif
var value = beginValue.GetString(endValue);
if (wrapping)
{
value = value.Replace("\r\n", " ");
}

consumed = scan;
_requestHeaders.Append(name.Array, name.Offset, name.Count, value);
requestHeaders.Append(name.Array, name.Offset, name.Count, value);
break;
}
}
Expand Down
31 changes: 16 additions & 15 deletions src/Microsoft.AspNet.Server.Kestrel/Http/Listener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.Extensions.Logging;

Expand All @@ -20,7 +21,7 @@ protected Listener(ServiceContext serviceContext)

protected UvStreamHandle ListenSocket { get; private set; }

public Task StartAsync(
public StateCompletionSource<Listener, int> StartAsync(
ServerAddress address,
KestrelThread thread,
Func<Frame, Task> application)
Expand All @@ -29,20 +30,20 @@ public Task StartAsync(
Thread = thread;
Application = application;

var tcs = new TaskCompletionSource<int>();
Thread.Post(_ =>
var scs = new StateCompletionSource<Listener, int>(this);
Thread.Post(scs2 =>
{
try
{
ListenSocket = CreateListenSocket();
tcs.SetResult(0);
scs2.State.ListenSocket = scs2.State.CreateListenSocket();
scs2.SetResult(0);
}
catch (Exception ex)
{
tcs.SetException(ex);
scs2.SetException(ex);
}
}, null);
return tcs.Task;
}, scs);
return scs;
}

/// <summary>
Expand Down Expand Up @@ -84,24 +85,24 @@ public void Dispose()
// the exception that stopped the event loop will never be surfaced.
if (Thread.FatalError == null && ListenSocket != null)
{
var tcs = new TaskCompletionSource<int>();
var scs = new StateCompletionSource<UvStreamHandle, int>(ListenSocket);
Thread.Post(
_ =>
scs2 =>
{
try
{
ListenSocket.Dispose();
tcs.SetResult(0);
scs2.State.Dispose();
scs2.SetResult(0);
}
catch (Exception ex)
{
tcs.SetException(ex);
scs2.SetException(ex);
}
},
null);
scs);

// REVIEW: Should we add a timeout here to be safe?
tcs.Task.Wait();
scs.Wait();
}

ListenSocket = null;
Expand Down
20 changes: 13 additions & 7 deletions src/Microsoft.AspNet.Server.Kestrel/Http/ListenerPrimary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,21 @@ public async Task StartAsync(
KestrelThread thread,
Func<Frame, Task> application)
{
await StartAsync(address, thread, application).ConfigureAwait(false);
await StartAsync(address, thread, application);

await Thread.PostAsync(_ =>
await Thread.PostAsync(listener =>
{
ListenPipe = new UvPipeHandle(Log);
ListenPipe.Init(Thread.Loop, false);
ListenPipe.Bind(pipeName);
ListenPipe.Listen(Constants.ListenBacklog, OnListenPipe, null);
}, null).ConfigureAwait(false);
listener.ListenPipe = new UvPipeHandle(listener.Log);
listener.ListenPipe.Init(listener.Thread.Loop, false);
listener.ListenPipe.Bind(pipeName);
listener.ListenPipe.Listen(
Constants.ListenBacklog,
(pipe, status, error, state) =>
{
((ListenerPrimary)state).OnListenPipe(pipe, status, error, state);
},
listener);
}, this).ConfigureAwait(false);
}

private void OnListenPipe(UvStreamHandle pipe, int status, Exception error, object state)
Expand Down
75 changes: 42 additions & 33 deletions src/Microsoft.AspNet.Server.Kestrel/Http/ListenerSecondary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext

UvPipeHandle DispatchPipe { get; set; }

public Task StartAsync(
public async Task StartAsync(
string pipeName,
ServerAddress address,
KestrelThread thread,
Expand All @@ -34,89 +34,98 @@ public Task StartAsync(

DispatchPipe = new UvPipeHandle(Log);

var tcs = new TaskCompletionSource<int>();
Thread.Post(_ =>
var qscs = new QuadStateCompletionSource<ListenerSecondary, string, IntPtr, Libuv.uv_buf_t, int>(this, pipeName);
Thread.Post(qscs2 =>
{
try
{
DispatchPipe.Init(Thread.Loop, true);
var connect = new UvConnectRequest(Log);
connect.Init(Thread.Loop);
var listener = qscs2.State1;
listener.DispatchPipe.Init(listener.Thread.Loop, true);
var connect = new UvConnectRequest(listener.Log);
connect.Init(listener.Thread.Loop);
connect.Connect(
DispatchPipe,
pipeName,
listener.DispatchPipe,
qscs2.State2,
(connect2, status, error, state) =>
{
connect.Dispose();
var qscs3 = (QuadStateCompletionSource<ListenerSecondary, string, IntPtr, Libuv.uv_buf_t, int>)state;
var listener2 = qscs3.State1;
connect2.Dispose();
if (error != null)
{
tcs.SetException(error);
qscs3.SetException(error);
return;
}

try
{
var ptr = Marshal.AllocHGlobal(4);
var buf = Thread.Loop.Libuv.buf_init(ptr, 4);
var buf = listener2.Thread.Loop.Libuv.buf_init(ptr, 4);

DispatchPipe.ReadStart(
(_1, _2, _3) => buf,
(_1, status2, state2) =>
qscs3.State3 = ptr;
qscs3.State4 = buf;

listener2.DispatchPipe.ReadStart(
(handle, status2, state2) => ((QuadStateCompletionSource<ListenerSecondary, string, IntPtr, Libuv.uv_buf_t, int>)state2).State4,
(handle, status2, state2) =>
{
var qscs4 = (QuadStateCompletionSource<ListenerSecondary, string, IntPtr, Libuv.uv_buf_t, int>)state2;
var listener3 = qscs4.State1;
if (status2 < 0)
{
if (status2 != Constants.EOF)
{
Exception ex;
Thread.Loop.Libuv.Check(status2, out ex);
Log.LogError("DispatchPipe.ReadStart", ex);
listener3.Thread.Loop.Libuv.Check(status2, out ex);
listener3.Log.LogError("DispatchPipe.ReadStart", ex);
}

DispatchPipe.Dispose();
Marshal.FreeHGlobal(ptr);
listener3.DispatchPipe.Dispose();
Marshal.FreeHGlobal(qscs4.State3);
return;
}

if (DispatchPipe.PendingCount() == 0)
if (listener3.DispatchPipe.PendingCount() == 0)
{
return;
}

var acceptSocket = CreateAcceptSocket();
var acceptSocket = listener3.CreateAcceptSocket();

try
{
DispatchPipe.Accept(acceptSocket);
listener3.DispatchPipe.Accept(acceptSocket);
}
catch (UvException ex)
{
Log.LogError("DispatchPipe.Accept", ex);
listener3.Log.LogError("DispatchPipe.Accept", ex);
acceptSocket.Dispose();
return;
}

var connection = new Connection(this, acceptSocket);
var connection = new Connection(listener3, acceptSocket);
connection.Start();
},
null);
qscs3);

tcs.SetResult(0);
qscs3.SetResult(0);
}
catch (Exception ex)
{
DispatchPipe.Dispose();
tcs.SetException(ex);
listener2.DispatchPipe.Dispose();
qscs3.SetException(ex);
}
},
null);
qscs2);
}
catch (Exception ex)
{
DispatchPipe.Dispose();
tcs.SetException(ex);
qscs2.State1.DispatchPipe.Dispose();
qscs2.SetException(ex);
}
}, null);
return tcs.Task;
}, qscs);
await qscs;
return;
}

/// <summary>
Expand All @@ -132,7 +141,7 @@ public void Dispose()
// the exception that stopped the event loop will never be surfaced.
if (Thread.FatalError == null)
{
Thread.Send(_ => DispatchPipe.Dispose(), null);
Thread.Send(listener => ((ListenerSecondary)listener).DispatchPipe.Dispose(), this);
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/Microsoft.AspNet.Server.Kestrel/Http/PipeListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ protected override UvStreamHandle CreateListenSocket()
var socket = new UvPipeHandle(Log);
socket.Init(Thread.Loop, false);
socket.Bind(ServerAddress.UnixPipePath);
socket.Listen(Constants.ListenBacklog, ConnectionCallback, this);
socket.Listen(
Constants.ListenBacklog,
(stream, status, error, state) =>
{
ConnectionCallback(stream, status, error, state);
},
this);
return socket;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ protected override UvStreamHandle CreateListenSocket()
var socket = new UvPipeHandle(Log);
socket.Init(Thread.Loop, false);
socket.Bind(ServerAddress.UnixPipePath);
socket.Listen(Constants.ListenBacklog, ConnectionCallback, this);
socket.Listen(
Constants.ListenBacklog,
(stream, status, error, state) =>
{
ConnectionCallback(stream, status, error, state);
},
this);
return socket;
}

Expand Down
Loading