Initial bedrock refactoring (#1995)

- Added Protocols.Abstractions
 - IConnectionHandler.OnConnection takes an IFeatureCollection instead of
 IConnectionInfo
 - Removed IConnectionContext and IConnectionInformation replaced with
 IConnectionTransportFeature
 - Updated FrameConnectionContext and FrameContext to have the relevant
 state instead of flowing the ConnectionInformation.
 - Updated tests
This commit is contained in:
David Fowler 2017-08-16 00:02:48 -07:00 committed by GitHub
parent f3745608af
commit 5c775073a4
51 changed files with 632 additions and 237 deletions

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26706.0
VisualStudioVersion = 15.0.26730.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}"
ProjectSection(SolutionItems) = preProject
@ -80,6 +80,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Transport.Libuv.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Tests", "test\Kestrel.Tests\Kestrel.Tests.csproj", "{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protocols.Abstractions", "src\Protocols.Abstractions\Protocols.Abstractions.csproj", "{6956CF5C-3163-4398-8628-4ECA569245B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -258,6 +260,18 @@ Global
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x64.Build.0 = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x86.ActiveCfg = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x86.Build.0 = Release|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Debug|x64.ActiveCfg = Debug|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Debug|x64.Build.0 = Debug|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Debug|x86.ActiveCfg = Debug|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Debug|x86.Build.0 = Debug|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Release|Any CPU.Build.0 = Release|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Release|x64.ActiveCfg = Release|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Release|x64.Build.0 = Release|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Release|x86.ActiveCfg = Release|Any CPU
{6956CF5C-3163-4398-8628-4ECA569245B5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -279,6 +293,7 @@ Global
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{6956CF5C-3163-4398-8628-4ECA569245B5} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2D10D020-6770-47CA-BB8D-2C23FE3AE071}

View File

@ -9,8 +9,8 @@ using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal

View File

@ -2,8 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO.Pipelines;
using System.Net;
using System.Threading;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Protocols.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
@ -24,38 +28,73 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
_application = application;
}
public IConnectionContext OnConnection(IConnectionInformation connectionInfo)
public void OnConnection(IFeatureCollection features)
{
var inputPipe = connectionInfo.PipeFactory.Create(GetInputPipeOptions(connectionInfo.InputWriterScheduler));
var outputPipe = connectionInfo.PipeFactory.Create(GetOutputPipeOptions(connectionInfo.OutputReaderScheduler));
var connectionContext = new DefaultConnectionContext(features);
var transportFeature = connectionContext.Features.Get<IConnectionTransportFeature>();
var inputPipe = transportFeature.PipeFactory.Create(GetInputPipeOptions(transportFeature.InputWriterScheduler));
var outputPipe = transportFeature.PipeFactory.Create(GetOutputPipeOptions(transportFeature.OutputReaderScheduler));
var connectionId = CorrelationIdGenerator.GetNextId();
var frameConnectionId = Interlocked.Increment(ref _lastFrameConnectionId);
// Set the transport and connection id
connectionContext.ConnectionId = connectionId;
transportFeature.Connection = new PipeConnection(inputPipe.Reader, outputPipe.Writer);
var applicationConnection = new PipeConnection(outputPipe.Reader, inputPipe.Writer);
if (!_serviceContext.ConnectionManager.NormalConnectionCount.TryLockOne())
{
var goAway = new RejectionConnection(inputPipe, outputPipe, connectionId, _serviceContext);
var goAway = new RejectionConnection(inputPipe, outputPipe, connectionId, _serviceContext)
{
Connection = applicationConnection
};
connectionContext.Features.Set<IConnectionApplicationFeature>(goAway);
goAway.Reject();
return goAway;
return;
}
var connection = new FrameConnection(new FrameConnectionContext
var frameConnectionContext = new FrameConnectionContext
{
ConnectionId = connectionId,
FrameConnectionId = frameConnectionId,
ServiceContext = _serviceContext,
ConnectionInformation = connectionInfo,
PipeFactory = connectionContext.PipeFactory,
ConnectionAdapters = _listenOptions.ConnectionAdapters,
Input = inputPipe,
Output = outputPipe,
});
Output = outputPipe
};
var connectionFeature = connectionContext.Features.Get<IHttpConnectionFeature>();
if (connectionFeature != null)
{
if (connectionFeature.LocalIpAddress != null)
{
frameConnectionContext.LocalEndPoint = new IPEndPoint(connectionFeature.LocalIpAddress, connectionFeature.LocalPort);
}
if (connectionFeature.RemoteIpAddress != null)
{
frameConnectionContext.RemoteEndPoint = new IPEndPoint(connectionFeature.RemoteIpAddress, connectionFeature.RemotePort);
}
}
var connection = new FrameConnection(frameConnectionContext)
{
Connection = applicationConnection
};
connectionContext.Features.Set<IConnectionApplicationFeature>(connection);
// Since data cannot be added to the inputPipe by the transport until OnConnection returns,
// Frame.ProcessRequestsAsync is guaranteed to unblock the transport thread before calling
// application code.
connection.StartRequestProcessing<TContext>(_application);
return connection;
connection.StartRequestProcessing(_application);
}
// Internal for testing

View File

@ -6,19 +6,20 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipelines;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
{
public class FrameConnection : IConnectionContext, ITimeoutControl
public class FrameConnection : IConnectionApplicationFeature, ITimeoutControl
{
private readonly FrameConnectionContext _context;
private List<IAdaptedConnection> _adaptedConnections;
@ -55,8 +56,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public string ConnectionId => _context.ConnectionId;
public IPipeWriter Input => _context.Input.Writer;
public IPipeReader Output => _context.Output.Reader;
public IPEndPoint LocalEndPoint => _context.LocalEndPoint;
public IPEndPoint RemoteEndPoint => _context.RemoteEndPoint;
private PipeFactory PipeFactory => _context.ConnectionInformation.PipeFactory;
private PipeFactory PipeFactory => _context.PipeFactory;
// Internal for testing
internal PipeOptions AdaptedInputPipeOptions => new PipeOptions
@ -77,6 +80,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
private IKestrelTrace Log => _context.ServiceContext.Log;
public IPipeConnection Connection { get; set; }
public void StartRequestProcessing<TContext>(IHttpApplication<TContext> application)
{
_lifetimeTask = ProcessRequestsAsync(application);
@ -89,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
try
{
Log.ConnectionStart(ConnectionId);
KestrelEventSource.Log.ConnectionStart(this, _context.ConnectionInformation);
KestrelEventSource.Log.ConnectionStart(this);
AdaptedPipeline adaptedPipeline = null;
var adaptedPipelineTask = Task.CompletedTask;
@ -156,7 +161,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
_frame = new Frame<TContext>(application, new FrameContext
{
ConnectionId = _context.ConnectionId,
ConnectionInformation = _context.ConnectionInformation,
PipeFactory = PipeFactory,
LocalEndPoint = LocalEndPoint,
RemoteEndPoint = RemoteEndPoint,
ServiceContext = _context.ServiceContext,
TimeoutControl = this,
Input = input,

View File

@ -3,8 +3,8 @@
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
{
@ -14,7 +14,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public long FrameConnectionId { get; set; }
public ServiceContext ServiceContext { get; set; }
public List<IConnectionAdapter> ConnectionAdapters { get; set; }
public IConnectionInformation ConnectionInformation { get; set; }
public PipeFactory PipeFactory { get; set; }
public IPEndPoint LocalEndPoint { get; set; }
public IPEndPoint RemoteEndPoint { get; set; }
public IPipe Input { get; set; }
public IPipe Output { get; set; }

View File

@ -15,8 +15,8 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
@ -103,7 +103,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public IPipe RequestBodyPipe { get; }
public ServiceContext ServiceContext => _frameContext.ServiceContext;
public IConnectionInformation ConnectionInformation => _frameContext.ConnectionInformation;
private IPEndPoint LocalEndPoint => _frameContext.LocalEndPoint;
private IPEndPoint RemoteEndPoint => _frameContext.RemoteEndPoint;
public IFeatureCollection ConnectionFeatures { get; set; }
public IPipeReader Input => _frameContext.Input;
@ -114,8 +115,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private DateHeaderValueManager DateHeaderValueManager => ServiceContext.DateHeaderValueManager;
// Hold direct reference to ServerOptions since this is used very often in the request processing path
private KestrelServerOptions ServerOptions { get; }
private IPEndPoint LocalEndPoint => ConnectionInformation.LocalEndPoint;
private IPEndPoint RemoteEndPoint => ConnectionInformation.RemoteEndPoint;
protected string ConnectionId => _frameContext.ConnectionId;
public string ConnectionIdFeature { get; set; }
@ -1376,7 +1375,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
private IPipe CreateRequestBodyPipe()
=> ConnectionInformation.PipeFactory.Create(new PipeOptions
=> _frameContext.PipeFactory.Create(new PipeOptions
{
ReaderScheduler = ServiceContext.ThreadPool,
WriterScheduler = InlineScheduler.Default,

View File

@ -2,8 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO.Pipelines;
using System.Net;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
@ -11,7 +12,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
public string ConnectionId { get; set; }
public ServiceContext ServiceContext { get; set; }
public IConnectionInformation ConnectionInformation { get; set; }
public PipeFactory PipeFactory { get; set; }
public IPEndPoint RemoteEndPoint { get; set; }
public IPEndPoint LocalEndPoint { get; set; }
public ITimeoutControl TimeoutControl { get; set; }
public IPipeReader Input { get; set; }
public IPipe Output { get; set; }

View File

@ -6,8 +6,8 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure

View File

@ -2,7 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics.Tracing;
using System.Net;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
@ -26,15 +29,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.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(FrameConnection connection)
{
// avoid allocating strings unless this event source is enabled
if (IsEnabled())
{
ConnectionStart(
context.ConnectionId,
information.LocalEndPoint.ToString(),
information.RemoteEndPoint.ToString());
connection.ConnectionId,
connection.LocalEndPoint.ToString(),
connection.RemoteEndPoint.ToString());
}
}
@ -53,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
}
[NonEvent]
public void ConnectionStop(IConnectionContext connection)
public void ConnectionStop(FrameConnection connection)
{
if (IsEnabled())
{

View File

@ -3,12 +3,12 @@
using System;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Protocols.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
{
public class RejectionConnection : IConnectionContext
public class RejectionConnection : IConnectionApplicationFeature
{
private readonly IKestrelTrace _log;
private readonly IPipe _input;
@ -26,6 +26,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public IPipeWriter Input => _input.Writer;
public IPipeReader Output => _output.Reader;
public IPipeConnection Connection { get; set; }
public void Reject()
{
KestrelEventSource.Log.ConnectionRejected(ConnectionId);
@ -34,13 +36,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
_output.Writer.Complete();
}
// TODO: Remove these (https://github.com/aspnet/KestrelHttpServer/issues/1772)
void IConnectionContext.OnConnectionClosed(Exception ex)
void IConnectionApplicationFeature.OnConnectionClosed(Exception ex)
{
}
void IConnectionContext.Abort(Exception ex)
void IConnectionApplicationFeature.Abort(Exception ex)
{
}
}
}
}

View File

@ -1,19 +0,0 @@
// 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;
using System.IO.Pipelines;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
{
public interface IConnectionContext
{
string ConnectionId { get; }
IPipeWriter Input { get; }
IPipeReader Output { get; }
// TODO: Remove these (https://github.com/aspnet/KestrelHttpServer/issues/1772)
void OnConnectionClosed(Exception ex);
void Abort(Exception ex);
}
}

View File

@ -1,10 +1,12 @@
// 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.Http.Features;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
{
public interface IConnectionHandler
{
IConnectionContext OnConnection(IConnectionInformation connectionInfo);
void OnConnection(IFeatureCollection features);
}
}

View File

@ -1,19 +0,0 @@
// 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.IO.Pipelines;
using System.Net;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
{
public interface IConnectionInformation
{
IPEndPoint RemoteEndPoint { get; }
IPEndPoint LocalEndPoint { get; }
PipeFactory PipeFactory { get; }
IScheduler InputWriterScheduler { get; }
IScheduler OutputReaderScheduler { get; }
}
}

View File

@ -0,0 +1,215 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols.Features;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
{
public partial class TransportConnection : IFeatureCollection,
IHttpConnectionFeature,
IConnectionIdFeature,
IConnectionTransportFeature
{
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
private static readonly Type IConnectionIdFeatureType = typeof(IConnectionIdFeature);
private static readonly Type IConnectionTransportFeatureType = typeof(IConnectionTransportFeature);
private static readonly Type IConnectionApplicationFeatureType = typeof(IConnectionApplicationFeature);
private object _currentIHttpConnectionFeature;
private object _currentIConnectionIdFeature;
private object _currentIConnectionTransportFeature;
private object _currentIConnectionApplicationFeature;
private int _featureRevision;
private List<KeyValuePair<Type, object>> MaybeExtra;
private object ExtraFeatureGet(Type key)
{
if (MaybeExtra == null)
{
return null;
}
for (var i = 0; i < MaybeExtra.Count; i++)
{
var kv = MaybeExtra[i];
if (kv.Key == key)
{
return kv.Value;
}
}
return null;
}
private void ExtraFeatureSet(Type key, object value)
{
if (MaybeExtra == null)
{
MaybeExtra = new List<KeyValuePair<Type, object>>(2);
}
for (var i = 0; i < MaybeExtra.Count; i++)
{
if (MaybeExtra[i].Key == key)
{
MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
return;
}
}
MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));
}
bool IFeatureCollection.IsReadOnly => false;
int IFeatureCollection.Revision => _featureRevision;
string IHttpConnectionFeature.ConnectionId
{
get => ConnectionId;
set => ConnectionId = value;
}
IPAddress IHttpConnectionFeature.RemoteIpAddress
{
get => RemoteAddress;
set => RemoteAddress = value;
}
IPAddress IHttpConnectionFeature.LocalIpAddress
{
get => LocalAddress;
set => LocalAddress = value;
}
int IHttpConnectionFeature.RemotePort
{
get => RemotePort;
set => RemotePort = value;
}
int IHttpConnectionFeature.LocalPort
{
get => LocalPort;
set => LocalPort = value;
}
PipeFactory IConnectionTransportFeature.PipeFactory => PipeFactory;
IPipeConnection IConnectionTransportFeature.Connection
{
get => Transport;
set => Transport = value;
}
object IFeatureCollection.this[Type key]
{
get => FastFeatureGet(key);
set => FastFeatureSet(key, value);
}
TFeature IFeatureCollection.Get<TFeature>()
{
return (TFeature)FastFeatureGet(typeof(TFeature));
}
void IFeatureCollection.Set<TFeature>(TFeature instance)
{
FastFeatureSet(typeof(TFeature), instance);
}
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
private object FastFeatureGet(Type key)
{
if (key == IHttpConnectionFeatureType)
{
return _currentIHttpConnectionFeature;
}
if (key == IConnectionIdFeatureType)
{
return _currentIConnectionIdFeature;
}
if (key == IConnectionTransportFeatureType)
{
return _currentIConnectionTransportFeature;
}
if (key == IConnectionApplicationFeatureType)
{
return _currentIConnectionApplicationFeature;
}
return ExtraFeatureGet(key);
}
private void FastFeatureSet(Type key, object feature)
{
_featureRevision++;
if (key == IHttpConnectionFeatureType)
{
_currentIHttpConnectionFeature = feature;
return;
}
if (key == IConnectionIdFeatureType)
{
_currentIConnectionIdFeature = feature;
return;
}
if (key == IConnectionTransportFeatureType)
{
_currentIConnectionTransportFeature = feature;
return;
}
if (key == IConnectionApplicationFeatureType)
{
_currentIConnectionApplicationFeature = feature;
return;
}
ExtraFeatureSet(key, feature);
}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{
if (_currentIHttpConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
}
if (_currentIConnectionIdFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionIdFeatureType, _currentIConnectionIdFeature);
}
if (_currentIConnectionTransportFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionTransportFeatureType, _currentIConnectionTransportFeature);
}
if (_currentIConnectionApplicationFeature != null)
{
yield return new KeyValuePair<Type, object>(IConnectionApplicationFeatureType, _currentIConnectionApplicationFeature);
}
if (MaybeExtra != null)
{
foreach (var item in MaybeExtra)
{
yield return item;
}
}
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Protocols.Features;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
{
public abstract partial class TransportConnection
{
public TransportConnection()
{
_currentIConnectionIdFeature = this;
_currentIConnectionTransportFeature = this;
_currentIHttpConnectionFeature = this;
}
public IPAddress RemoteAddress { get; set; }
public int RemotePort { get; set; }
public IPAddress LocalAddress { get; set; }
public int LocalPort { get; set; }
public string ConnectionId { get; set; }
public virtual PipeFactory PipeFactory { get; }
public virtual IScheduler InputWriterScheduler { get; }
public virtual IScheduler OutputReaderScheduler { get; }
public IPipeConnection Transport { get; set; }
public IConnectionApplicationFeature Application => (IConnectionApplicationFeature)_currentIConnectionApplicationFeature;
}
}

View File

@ -16,15 +16,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="$(AspNetCoreVersion)" />
<PackageReference Include="System.Numerics.Vectors" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Buffers" Version="$(CoreFxVersion)" />
<PackageReference Include="System.IO.Pipelines" Version="$(CoreFxLabVersion)" />
<PackageReference Include="System.Text.Encodings.Web.Utf8" Version="$(CoreFxLabVersion)" />
<!-- Override System.Memory and System.Runtime.CompilerServices.Unsafe to the ones we have on feed -->
<PackageReference Include="System.Memory" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(CoreFxVersion)" />
<ProjectReference Include="..\Protocols.Abstractions\Protocols.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@ -5,15 +5,16 @@ using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvConnection : LibuvConnectionContext
public partial class LibuvConnection : LibuvConnectionContext
{
private const int MinAllocBufferSize = 2048;
@ -24,7 +25,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
(handle, suggestedsize, state) => AllocCallback(handle, suggestedsize, state);
private readonly UvStreamHandle _socket;
private IConnectionContext _connectionContext;
private WritableBuffer? _currentWritableBuffer;
private BufferHandle _bufferHandle;
@ -35,14 +35,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
if (_socket is UvTcpHandle tcpHandle)
{
RemoteEndPoint = tcpHandle.GetPeerIPEndPoint();
LocalEndPoint = tcpHandle.GetSockIPEndPoint();
var remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
var localEndPoint = tcpHandle.GetSockIPEndPoint();
RemoteAddress = remoteEndPoint.Address;
RemotePort = remoteEndPoint.Port;
LocalAddress = localEndPoint.Address;
LocalPort = localEndPoint.Port;
}
}
public string ConnectionId { get; set; }
public IPipeWriter Input { get; set; }
public LibuvOutputConsumer Output { get; set; }
public IPipeWriter Input => Application.Connection.Output;
public IPipeReader Output => Application.Connection.Input;
public LibuvOutputConsumer OutputConsumer { get; set; }
private ILibuvTrace Log => ListenerContext.TransportContext.Log;
private IConnectionHandler ConnectionHandler => ListenerContext.TransportContext.ConnectionHandler;
@ -52,11 +59,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
try
{
_connectionContext = ConnectionHandler.OnConnection(this);
ConnectionId = _connectionContext.ConnectionId;
ConnectionHandler.OnConnection(this);
Input = _connectionContext.Input;
Output = new LibuvOutputConsumer(_connectionContext.Output, Thread, _socket, ConnectionId, Log);
OutputConsumer = new LibuvOutputConsumer(Output, Thread, _socket, ConnectionId, Log);
StartReading();
@ -67,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
// This *must* happen after socket.ReadStart
// The socket output consumer is the only thing that can close the connection. If the
// output pipe is already closed by the time we start then it's fine since, it'll close gracefully afterwards.
await Output.WriteOutputAsync();
await OutputConsumer.WriteOutputAsync();
}
catch (UvException ex)
{
@ -77,8 +82,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
// Now, complete the input so that no more reads can happen
Input.Complete(error ?? new ConnectionAbortedException());
_connectionContext.Output.Complete(error);
_connectionContext.OnConnectionClosed(error);
Output.Complete(error);
Application.OnConnectionClosed(error);
// Make sure it isn't possible for a paused read to resume reading after calling uv_close
// on the stream handle
@ -173,7 +178,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
}
}
_connectionContext.Abort(error);
Application.Abort(error);
// Complete after aborting the connection
Input.Complete(error);
}
@ -211,7 +216,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
Log.ConnectionReadFin(ConnectionId);
var error = new IOException(ex.Message, ex);
_connectionContext.Abort(error);
Application.Abort(error);
Input.Complete(error);
}
}

View File

@ -7,24 +7,17 @@ using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{
public class LibuvConnectionContext : IConnectionInformation
public class LibuvConnectionContext : TransportConnection
{
public LibuvConnectionContext()
{
}
public LibuvConnectionContext(ListenerContext context)
{
ListenerContext = context;
}
public ListenerContext ListenerContext { get; set; }
public IPEndPoint RemoteEndPoint { get; set; }
public IPEndPoint LocalEndPoint { get; set; }
public PipeFactory PipeFactory => ListenerContext.Thread.PipeFactory;
public IScheduler InputWriterScheduler => ListenerContext.Thread;
public IScheduler OutputReaderScheduler => ListenerContext.Thread;
public override PipeFactory PipeFactory => ListenerContext.Thread.PipeFactory;
public override IScheduler InputWriterScheduler => ListenerContext.Thread;
public override IScheduler OutputReaderScheduler => ListenerContext.Thread;
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;

View File

@ -10,16 +10,15 @@ using System.Net.Sockets;
using System.Threading.Tasks;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Protocols;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
{
internal sealed class SocketConnection : IConnectionInformation
internal sealed class SocketConnection : TransportConnection
{
private readonly Socket _socket;
private readonly SocketTransport _transport;
private readonly IPEndPoint _localEndPoint;
private readonly IPEndPoint _remoteEndPoint;
private IConnectionContext _connectionContext;
private IPipeWriter _input;
private IPipeReader _output;
private IList<ArraySegment<byte>> _sendBufferList;
@ -33,18 +32,24 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
_socket = socket;
_transport = transport;
_localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
_remoteEndPoint = (IPEndPoint)_socket.RemoteEndPoint;
var localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
var remoteEndPoint = (IPEndPoint)_socket.RemoteEndPoint;
LocalAddress = localEndPoint.Address;
LocalPort = localEndPoint.Port;
RemoteAddress = remoteEndPoint.Address;
RemotePort = remoteEndPoint.Port;
}
public async Task StartAsync(IConnectionHandler connectionHandler)
{
try
{
_connectionContext = connectionHandler.OnConnection(this);
connectionHandler.OnConnection(this);
_input = _connectionContext.Input;
_output = _connectionContext.Output;
_input = Application.Connection.Output;
_output = Application.Connection.Input;
// Spawn send and receive logic
Task receiveTask = DoReceive();
@ -130,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
}
finally
{
_connectionContext.Abort(error);
Application.Abort(error);
_input.Complete(error);
}
}
@ -224,7 +229,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
}
finally
{
_connectionContext.OnConnectionClosed(error);
Application.OnConnectionClosed(error);
_output.Complete(error);
}
}
@ -239,14 +244,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
return segment;
}
public IPEndPoint RemoteEndPoint => _remoteEndPoint;
public IPEndPoint LocalEndPoint => _localEndPoint;
public PipeFactory PipeFactory => _transport.TransportFactory.PipeFactory;
public IScheduler InputWriterScheduler => InlineScheduler.Default;
public IScheduler OutputReaderScheduler => TaskRunScheduler.Default;
public override PipeFactory PipeFactory => _transport.TransportFactory.PipeFactory;
public override IScheduler InputWriterScheduler => InlineScheduler.Default;
public override IScheduler OutputReaderScheduler => TaskRunScheduler.Default;
}
}

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets

View File

@ -0,0 +1,17 @@
using System;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Protocols
{
public abstract class ConnectionContext
{
public abstract string ConnectionId { get; set; }
public abstract IFeatureCollection Features { get; }
public abstract IPipeConnection Transport { get; set; }
public abstract PipeFactory PipeFactory { get; }
}
}

View File

@ -0,0 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Protocols
{
public delegate Task ConnectionDelegate(ConnectionContext connection);
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Text;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols.Features;
namespace Microsoft.AspNetCore.Protocols
{
public class DefaultConnectionContext : ConnectionContext
{
private FeatureReferences<FeatureInterfaces> _features;
public DefaultConnectionContext(IFeatureCollection features)
{
_features = new FeatureReferences<FeatureInterfaces>(features);
}
private IConnectionIdFeature ConnectionIdFeature =>
_features.Fetch(ref _features.Cache.ConnectionId, _ => null);
private IConnectionTransportFeature ConnectionTransportFeature =>
_features.Fetch(ref _features.Cache.ConnectionTransport, _ => null);
public override string ConnectionId
{
get => ConnectionIdFeature.ConnectionId;
set => ConnectionIdFeature.ConnectionId = value;
}
public override IFeatureCollection Features => _features.Collection;
public override PipeFactory PipeFactory => ConnectionTransportFeature.PipeFactory;
public override IPipeConnection Transport
{
get => ConnectionTransportFeature.Connection;
set => ConnectionTransportFeature.Connection = value;
}
struct FeatureInterfaces
{
public IConnectionIdFeature ConnectionId;
public IConnectionTransportFeature ConnectionTransport;
}
}
}

View File

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

View File

@ -1,6 +1,6 @@
using System;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
namespace Microsoft.AspNetCore.Protocols
{
public class ConnectionAbortedException : OperationCanceledException
{

View File

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

View File

@ -0,0 +1,18 @@
using System;
using System.IO.Pipelines;
namespace Microsoft.AspNetCore.Protocols.Features
{
public interface IConnectionApplicationFeature
{
IPipeConnection Connection { get; set; }
// TODO: Remove these (https://github.com/aspnet/KestrelHttpServer/issues/1772)
// REVIEW: These are around for now because handling pipe events messes with the order
// of operations an that breaks tons of tests. Instead, we preserve the existing semantics
// and ordering.
void Abort(Exception exception);
void OnConnectionClosed(Exception exception);
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNetCore.Protocols.Features
{
public interface IConnectionIdFeature
{
string ConnectionId { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Text;
namespace Microsoft.AspNetCore.Protocols.Features
{
public interface IConnectionTransportFeature
{
PipeFactory PipeFactory { get; }
IPipeConnection Connection { get; set; }
IScheduler InputWriterScheduler { get; }
IScheduler OutputReaderScheduler { get; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNetCore.Protocols
{
public interface IConnectionBuilder
{
IServiceProvider ApplicationServices { get; }
IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware);
ConnectionDelegate Build();
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.IO.Pipelines
{
public class PipeConnection : IPipeConnection
{
public PipeConnection(IPipeReader reader, IPipeWriter writer)
{
Input = reader;
Output = writer;
}
public IPipeReader Input { get; }
public IPipeWriter Output { get; }
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<AssemblyName>Microsoft.AspNetCore.Protocols.Abstractions</AssemblyName>
<RootNamespace>Microsoft.AspNetCore.Protocols.Abstractions</RootNamespace>
<Description>Core components of ASP.NET Core networking protocol stack.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore</PackageTags>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>CS1591;$(NoWarn)</NoWarn>
<EnableApiCheck>false</EnableApiCheck>
<!-- TODO: remove when https://github.com/dotnet/sdk/pull/1270 is fixed -->
<GenerateResourceMSBuildRuntime>CurrentRuntime</GenerateResourceMSBuildRuntime>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="$(AspNetCoreVersion)" />
<PackageReference Include="System.Numerics.Vectors" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Buffers" Version="$(CoreFxVersion)" />
<PackageReference Include="System.IO.Pipelines" Version="$(CoreFxLabVersion)" />
<PackageReference Include="System.Text.Encodings.Web.Utf8" Version="$(CoreFxLabVersion)" />
<!-- Override System.Memory and System.Runtime.CompilerServices.Unsafe to the ones we have on feed -->
<PackageReference Include="System.Memory" Version="$(CoreFxVersion)" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(CoreFxVersion)" />
</ItemGroup>
</Project>

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing;

View File

@ -30,10 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
ConnectionId = "0123456789",
ConnectionAdapters = new List<IConnectionAdapter>(),
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = _pipeFactory
},
PipeFactory = _pipeFactory,
FrameConnectionId = long.MinValue,
Input = _pipeFactory.Create(),
Output = _pipeFactory.Create(),

View File

@ -21,10 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var frameContext = new FrameContext
{
ServiceContext = new TestServiceContext(),
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = new PipeFactory()
},
PipeFactory = new PipeFactory(),
TimeoutControl = null
};

View File

@ -60,10 +60,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_frameContext = new FrameContext
{
ServiceContext = _serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = _pipelineFactory
},
PipeFactory = _pipelineFactory,
TimeoutControl = _timeoutControl.Object,
Input = _input.Reader,
Output = output

View File

@ -26,10 +26,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
ServiceContext = new TestServiceContext(),
Input = Pipe.Reader,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = _pipelineFactory
},
PipeFactory = _pipelineFactory,
TimeoutControl = Mock.Of<ITimeoutControl>()
};

View File

@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;

View File

@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
[Benchmark]
public IHttpSendFileFeature GetLastViaGeneric()
{
return _collection.Get<IHttpSendFileFeature> ();
return _collection.Get<IHttpSendFileFeature>();
}
private object Get(Type type)
@ -85,10 +85,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var frameContext = new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = new PipeFactory()
}
PipeFactory = new PipeFactory()
};
_frame = new Frame<object>(application: null, frameContext: frameContext);

View File

@ -29,10 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var frameContext = new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = new PipeFactory()
},
PipeFactory = new PipeFactory(),
TimeoutControl = new MockTimeoutControl()
};

View File

@ -90,10 +90,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var frame = new TestFrame<object>(application: null, context: new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = pipeFactory
},
PipeFactory = pipeFactory,
Input = input.Reader,
Output = output
});

View File

@ -1,20 +0,0 @@
// 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;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
public class MockConnectionInformation : IConnectionInformation
{
public IPEndPoint RemoteEndPoint { get; }
public IPEndPoint LocalEndPoint { get; }
public PipeFactory PipeFactory { get; set; }
public bool RequiresDispatch { get; }
public IScheduler InputWriterScheduler { get; }
public IScheduler OutputReaderScheduler { get; }
}
}

View File

@ -33,10 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var frameContext = new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = PipeFactory
},
PipeFactory = PipeFactory,
TimeoutControl = new MockTimeoutControl()
};

View File

@ -177,10 +177,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var frameContext = new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = new PipeFactory()
}
PipeFactory = new PipeFactory()
};
var frame = new Frame<object>(application: null, frameContext: frameContext);

View File

@ -124,10 +124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var frame = new TestFrame<object>(application: null, context: new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = pipeFactory
},
PipeFactory = pipeFactory,
TimeoutControl = new MockTimeoutControl(),
Input = input.Reader,
Output = output

View File

@ -699,10 +699,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
var frame = new Frame<object>(null, new FrameContext
{
ServiceContext = serviceContext,
ConnectionInformation = new MockConnectionInformation
{
PipeFactory = _pipeFactory
},
PipeFactory = _pipeFactory,
TimeoutControl = Mock.Of<ITimeoutControl>(),
Output = pipe
});

View File

@ -3,6 +3,9 @@
using System;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Protocols.Features;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
@ -12,26 +15,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
public PipeOptions InputOptions { get; set; } = new PipeOptions();
public PipeOptions OutputOptions { get; set; } = new PipeOptions();
public IConnectionContext OnConnection(IConnectionInformation connectionInfo)
public void OnConnection(IFeatureCollection features)
{
Input = connectionInfo.PipeFactory.Create(InputOptions ?? new PipeOptions());
Output = connectionInfo.PipeFactory.Create(OutputOptions ?? new PipeOptions());
var connectionContext = new DefaultConnectionContext(features);
return new TestConnectionContext
Input = connectionContext.PipeFactory.Create(InputOptions ?? new PipeOptions());
Output = connectionContext.PipeFactory.Create(OutputOptions ?? new PipeOptions());
var context = new TestConnectionContext
{
Input = Input.Writer,
Output = Output.Reader,
Connection = new PipeConnection(Output.Reader, Input.Writer)
};
connectionContext.Features.Set<IConnectionApplicationFeature>(context);
}
public IPipe Input { get; private set; }
public IPipe Output { get; private set; }
private class TestConnectionContext : IConnectionContext
private class TestConnectionContext : IConnectionApplicationFeature
{
public string ConnectionId { get; }
public IPipeWriter Input { get; set; }
public IPipeReader Output { get; set; }
public IPipeConnection Connection { get; set; }
public void Abort(Exception ex)
{

View File

@ -1,22 +0,0 @@
// 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.IO.Pipelines;
using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Testing
{
public class MockConnectionInformation : IConnectionInformation
{
public IPEndPoint RemoteEndPoint { get; }
public IPEndPoint LocalEndPoint { get; }
public PipeFactory PipeFactory { get; set; }
public IScheduler InputWriterScheduler { get; }
public IScheduler OutputReaderScheduler { get; }
}
}