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:
parent
f3745608af
commit
5c775073a4
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||
namespace Microsoft.AspNetCore.Protocols
|
||||
{
|
||||
public class AddressInUseException : InvalidOperationException
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||
namespace Microsoft.AspNetCore.Protocols
|
||||
{
|
||||
public class ConnectionAbortedException : OperationCanceledException
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue