Add Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions project (#1582).

- Changes the design to have one ConnectionHandler per endpoint.
This commit is contained in:
Cesar Blum Silveira 2017-04-03 15:09:03 -07:00 committed by GitHub
parent f285b18f08
commit 6bd0344880
42 changed files with 181 additions and 146 deletions

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
VisualStudioVersion = 15.0.26327.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}"
ProjectSection(SolutionItems) = preProject
@ -65,6 +65,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel", "src\Microsoft.AspNetCore.Server.Kestrel\Microsoft.AspNetCore.Server.Kestrel.csproj", "{56139957-5C29-4E7D-89BD-7D20598B4EAF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions", "src\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj", "{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -195,6 +197,18 @@ Global
{56139957-5C29-4E7D-89BD-7D20598B4EAF}.Release|x64.Build.0 = Release|Any CPU
{56139957-5C29-4E7D-89BD-7D20598B4EAF}.Release|x86.ActiveCfg = Release|Any CPU
{56139957-5C29-4E7D-89BD-7D20598B4EAF}.Release|x86.Build.0 = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Debug|x64.ActiveCfg = Debug|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Debug|x64.Build.0 = Debug|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Debug|x86.Build.0 = Debug|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|Any CPU.Build.0 = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x64.ActiveCfg = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x64.Build.0 = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x86.ActiveCfg = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -212,5 +226,6 @@ Global
{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E} = {0EF2ACDF-012F-4472-A13A-4272419E2903}
{A76B8C8C-0DC5-4DD3-9B1F-02E51A0915F4} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{56139957-5C29-4E7D-89BD-7D20598B4EAF} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
EndGlobalSection
EndGlobal

View File

@ -5,17 +5,19 @@ using System.IO.Pipelines;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal
{
public class ConnectionHandler<TContext> : IConnectionHandler
{
private readonly ListenOptions _listenOptions;
private readonly ServiceContext _serviceContext;
private readonly IHttpApplication<TContext> _application;
public ConnectionHandler(ServiceContext serviceContext, IHttpApplication<TContext> application)
public ConnectionHandler(ListenOptions listenOptions, ServiceContext serviceContext, IHttpApplication<TContext> application)
{
_listenOptions = listenOptions;
_serviceContext = serviceContext;
_application = application;
}
@ -44,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
ConnectionId = connectionId,
ServiceContext = _serviceContext,
PipeFactory = connectionInfo.PipeFactory,
ConnectionAdapters = connectionInfo.ListenOptions.ConnectionAdapters,
ConnectionAdapters = _listenOptions.ConnectionAdapters,
Frame = frame,
Input = inputPipe,
Output = outputPipe,
@ -52,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
});
_serviceContext.Log.ConnectionStart(connectionId);
KestrelEventSource.Log.ConnectionStart(connection, connectionInfo);
KestrelEventSource.Log.ConnectionStart(_listenOptions, connection, connectionInfo);
// Since data cannot be added to the inputPipe by the transport until OnConnection returns,
// Frame.RequestProcessingAsync is guaranteed to unblock the transport thread before calling

View File

@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Adapter;
using Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;

View File

@ -16,7 +16,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Adapter;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
{

View File

@ -7,7 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Exceptions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http

View File

@ -4,7 +4,7 @@
using System.Diagnostics.Tracing;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
{
@ -26,14 +26,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
// - Avoid renaming methods or parameters marked with EventAttribute. EventSource uses these to form the event object.
[NonEvent]
public void ConnectionStart(IConnectionContext context, IConnectionInformation information)
public void ConnectionStart(ListenOptions listenOptions, IConnectionContext context, IConnectionInformation information)
{
// avoid allocating strings unless this event source is enabled
if (IsEnabled())
{
ConnectionStart(
context.ConnectionId,
information.ListenOptions.Scheme,
listenOptions.Scheme,
information.LocalEndPoint.ToString(),
information.RemoteEndPoint.ToString());
}

View File

@ -16,8 +16,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Exceptions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -110,8 +109,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel
ServerOptions = Options
};
var connectionHandler = new ConnectionHandler<TContext>(serviceContext, application);
var listenOptions = Options.ListenOptions;
var hasListenOptions = listenOptions.Any();
var hasServerAddresses = _serverAddresses.Addresses.Any();
@ -128,7 +125,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
_logger.LogDebug($"No listening endpoints were configured. Binding to {Constants.DefaultServerAddress} by default.");
// "localhost" for both IPv4 and IPv6 can't be represented as an IPEndPoint.
StartLocalhost(connectionHandler, ServerAddress.FromUrl(Constants.DefaultServerAddress));
StartLocalhost(ServerAddress.FromUrl(Constants.DefaultServerAddress), serviceContext, application);
// If StartLocalhost doesn't throw, there is at least one listener.
// The port cannot change for "localhost".
@ -173,7 +170,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
if (string.Equals(parsedAddress.Host, "localhost", StringComparison.OrdinalIgnoreCase))
{
// "localhost" for both IPv4 and IPv6 can't be represented as an IPEndPoint.
StartLocalhost(connectionHandler, parsedAddress);
StartLocalhost(parsedAddress, serviceContext, application);
// If StartLocalhost doesn't throw, there is at least one listener.
// The port cannot change for "localhost".
@ -193,6 +190,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
foreach (var endPoint in listenOptions)
{
var connectionHandler = new ConnectionHandler<TContext>(endPoint, serviceContext, application);
var transport = _transportFactory.Create(endPoint, connectionHandler);
_transports.Add(transport);
@ -256,7 +254,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
}
}
private void StartLocalhost<TContext>(ConnectionHandler<TContext> connectionHandler, ServerAddress parsedAddress)
private void StartLocalhost<TContext>(ServerAddress parsedAddress, ServiceContext serviceContext, IHttpApplication<TContext> application)
{
if (parsedAddress.Port == 0)
{
@ -272,6 +270,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
Scheme = parsedAddress.Scheme,
};
var connectionHandler = new ConnectionHandler<TContext>(ipv4ListenOptions, serviceContext, application);
var transport = _transportFactory.Create(ipv4ListenOptions, connectionHandler);
_transports.Add(transport);
transport.BindAsync().Wait();
@ -293,6 +292,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
Scheme = parsedAddress.Scheme,
};
var connectionHandler = new ConnectionHandler<TContext>(ipv6ListenOptions, serviceContext, application);
var transport = _transportFactory.Create(ipv6ListenOptions, connectionHandler);
_transports.Add(transport);
transport.BindAsync().Wait();

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Adapter;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel
{
@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel
/// Describes either an <see cref="IPEndPoint"/>, Unix domain socket path, or a file descriptor for an already open
/// socket that Kestrel should bind to or open.
/// </summary>
public class ListenOptions
public class ListenOptions : IEndPointInformation
{
internal ListenOptions(IPEndPoint endPoint)
{

View File

@ -25,6 +25,10 @@
<PackageReference Include="System.Text.Encodings.Web.Utf8" Version="$(CoreFxLabsVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.Diagnostics.Process" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Threading.Thread" Version="$(CoreFxVersion)" />

View File

@ -3,7 +3,7 @@
using System;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Exceptions
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public class AddressInUseException : InvalidOperationException
{

View File

@ -4,7 +4,7 @@
using System;
using System.IO;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Exceptions
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public class ConnectionResetException : IOException
{

View File

@ -5,7 +5,7 @@ using System;
using System.IO.Pipelines;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface IConnectionContext
{

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Server.Kestrel.Transport
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface IConnectionHandler
{

View File

@ -3,13 +3,11 @@
using System.IO.Pipelines;
using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface IConnectionInformation
{
ListenOptions ListenOptions { get; }
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }

View File

@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Net;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface IEndPointInformation
{
/// <summary>
/// The type of interface being described: either an <see cref="IPEndPoint"/>, Unix domain socket path, or a file descriptor.
/// </summary>
ListenType Type { get; }
// IPEndPoint is mutable so port 0 can be updated to the bound port.
/// <summary>
/// The <see cref="IPEndPoint"/> to bind to.
/// Only set if <see cref="Type"/> is <see cref="ListenType.IPEndPoint"/>.
/// </summary>
IPEndPoint IPEndPoint { get; set; }
/// <summary>
/// The absolute path to a Unix domain socket to bind to.
/// Only set if <see cref="Type"/> is <see cref="ListenType.SocketPath"/>.
/// </summary>
string SocketPath { get; }
/// <summary>
/// A file descriptor for the socket to open.
/// Only set if <see cref="Type"/> is <see cref="ListenType.FileHandle"/>.
/// </summary>
ulong FileHandle { get; }
/// <summary>
/// Set to false to enable Nagle's algorithm for all connections.
/// </summary>
bool NoDelay { get; }
}
}

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface ITimeoutControl
{

View File

@ -3,7 +3,7 @@
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface ITransport
{

View File

@ -1,10 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Server.Kestrel.Transport
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public interface ITransportFactory
{
ITransport Create(ListenOptions listenOptions, IConnectionHandler handler);
ITransport Create(IEndPointInformation endPointInformation, IConnectionHandler handler);
}
}

View File

@ -1,10 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Server.Kestrel
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
/// <summary>
/// Enumerates the <see cref="ListenOptions"/> types.
/// Enumerates the <see cref="IEndPointInformation"/> types.
/// </summary>
public enum ListenType
{

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<Description>Transport abstractions for the ASP.NET Core Kestrel cross-platform web server.</Description>
<TargetFrameworks>netstandard1.3</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;kestrel</PackageTags>
<NoWarn>CS1591;$(NoWarn)</NoWarn>
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.IO.Pipelines" Version="$(CoreFxLabsPipelinesVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="$(AspNetCoreVersion)" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
{
public enum TimeoutAction
{

View File

@ -9,8 +9,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Exceptions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http

View File

@ -3,7 +3,7 @@
using System.IO.Pipelines;
using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
{
@ -20,7 +20,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
public ListenerContext ListenerContext { get; set; }
public ListenOptions ListenOptions => ListenerContext.ListenOptions;
public IPEndPoint RemoteEndPoint { get; set; }
public IPEndPoint LocalEndPoint { get; set; }

View File

@ -5,6 +5,7 @@ using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.Extensions.Logging;
@ -26,10 +27,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
public IKestrelTrace Log => TransportContext.Log;
public Task StartAsync(
ListenOptions listenOptions,
IEndPointInformation endPointInformation,
KestrelThread thread)
{
ListenOptions = listenOptions;
EndPointInformation = endPointInformation;
Thread = thread;
var tcs = new TaskCompletionSource<int>(this);
@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
/// </summary>
private UvStreamHandle CreateListenSocket()
{
switch (ListenOptions.Type)
switch (EndPointInformation.Type)
{
case ListenType.IPEndPoint:
case ListenType.FileHandle:
@ -67,18 +68,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
try
{
socket.Init(Thread.Loop, Thread.QueueCloseHandle);
socket.NoDelay(ListenOptions.NoDelay);
socket.NoDelay(EndPointInformation.NoDelay);
if (ListenOptions.Type == ListenType.IPEndPoint)
if (EndPointInformation.Type == ListenType.IPEndPoint)
{
socket.Bind(ListenOptions.IPEndPoint);
socket.Bind(EndPointInformation.IPEndPoint);
// If requested port was "0", replace with assigned dynamic port.
ListenOptions.IPEndPoint = socket.GetSockIPEndPoint();
EndPointInformation.IPEndPoint = socket.GetSockIPEndPoint();
}
else
{
socket.Open((IntPtr)ListenOptions.FileHandle);
socket.Open((IntPtr)EndPointInformation.FileHandle);
}
}
catch
@ -94,7 +95,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
try
{
pipe.Init(Thread.Loop, Thread.QueueCloseHandle, false);
pipe.Bind(ListenOptions.SocketPath);
pipe.Bind(EndPointInformation.SocketPath);
}
catch
{

View File

@ -3,6 +3,7 @@
using System;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
public LibuvTransportContext TransportContext { get; set; }
public ListenOptions ListenOptions { get; set; }
public IEndPointInformation EndPointInformation { get; set; }
public KestrelThread Thread { get; set; }
@ -25,13 +26,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
/// </summary>
protected UvStreamHandle CreateAcceptSocket()
{
switch (ListenOptions.Type)
switch (EndPointInformation.Type)
{
case ListenType.IPEndPoint:
case ListenType.FileHandle:
var tcpHandle = new UvTcpHandle(TransportContext.Log);
tcpHandle.Init(Thread.Loop, Thread.QueueCloseHandle);
tcpHandle.NoDelay(ListenOptions.NoDelay);
tcpHandle.NoDelay(EndPointInformation.NoDelay);
return tcpHandle;
case ListenType.SocketPath:
var pipeHandle = new UvPipeHandle(TransportContext.Log);

View File

@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.Extensions.Logging;
@ -39,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
public async Task StartAsync(
string pipeName,
byte[] pipeMessage,
ListenOptions listenOptions,
IEndPointInformation endPointInformation,
KestrelThread thread)
{
_pipeName = pipeName;
@ -52,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
Marshal.StructureToPtr(fileCompletionInfo, _fileCompletionInfoPtr, false);
}
await StartAsync(listenOptions, thread).ConfigureAwait(false);
await StartAsync(endPointInformation, thread).ConfigureAwait(false);
await Thread.PostAsync(state => ((ListenerPrimary)state).PostCallback(),
this).ConfigureAwait(false);

View File

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.Extensions.Logging;
@ -36,14 +37,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
public Task StartAsync(
string pipeName,
byte[] pipeMessage,
ListenOptions listenOptions,
IEndPointInformation endPointInformation,
KestrelThread thread)
{
_pipeName = pipeName;
_pipeMessage = pipeMessage;
_buf = thread.Loop.Libuv.buf_init(_ptr, 4);
ListenOptions = listenOptions;
EndPointInformation = endPointInformation;
Thread = thread;
DispatchPipe = new UvPipeHandle(Log);

View File

@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{

View File

@ -9,8 +9,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Exceptions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.Extensions.Logging;
@ -19,21 +18,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
{
public class KestrelEngine : ITransport
{
private readonly ListenOptions _listenOptions;
private readonly IEndPointInformation _endPointInformation;
private readonly List<IAsyncDisposable> _listeners = new List<IAsyncDisposable>();
public KestrelEngine(LibuvTransportContext context, ListenOptions listenOptions)
: this(new LibuvFunctions(), context, listenOptions)
public KestrelEngine(LibuvTransportContext context, IEndPointInformation endPointInformation)
: this(new LibuvFunctions(), context, endPointInformation)
{ }
// For testing
public KestrelEngine(LibuvFunctions uv, LibuvTransportContext context, ListenOptions listenOptions)
public KestrelEngine(LibuvFunctions uv, LibuvTransportContext context, IEndPointInformation endPointInformation)
{
Libuv = uv;
TransportContext = context;
_listenOptions = listenOptions;
_endPointInformation = endPointInformation;
}
public LibuvFunctions Libuv { get; }
@ -92,7 +91,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
{
var listener = new Listener(TransportContext);
_listeners.Add(listener);
await listener.StartAsync(_listenOptions, Threads[0]).ConfigureAwait(false);
await listener.StartAsync(_endPointInformation, Threads[0]).ConfigureAwait(false);
}
else
{
@ -101,13 +100,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal
var listenerPrimary = new ListenerPrimary(TransportContext);
_listeners.Add(listenerPrimary);
await listenerPrimary.StartAsync(pipeName, pipeMessage, _listenOptions, Threads[0]).ConfigureAwait(false);
await listenerPrimary.StartAsync(pipeName, pipeMessage, _endPointInformation, Threads[0]).ConfigureAwait(false);
foreach (var thread in Threads.Skip(1))
{
var listenerSecondary = new ListenerSecondary(TransportContext);
_listeners.Add(listenerSecondary);
await listenerSecondary.StartAsync(pipeName, pipeMessage, _listenOptions, thread).ConfigureAwait(false);
await listenerSecondary.StartAsync(pipeName, pipeMessage, _endPointInformation, thread).ConfigureAwait(false);
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -65,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv
};
}
public ITransport Create(ListenOptions listenOptions, IConnectionHandler handler)
public ITransport Create(IEndPointInformation endPointInformation, IConnectionHandler handler)
{
var transportContext = new LibuvTransportContext
{
@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv
ConnectionHandler = handler
};
return new KestrelEngine(transportContext, listenOptions);
return new KestrelEngine(transportContext, endPointInformation);
}
}
}

View File

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.Extensions.DependencyInjection;

View File

@ -3,14 +3,12 @@
using System.IO.Pipelines;
using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
public class MockConnectionInformation : IConnectionInformation
{
public ListenOptions ListenOptions { get; }
public IPEndPoint RemoteEndPoint { get; }
public IPEndPoint LocalEndPoint { get; }

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public async Task ListenerCanCreateAndDispose(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
testContext.App = TestApp.EchoApp;
testContext.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(listenOptions, testContext, new DummyApplication(TestApp.EchoApp));
var engine = new KestrelEngine(testContext.TransportContext, listenOptions);
await engine.BindAsync();
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public async Task ConnectionCanReadAndWrite(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
testContext.App = TestApp.EchoApp;
testContext.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(listenOptions, testContext, new DummyApplication(TestApp.EchoApp));
var engine = new KestrelEngine(testContext.TransportContext, listenOptions);
await engine.BindAsync();

View File

@ -16,7 +16,7 @@ using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
@ -712,7 +712,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
private class MockConnectionInformation : IConnectionInformation
{
public ListenOptions ListenOptions { get; }
public IPEndPoint RemoteEndPoint { get; }
public IPEndPoint LocalEndPoint { get; }
public PipeFactory PipeFactory { get; }

View File

@ -4,17 +4,17 @@
using System;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
using Microsoft.AspNetCore.Builder;
namespace Microsoft.AspNetCore.Server.KestrelTests
{
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
private class MockTransportFactory : ITransportFactory
{
public ITransport Create(ListenOptions listenOptions, IConnectionHandler handler)
public ITransport Create(IEndPointInformation endPointInformation, IConnectionHandler handler)
{
return Mock.Of<ITransport>();
}

View File

@ -6,9 +6,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
@ -26,18 +24,16 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public async Task ConnectionsGetRoundRobinedToSecondaryListeners()
{
var libuv = new LibuvFunctions();
var serviceContextPrimary = new TestServiceContext
{
App = c => c.Response.WriteAsync("Primary")
};
var serviceContextSecondary = new TestServiceContext
{
App = c => c.Response.WriteAsync("Secondary")
};
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var serviceContextPrimary = new TestServiceContext();
serviceContextPrimary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
var serviceContextSecondary = new TestServiceContext();
serviceContextSecondary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
var kestrelEngine = new KestrelEngine(libuv, serviceContextPrimary.TransportContext, listenOptions);
var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
@ -80,11 +76,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public async Task NonListenerPipeConnectionsAreLoggedAndIgnored()
{
var libuv = new LibuvFunctions();
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var serviceContextPrimary = new TestServiceContext
{
App = c => c.Response.WriteAsync("Primary")
};
var serviceContextPrimary = new TestServiceContext();
serviceContextPrimary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
var serviceContextSecondary = new TestServiceContext
{
@ -92,10 +88,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
ServerOptions = serviceContextPrimary.ServerOptions,
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
App = c => c.Response.WriteAsync("Secondary")
};
serviceContextSecondary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var kestrelEngine = new KestrelEngine(libuv, serviceContextPrimary.TransportContext, listenOptions);
var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
@ -187,11 +183,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public async Task PipeConnectionsWithWrongMessageAreLoggedAndIgnored()
{
var libuv = new LibuvFunctions();
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var serviceContextPrimary = new TestServiceContext
{
App = c => c.Response.WriteAsync("Primary")
};
var serviceContextPrimary = new TestServiceContext();
serviceContextPrimary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
var serviceContextSecondary = new TestServiceContext
{
@ -199,10 +195,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
ServerOptions = serviceContextPrimary.ServerOptions,
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
App = c => c.Response.WriteAsync("Secondary")
};
serviceContextSecondary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var kestrelEngine = new KestrelEngine(libuv, serviceContextPrimary.TransportContext, listenOptions);
var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
@ -271,29 +267,5 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
Assert.True(false, $"'{address}' failed to respond with '{expected}' in {maxRetries} retries.");
}
private class TestApplication : IHttpApplication<DefaultHttpContext>
{
private readonly Func<DefaultHttpContext, Task> _app;
public TestApplication(Func<DefaultHttpContext, Task> app)
{
_app = app;
}
public DefaultHttpContext CreateContext(IFeatureCollection contextFeatures)
{
return new DefaultHttpContext(contextFeatures);
}
public Task ProcessRequestAsync(DefaultHttpContext context)
{
return _app(context);
}
public void DisposeContext(DefaultHttpContext context, Exception exception)
{
}
}
}
}

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
serviceContext.ServerOptions.Limits.MaxResponseBufferSize = maxResponseBufferSize;
serviceContext.ThreadPool = new LoggingThreadPool(null);
var connectionHandler = new ConnectionHandler<object>(serviceContext, application: null);
var connectionHandler = new ConnectionHandler<object>(listenOptions: null, serviceContext: serviceContext, application: null);
var mockScheduler = Mock.Of<IScheduler>();
var outputPipeOptions = connectionHandler.GetOutputPipeOptions(mockScheduler);
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize;
serviceContext.ThreadPool = new LoggingThreadPool(null);
var connectionHandler = new ConnectionHandler<object>(serviceContext, application: null);
var connectionHandler = new ConnectionHandler<object>(listenOptions: null, serviceContext: serviceContext, application: null);
var mockScheduler = Mock.Of<IScheduler>();
var inputPipeOptions = connectionHandler.GetInputPipeOptions(mockScheduler);

View File

@ -4,7 +4,7 @@
using System;
using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Transport;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers

View File

@ -7,6 +7,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;

View File

@ -43,8 +43,7 @@ namespace Microsoft.AspNetCore.Testing
_listenOptions = listenOptions;
Context = context;
Context.App = app;
Context.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(Context, new DummyApplication(app, httpContextFactory));
Context.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(listenOptions, Context, new DummyApplication(app, httpContextFactory));
try
{

View File

@ -14,8 +14,6 @@ namespace Microsoft.AspNetCore.Testing
{
public class TestServiceContext : ServiceContext
{
private RequestDelegate _app;
public TestServiceContext()
{
Log = new TestKestrelTrace();
@ -43,18 +41,5 @@ namespace Microsoft.AspNetCore.Testing
public string DateHeaderValue { get; }
public LibuvTransportContext TransportContext { get; }
public RequestDelegate App
{
get
{
return _app;
}
set
{
TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(this, new DummyApplication(value));
_app = value;
}
}
}
}