React to pipes in corefx (#2337)

This commit is contained in:
Pavel Krymets 2018-02-28 12:41:51 -08:00 committed by GitHub
parent a3911269c5
commit 2c108d9ba1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 715 additions and 258 deletions

View File

@ -17,5 +17,7 @@
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign> <PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<!-- https://github.com/aspnet/KestrelHttpServer/issues/2350 -->
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks; using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
@ -16,13 +17,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
private const int InnerLoopCount = 512; private const int InnerLoopCount = 512;
public ReadOnlyBuffer<byte> _buffer; public ReadOnlySequence<byte> _buffer;
public Http1Connection _http1Connection; public Http1Connection _http1Connection;
[IterationSetup] [IterationSetup]
public void Setup() public void Setup()
{ {
var memoryPool = new MemoryPool(); var memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(memoryPool); var pair = DuplexPipe.CreateConnectionPair(memoryPool);
var serviceContext = new ServiceContext var serviceContext = new ServiceContext

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
@ -24,15 +25,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private static readonly Task _psuedoAsyncTask = Task.FromResult(27); private static readonly Task _psuedoAsyncTask = Task.FromResult(27);
private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask; private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask;
private readonly TestHttp1Connection _http1Connection; private TestHttp1Connection _http1Connection;
private DuplexPipe.DuplexPipePair _pair; private DuplexPipe.DuplexPipePair _pair;
private MemoryPool<byte> _memoryPool;
private readonly byte[] _writeData; private readonly byte[] _writeData = Encoding.ASCII.GetBytes("Hello, World!");
public Http1WritingBenchmark() [GlobalSetup]
public void GlobalSetup()
{ {
_memoryPool = KestrelMemoryPool.Create();
_http1Connection = MakeHttp1Connection(); _http1Connection = MakeHttp1Connection();
_writeData = Encoding.ASCII.GetBytes("Hello, World!");
} }
[Params(true, false)] [Params(true, false)]
@ -93,33 +96,30 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private TestHttp1Connection MakeHttp1Connection() private TestHttp1Connection MakeHttp1Connection()
{ {
using (var memoryPool = new MemoryPool()) var pair = DuplexPipe.CreateConnectionPair(_memoryPool);
_pair = pair;
var serviceContext = new ServiceContext
{ {
var pair = DuplexPipe.CreateConnectionPair(memoryPool); DateHeaderValueManager = new DateHeaderValueManager(),
_pair = pair; ServerOptions = new KestrelServerOptions(),
Log = new MockTrace(),
HttpParser = new HttpParser<Http1ParsingHandler>()
};
var serviceContext = new ServiceContext var http1Connection = new TestHttp1Connection(new Http1ConnectionContext
{ {
DateHeaderValueManager = new DateHeaderValueManager(), ServiceContext = serviceContext,
ServerOptions = new KestrelServerOptions(), ConnectionFeatures = new FeatureCollection(),
Log = new MockTrace(), MemoryPool = _memoryPool,
HttpParser = new HttpParser<Http1ParsingHandler>() Application = pair.Application,
}; Transport = pair.Transport
});
var http1Connection = new TestHttp1Connection(new Http1ConnectionContext http1Connection.Reset();
{ http1Connection.InitializeStreams(MessageBody.ZeroContentLengthKeepAlive);
ServiceContext = serviceContext,
ConnectionFeatures = new FeatureCollection(),
MemoryPool = memoryPool,
Application = pair.Application,
Transport = pair.Transport
});
http1Connection.Reset(); return http1Connection;
http1Connection.InitializeStreams(MessageBody.ZeroContentLengthKeepAlive);
return http1Connection;
}
} }
[IterationCleanup] [IterationCleanup]
@ -138,5 +138,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
Sync, Sync,
Async Async
} }
[GlobalCleanup]
public void Dispose()
{
_memoryPool?.Dispose();
}
} }
} }

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
private readonly HttpParser<Adapter> _parser = new HttpParser<Adapter>(); private readonly HttpParser<Adapter> _parser = new HttpParser<Adapter>();
private ReadOnlyBuffer<byte> _buffer; private ReadOnlySequence<byte> _buffer;
[Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)] [Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)]
public void PlaintextTechEmpower() public void PlaintextTechEmpower()
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private void InsertData(byte[] data) private void InsertData(byte[] data)
{ {
_buffer = new ReadOnlyBuffer<byte>(data); _buffer = new ReadOnlySequence<byte>(data);
} }
private void ParseData() private void ParseData()

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
@ -78,7 +79,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
public HttpProtocolFeatureCollection() public HttpProtocolFeatureCollection()
{ {
var memoryPool = new MemoryPool(); var memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(memoryPool); var pair = DuplexPipe.CreateConnectionPair(memoryPool);
var serviceContext = new ServiceContext var serviceContext = new ServiceContext

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
public static readonly NullParser<Http1ParsingHandler> Instance = new NullParser<Http1ParsingHandler>(); public static readonly NullParser<Http1ParsingHandler> Instance = new NullParser<Http1ParsingHandler>();
public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes) public bool ParseHeaders(TRequestHandler handler, ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
{ {
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue)); handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue)); handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
return true; return true;
} }
public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) public bool ParseRequestLine(TRequestHandler handler, ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
handler.OnStartLine(HttpMethod.Get, handler.OnStartLine(HttpMethod.Get,
HttpVersion.Http11, HttpVersion.Http11,

View File

@ -1,10 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Buffers; using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Threading.Tasks; using System.Threading.Tasks;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
@ -14,12 +16,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private const int InnerLoopCount = 512; private const int InnerLoopCount = 512;
private Pipe _pipe; private Pipe _pipe;
private MemoryPool _memoryPool; private MemoryPool<byte> _memoryPool;
[IterationSetup] [IterationSetup]
public void Setup() public void Setup()
{ {
_memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
_pipe = new Pipe(new PipeOptions(_memoryPool)); _pipe = new Pipe(new PipeOptions(_memoryPool));
} }
@ -62,5 +64,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
_pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); _pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
} }
} }
[IterationCleanup]
public void Cleanup()
{
_memoryPool.Dispose();
}
} }
} }

View File

@ -9,11 +9,14 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks; using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
public class RequestParsingBenchmark public class RequestParsingBenchmark
{ {
private MemoryPool<byte> _memoryPool;
public Pipe Pipe { get; set; } public Pipe Pipe { get; set; }
public Http1Connection Http1Connection { get; set; } public Http1Connection Http1Connection { get; set; }
@ -21,8 +24,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
[IterationSetup] [IterationSetup]
public void Setup() public void Setup()
{ {
var memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(memoryPool); var pair = DuplexPipe.CreateConnectionPair(_memoryPool);
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
ServiceContext = serviceContext, ServiceContext = serviceContext,
ConnectionFeatures = new FeatureCollection(), ConnectionFeatures = new FeatureCollection(),
MemoryPool = memoryPool, MemoryPool = _memoryPool,
Application = pair.Application, Application = pair.Application,
Transport = pair.Transport, Transport = pair.Transport,
TimeoutControl = new MockTimeoutControl() TimeoutControl = new MockTimeoutControl()
@ -45,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
http1Connection.Reset(); http1Connection.Reset();
Http1Connection = http1Connection; Http1Connection = http1Connection;
Pipe = new Pipe(new PipeOptions(memoryPool)); Pipe = new Pipe(new PipeOptions(_memoryPool));
} }
[Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)] [Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)]
@ -201,5 +204,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
} }
while (true); while (true);
} }
[IterationCleanup]
public void Cleanup()
{
_memoryPool.Dispose();
}
} }
} }

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
[IterationSetup] [IterationSetup]
public void Setup() public void Setup()
{ {
var memoryPool = new MemoryPool(); var memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(memoryPool); var pair = DuplexPipe.CreateConnectionPair(memoryPool);
var serviceContext = new ServiceContext var serviceContext = new ServiceContext

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks; using Microsoft.AspNetCore.Server.Kestrel.Performance.Mocks;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance namespace Microsoft.AspNetCore.Server.Kestrel.Performance
@ -23,6 +24,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private TestHttp1Connection _http1Connection; private TestHttp1Connection _http1Connection;
private MemoryPool<byte> _memoryPool;
[Params( [Params(
BenchmarkTypes.TechEmpowerPlaintext, BenchmarkTypes.TechEmpowerPlaintext,
BenchmarkTypes.PlaintextChunked, BenchmarkTypes.PlaintextChunked,
@ -110,8 +113,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
[IterationSetup] [IterationSetup]
public void Setup() public void Setup()
{ {
var memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(memoryPool); var pair = DuplexPipe.CreateConnectionPair(_memoryPool);
var serviceContext = new ServiceContext var serviceContext = new ServiceContext
{ {
@ -125,7 +128,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
ServiceContext = serviceContext, ServiceContext = serviceContext,
ConnectionFeatures = new FeatureCollection(), ConnectionFeatures = new FeatureCollection(),
MemoryPool = memoryPool, MemoryPool = _memoryPool,
TimeoutControl = new MockTimeoutControl(), TimeoutControl = new MockTimeoutControl(),
Application = pair.Application, Application = pair.Application,
Transport = pair.Transport Transport = pair.Transport
@ -136,6 +139,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
_http1Connection = http1Connection; _http1Connection = http1Connection;
} }
[IterationCleanup]
public void Cleanup()
{
_memoryPool.Dispose();
}
public enum BenchmarkTypes public enum BenchmarkTypes
{ {
TechEmpowerPlaintext, TechEmpowerPlaintext,

View File

@ -5,40 +5,39 @@
<!-- This files is typically managed by automation. Execute 'run.ps1 upgrade deps' to update these variables to the last-known-good versions. --> <!-- This files is typically managed by automation. Execute 'run.ps1 upgrade deps' to update these variables to the last-known-good versions. -->
<PropertyGroup Label="Package Versions"> <PropertyGroup Label="Package Versions">
<BenchmarkDotNetPackageVersion>0.10.11</BenchmarkDotNetPackageVersion> <BenchmarkDotNetPackageVersion>0.10.11</BenchmarkDotNetPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview2-15721</InternalAspNetCoreSdkPackageVersion> <InternalAspNetCoreSdkPackageVersion>2.1.0-preview2-15707</InternalAspNetCoreSdkPackageVersion>
<LibuvPackageVersion>1.10.0</LibuvPackageVersion> <LibuvPackageVersion>1.10.0</LibuvPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion> <MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion> <MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreHostingAbstractionsPackageVersion> <MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreHostingPackageVersion> <MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreHttpAbstractionsPackageVersion> <MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreHttpFeaturesPackageVersion> <MicrosoftAspNetCoreHttpFeaturesPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreHttpFeaturesPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreHttpPackageVersion> <MicrosoftAspNetCoreHttpPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreTestingPackageVersion> <MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview2-30187</MicrosoftAspNetCoreWebUtilitiesPackageVersion> <MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview2-30131</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsConfigurationBinderPackageVersion> <MicrosoftExtensionsBuffersSourcesPackageVersion>2.1.0-preview2-t000</MicrosoftExtensionsBuffersSourcesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsConfigurationJsonPackageVersion> <MicrosoftExtensionsConfigurationBinderPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsConfigurationBinderPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsDependencyInjectionPackageVersion> <MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsLoggingAbstractionsPackageVersion> <MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsLoggingConsolePackageVersion> <MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsLoggingPackageVersion> <MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsLoggingTestingPackageVersion> <MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview2-30187</MicrosoftExtensionsOptionsPackageVersion> <MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview2-30131</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion> <MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26130-04</MicrosoftNETCoreApp21PackageVersion> <MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26225-03</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30187</MicrosoftNetHttpHeadersPackageVersion> <MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30131</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.0</MicrosoftNETTestSdkPackageVersion> <MicrosoftNETTestSdkPackageVersion>15.3.0</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion> <MoqPackageVersion>4.7.49</MoqPackageVersion>
<NewtonsoftJsonPackageVersion>10.0.1</NewtonsoftJsonPackageVersion> <NewtonsoftJsonPackageVersion>10.0.1</NewtonsoftJsonPackageVersion>
<SystemBuffersPackageVersion>4.5.0-preview2-26130-01</SystemBuffersPackageVersion> <SystemBuffersPackageVersion>4.5.0-preview2-26224-02</SystemBuffersPackageVersion>
<SystemBuffersPrimitivesPackageVersion>0.1.0-preview2-180130-1</SystemBuffersPrimitivesPackageVersion> <SystemIOPipelinesPackageVersion>4.5.0-preview2-26224-02</SystemIOPipelinesPackageVersion>
<SystemIOPipelinesPackageVersion>0.1.0-preview2-180130-1</SystemIOPipelinesPackageVersion> <SystemMemoryPackageVersion>4.5.0-preview2-26224-02</SystemMemoryPackageVersion>
<SystemMemoryPackageVersion>4.5.0-preview2-26130-01</SystemMemoryPackageVersion> <SystemNumericsVectorsPackageVersion>4.5.0-preview2-26224-02</SystemNumericsVectorsPackageVersion>
<SystemNumericsVectorsPackageVersion>4.5.0-preview2-26130-01</SystemNumericsVectorsPackageVersion> <SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview2-26224-02</SystemRuntimeCompilerServicesUnsafePackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview2-26130-01</SystemRuntimeCompilerServicesUnsafePackageVersion> <SystemSecurityCryptographyCngPackageVersion>4.5.0-preview2-26224-02</SystemSecurityCryptographyCngPackageVersion>
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview2-26130-01</SystemSecurityCryptographyCngPackageVersion> <SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview2-26224-02</SystemThreadingTasksExtensionsPackageVersion>
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-preview2-180130-1</SystemTextEncodingsWebUtf8PackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview2-26130-01</SystemThreadingTasksExtensionsPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion> <XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion> <XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion> <XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>

View File

@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
try try
{ {
if (result.IsCancelled) if (result.IsCanceled)
{ {
// Forward the cancellation to the transport pipe // Forward the cancellation to the transport pipe
_application.Input.CancelPendingRead(); _application.Input.CancelPendingRead();
@ -132,26 +132,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
{ {
var outputBuffer = Input.Writer.GetMemory(MinAllocBufferSize); var outputBuffer = Input.Writer.GetMemory(MinAllocBufferSize);
try
{
#if NETCOREAPP2_1 #if NETCOREAPP2_1
var bytesRead = await stream.ReadAsync(outputBuffer); var bytesRead = await stream.ReadAsync(outputBuffer);
#else #else
var array = outputBuffer.GetArray(); var array = outputBuffer.GetArray();
var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count); var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count);
#endif #endif
Input.Writer.Advance(bytesRead); Input.Writer.Advance(bytesRead);
if (bytesRead == 0) if (bytesRead == 0)
{
// FIN
break;
}
}
finally
{ {
Input.Writer.Commit(); // FIN
break;
} }
var result = await Input.Writer.FlushAsync(); var result = await Input.Writer.FlushAsync();
@ -160,7 +152,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
{ {
break; break;
} }
} }
} }
catch (Exception ex) catch (Exception ex)

View File

@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
} }
// Internal for testing // Internal for testing
internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler writerScheduler) => new PipeOptions internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool<byte> memoryPool, PipeScheduler writerScheduler) => new PipeOptions
( (
pool: memoryPool, pool: memoryPool,
readerScheduler: serviceContext.ThreadPool, readerScheduler: serviceContext.ThreadPool,
@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
); );
internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler readerScheduler) => new PipeOptions internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool<byte> memoryPool, PipeScheduler readerScheduler) => new PipeOptions
( (
pool: memoryPool, pool: memoryPool,
readerScheduler: readerScheduler, readerScheduler: readerScheduler,

View File

@ -8,7 +8,7 @@ using System.Text;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
public static class ChunkWriter internal static class ChunkWriter
{ {
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n"); private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
private static readonly byte[] _hex = Encoding.ASCII.GetBytes("0123456789abcdef"); private static readonly byte[] _hex = Encoding.ASCII.GetBytes("0123456789abcdef");
@ -48,14 +48,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return new ArraySegment<byte>(bytes, offset, 10 - offset); return new ArraySegment<byte>(bytes, offset, 10 - offset);
} }
public static int WriteBeginChunkBytes(ref OutputWriter<PipeWriter> start, int dataCount) internal static int WriteBeginChunkBytes(ref BufferWriter<PipeWriter> start, int dataCount)
{ {
var chunkSegment = BeginChunkBytes(dataCount); var chunkSegment = BeginChunkBytes(dataCount);
start.Write(new ReadOnlySpan<byte>(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count)); start.Write(new ReadOnlySpan<byte>(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count));
return chunkSegment.Count; return chunkSegment.Count;
} }
public static void WriteEndChunkBytes(ref OutputWriter<PipeWriter> start) internal static void WriteEndChunkBytes(ref BufferWriter<PipeWriter> start)
{ {
start.Write(new ReadOnlySpan<byte>(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count)); start.Write(new ReadOnlySpan<byte>(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count));
} }

View File

@ -8,9 +8,10 @@ using System.Diagnostics;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.Encodings.Web.Utf8; using System.Text.Encodings.Web;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
@ -69,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Input.CancelPendingRead(); Input.CancelPendingRead();
} }
public void ParseRequest(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) public void ParseRequest(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -107,7 +108,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
public bool TakeStartLine(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) public bool TakeStartLine(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
var overLength = false; var overLength = false;
if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize) if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize)
@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return result; return result;
} }
public bool TakeMessageHeaders(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) public bool TakeMessageHeaders(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
// Make sure the buffer is limited // Make sure the buffer is limited
bool overLength = false; bool overLength = false;
@ -217,9 +218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
// URI was encoded, unescape and then parse as UTF-8 // URI was encoded, unescape and then parse as UTF-8
// Disabling warning temporary // Disabling warning temporary
#pragma warning disable 618 var pathLength = UrlDecoder.Decode(path, path);
var pathLength = UrlEncoder.Decode(path, path);
#pragma warning restore 618
// Removing dot segments must be done after unescaping. From RFC 3986: // Removing dot segments must be done after unescaping. From RFC 3986:
// //
@ -430,7 +429,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutAction.StopProcessingNextRequest); TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutAction.StopProcessingNextRequest);
} }
protected override bool BeginRead(out ValueAwaiter<ReadResult> awaitable) protected override bool BeginRead(out PipeAwaiter<ReadResult> awaitable)
{ {
awaitable = Input.ReadAsync(); awaitable = Input.ReadAsync();
return true; return true;

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public string ConnectionId { get; set; } public string ConnectionId { get; set; }
public ServiceContext ServiceContext { get; set; } public ServiceContext ServiceContext { get; set; }
public IFeatureCollection ConnectionFeatures { get; set; } public IFeatureCollection ConnectionFeatures { get; set; }
public MemoryPool MemoryPool { get; set; } public MemoryPool<byte> MemoryPool { get; set; }
public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; }
public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; }
public ITimeoutControl TimeoutControl { get; set; } public ITimeoutControl TimeoutControl { get; set; }

View File

@ -8,6 +8,7 @@ using System.IO;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Protocols.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
@ -63,15 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
if (!readableBuffer.IsEmpty) if (!readableBuffer.IsEmpty)
{ {
bool done; bool done;
done = Read(readableBuffer, _context.RequestBodyPipe.Writer, out consumed, out examined);
try
{
done = Read(readableBuffer, _context.RequestBodyPipe.Writer, out consumed, out examined);
}
finally
{
_context.RequestBodyPipe.Writer.Commit();
}
var writeAwaitable = _context.RequestBodyPipe.Writer.FlushAsync(); var writeAwaitable = _context.RequestBodyPipe.Writer.FlushAsync();
var backpressure = false; var backpressure = false;
@ -150,7 +143,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
protected void Copy(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer) protected void Copy(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer)
{ {
_context.TimeoutControl.BytesRead(readableBuffer.Length); _context.TimeoutControl.BytesRead(readableBuffer.Length);
@ -172,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_pumpTask = PumpAsync(); _pumpTask = PumpAsync();
} }
protected virtual bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) protected virtual bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -295,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public override bool IsEmpty => true; public override bool IsEmpty => true;
protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
Copy(readableBuffer, writableBuffer); Copy(readableBuffer, writableBuffer);
consumed = readableBuffer.End; consumed = readableBuffer.End;
@ -317,7 +310,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_inputLength = _contentLength; _inputLength = _contentLength;
} }
protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
if (_inputLength == 0) if (_inputLength == 0)
{ {
@ -365,7 +358,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
RequestKeepAlive = keepAlive; RequestKeepAlive = keepAlive;
} }
protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = default(SequencePosition); consumed = default(SequencePosition);
examined = default(SequencePosition); examined = default(SequencePosition);
@ -456,11 +449,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private void ParseChunkedPrefix(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) private void ParseChunkedPrefix(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.Start; examined = buffer.Start;
var reader = BufferReader.Create(buffer); var reader = new BufferReader(buffer);
var ch1 = reader.Read(); var ch1 = reader.Read();
var ch2 = reader.Read(); var ch2 = reader.Read();
@ -512,7 +505,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData); BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData);
} }
private void ParseExtension(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) private void ParseExtension(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
// Chunk-extensions not currently parsed // Chunk-extensions not currently parsed
// Just drain the data // Just drain the data
@ -565,7 +558,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} while (_mode == Mode.Extension); } while (_mode == Mode.Extension);
} }
private void ReadChunkedData(ReadOnlyBuffer<byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) private void ReadChunkedData(ReadOnlySequence<byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
var actual = Math.Min(buffer.Length, _inputLength); var actual = Math.Min(buffer.Length, _inputLength);
consumed = buffer.GetPosition(buffer.Start, actual); consumed = buffer.GetPosition(buffer.Start, actual);
@ -582,7 +575,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private void ParseChunkedSuffix(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) private void ParseChunkedSuffix(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.Start; examined = buffer.Start;
@ -608,7 +601,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private void ParseChunkedTrailer(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) private void ParseChunkedTrailer(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.Start; examined = buffer.Start;

View File

@ -84,7 +84,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var buffer = _pipeWriter; var buffer = _pipeWriter;
callback(buffer, state); callback(buffer, state);
buffer.Commit();
} }
} }
@ -99,7 +98,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var buffer = _pipeWriter; var buffer = _pipeWriter;
callback(buffer, state); callback(buffer, state);
buffer.Commit();
} }
return FlushAsync(); return FlushAsync();
@ -115,14 +113,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
var buffer = _pipeWriter; var buffer = _pipeWriter;
var writer = OutputWriter.Create(buffer); var writer = new BufferWriter<PipeWriter>(buffer);
writer.Write(_bytesHttpVersion11); writer.Write(_bytesHttpVersion11);
var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase); var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase);
writer.Write(statusBytes); writer.Write(statusBytes);
responseHeaders.CopyTo(ref writer); responseHeaders.CopyTo(ref writer);
writer.Write(_bytesEndHeaders); writer.Write(_bytesEndHeaders);
buffer.Commit(); writer.Commit();
} }
} }
@ -177,14 +175,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
writableBuffer = _pipeWriter; writableBuffer = _pipeWriter;
var writer = OutputWriter.Create(writableBuffer); var writer = new BufferWriter<PipeWriter>(writableBuffer);
if (buffer.Length > 0) if (buffer.Length > 0)
{ {
writer.Write(buffer); writer.Write(buffer);
bytesWritten += buffer.Length; bytesWritten += buffer.Length;
} }
writer.Commit();
writableBuffer.Commit();
} }
return FlushAsync(writableBuffer, bytesWritten, cancellationToken); return FlushAsync(writableBuffer, bytesWritten, cancellationToken);
@ -203,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return FlushAsyncAwaited(awaitable, bytesWritten, cancellationToken); return FlushAsyncAwaited(awaitable, bytesWritten, cancellationToken);
} }
private async Task FlushAsyncAwaited(ValueAwaiter<FlushResult> awaitable, long count, CancellationToken cancellationToken) private async Task FlushAsyncAwaited(PipeAwaiter<FlushResult> awaitable, long count, CancellationToken cancellationToken)
{ {
// https://github.com/dotnet/corefxlab/issues/1334 // https://github.com/dotnet/corefxlab/issues/1334
// Since the flush awaitable doesn't currently support multiple awaiters // Since the flush awaitable doesn't currently support multiple awaiters

View File

@ -7754,7 +7754,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true; return true;
} }
protected void CopyToFast(ref OutputWriter<PipeWriter> output) internal void CopyToFast(ref BufferWriter<PipeWriter> output)
{ {
var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0); var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0);

View File

@ -7,6 +7,7 @@ using System.Collections;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Protocols.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private const byte ByteQuestionMark = (byte)'?'; private const byte ByteQuestionMark = (byte)'?';
private const byte BytePercentage = (byte)'%'; private const byte BytePercentage = (byte)'%';
public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined) public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -188,7 +189,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded); handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded);
} }
public unsafe bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes) public unsafe bool ParseHeaders(TRequestHandler handler, ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -196,8 +197,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var bufferEnd = buffer.End; var bufferEnd = buffer.End;
var reader = BufferReader.Create(buffer); var reader = new BufferReader(buffer);
var start = default(BufferReader<ReadOnlyBuffer<byte>>); var start = default(BufferReader);
var done = false; var done = false;
try try
@ -418,7 +419,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private static bool TryGetNewLine(ref ReadOnlyBuffer<byte> buffer, out SequencePosition found) private static bool TryGetNewLine(ref ReadOnlySequence<byte> buffer, out SequencePosition found)
{ {
var byteLfPosition = buffer.PositionOf(ByteLF); var byteLfPosition = buffer.PositionOf(ByteLF);
if (byteLfPosition != null) if (byteLfPosition != null)

View File

@ -383,7 +383,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
} }
protected virtual bool BeginRead(out ValueAwaiter<ReadResult> awaitable) protected virtual bool BeginRead(out PipeAwaiter<ReadResult> awaitable)
{ {
awaitable = default; awaitable = default;
return false; return false;
@ -930,12 +930,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private static void WriteChunk(PipeWriter writableBuffer, ReadOnlyMemory<byte> buffer) private static void WriteChunk(PipeWriter writableBuffer, ReadOnlyMemory<byte> buffer)
{ {
var writer = OutputWriter.Create(writableBuffer); var writer = new BufferWriter<PipeWriter>(writableBuffer);
if (buffer.Length > 0) if (buffer.Length > 0)
{ {
ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Length); ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Length);
writer.Write(buffer.Span); writer.Write(buffer.Span);
ChunkWriter.WriteEndChunkBytes(ref writer); ChunkWriter.WriteEndChunkBytes(ref writer);
writer.Commit();
} }
} }

View File

@ -35,9 +35,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return GetEnumerator(); return GetEnumerator();
} }
public void CopyTo(ref OutputWriter<PipeWriter> output) internal void CopyTo(ref BufferWriter<PipeWriter> buffer)
{ {
CopyToFast(ref output); CopyToFast(ref buffer);
if (MaybeUnknown != null) if (MaybeUnknown != null)
{ {
foreach (var kv in MaybeUnknown) foreach (var kv in MaybeUnknown)
@ -46,10 +46,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
if (value != null) if (value != null)
{ {
output.Write(_CrLf); buffer.Write(_CrLf);
PipelineExtensions.WriteAsciiNoValidation(ref output, kv.Key); PipelineExtensions.WriteAsciiNoValidation(ref buffer, kv.Key);
output.Write(_colonSpace); buffer.Write(_colonSpace);
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref buffer, value);
} }
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
@ -8,8 +9,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
public interface IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler public interface IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
{ {
bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined); bool ParseRequestLine(TRequestHandler handler, ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined);
bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes); bool ParseHeaders(TRequestHandler handler, ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes);
} }
} }

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
string ConnectionId { get; set; } string ConnectionId { get; set; }
ServiceContext ServiceContext { get; set; } ServiceContext ServiceContext { get; set; }
IFeatureCollection ConnectionFeatures { get; set; } IFeatureCollection ConnectionFeatures { get; set; }
MemoryPool MemoryPool { get; set; } MemoryPool<byte> MemoryPool { get; set; }
IPEndPoint RemoteEndPoint { get; set; } IPEndPoint RemoteEndPoint { get; set; }
IPEndPoint LocalEndPoint { get; set; } IPEndPoint LocalEndPoint { get; set; }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private static byte[] _numericBytesScratch; private static byte[] _numericBytesScratch;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<byte> ToSpan(this ReadOnlyBuffer<byte> buffer) public static ReadOnlySpan<byte> ToSpan(this ReadOnlySequence<byte> buffer)
{ {
if (buffer.IsSingleSegment) if (buffer.IsSingleSegment)
{ {
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return result; return result;
} }
public unsafe static void WriteAsciiNoValidation(ref this OutputWriter<PipeWriter> buffer, string data) internal static unsafe void WriteAsciiNoValidation(ref this BufferWriter<PipeWriter> buffer, string data)
{ {
if (string.IsNullOrEmpty(data)) if (string.IsNullOrEmpty(data))
{ {
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void WriteNumeric(ref this OutputWriter<PipeWriter> buffer, ulong number) internal static unsafe void WriteNumeric(ref this BufferWriter<PipeWriter> buffer, ulong number)
{ {
const byte AsciiDigitStart = (byte)'0'; const byte AsciiDigitStart = (byte)'0';
@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private static void WriteNumericMultiWrite(ref this OutputWriter<PipeWriter> buffer, ulong number) private static void WriteNumericMultiWrite(ref this BufferWriter<PipeWriter> buffer, ulong number)
{ {
const byte AsciiDigitStart = (byte)'0'; const byte AsciiDigitStart = (byte)'0';
@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private unsafe static void WriteAsciiMultiWrite(ref this OutputWriter<PipeWriter> buffer, string data) private unsafe static void WriteAsciiMultiWrite(ref this BufferWriter<PipeWriter> buffer, string data)
{ {
var remaining = data.Length; var remaining = data.Length;
@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private unsafe static void EncodeAsciiCharsToBytes(char* input, byte* output, int length) private static unsafe void EncodeAsciiCharsToBytes(char* input, byte* output, int length)
{ {
// Note: Not BIGENDIAN or check for non-ascii // Note: Not BIGENDIAN or check for non-ascii
const int Shift16Shift24 = (1 << 16) | (1 << 24); const int Shift16Shift24 = (1 << 16) | (1 << 24);

View File

@ -0,0 +1,411 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.AspNetCore.Protocols.Abstractions
{
internal class UrlDecoder
{
static bool[] IsAllowed = new bool[0x7F + 1];
/// <summary>
/// Unescape a URL path
/// </summary>
/// <param name="source">The byte span represents a UTF8 encoding url path.</param>
/// <param name="destination">The byte span where unescaped url path is copied to.</param>
/// <returns>The length of the byte sequence of the unescaped url path.</returns>
public static int Decode(ReadOnlySpan<byte> source, Span<byte> destination)
{
if (destination.Length < source.Length)
{
throw new ArgumentException(
"Lenghth of the destination byte span is less then the source.",
nameof(destination));
}
// This requires the destination span to be larger or equal to source span
source.CopyTo(destination);
return DecodeInPlace(destination);
}
/// <summary>
/// Unescape a URL path in place.
/// </summary>
/// <param name="buffer">The byte span represents a UTF8 encoding url path.</param>
/// <returns>The number of the bytes representing the result.</returns>
/// <remarks>
/// The unescape is done in place, which means after decoding the result is the subset of
/// the input span.
/// </remarks>
public static int DecodeInPlace(Span<byte> buffer)
{
// the slot to read the input
var sourceIndex = 0;
// the slot to write the unescaped byte
var destinationIndex = 0;
while (true)
{
if (sourceIndex == buffer.Length)
{
break;
}
if (buffer[sourceIndex] == '%')
{
var decodeIndex = sourceIndex;
// If decoding process succeeds, the writer iterator will be moved
// to the next write-ready location. On the other hand if the scanned
// percent-encodings cannot be interpreted as sequence of UTF-8 octets,
// these bytes should be copied to output as is.
// The decodeReader iterator is always moved to the first byte not yet
// be scanned after the process. A failed decoding means the chars
// between the reader and decodeReader can be copied to output untouched.
if (!DecodeCore(ref decodeIndex, ref destinationIndex, buffer))
{
Copy(sourceIndex, decodeIndex, ref destinationIndex, buffer);
}
sourceIndex = decodeIndex;
}
else
{
buffer[destinationIndex++] = buffer[sourceIndex++];
}
}
return destinationIndex;
}
/// <summary>
/// Unescape the percent-encodings
/// </summary>
/// <param name="sourceIndex">The iterator point to the first % char</param>
/// <param name="destinationIndex">The place to write to</param>
/// <param name="buffer">The byte array</param>
private static bool DecodeCore(ref int sourceIndex, ref int destinationIndex, Span<byte> buffer)
{
// preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets,
// bytes from this till the last scanned one will be copied to the memory pointed by writer.
var byte1 = UnescapePercentEncoding(ref sourceIndex, buffer);
if (byte1 == -1)
{
return false;
}
if (byte1 == 0)
{
throw new InvalidOperationException("The path contains null characters.");
}
if (byte1 <= 0x7F)
{
// first byte < U+007f, it is a single byte ASCII
buffer[destinationIndex++] = (byte)byte1;
return true;
}
int byte2 = 0, byte3 = 0, byte4 = 0;
// anticipate more bytes
var currentDecodeBits = 0;
var byteCount = 1;
var expectValueMin = 0;
if ((byte1 & 0xE0) == 0xC0)
{
// 110x xxxx, expect one more byte
currentDecodeBits = byte1 & 0x1F;
byteCount = 2;
expectValueMin = 0x80;
}
else if ((byte1 & 0xF0) == 0xE0)
{
// 1110 xxxx, expect two more bytes
currentDecodeBits = byte1 & 0x0F;
byteCount = 3;
expectValueMin = 0x800;
}
else if ((byte1 & 0xF8) == 0xF0)
{
// 1111 0xxx, expect three more bytes
currentDecodeBits = byte1 & 0x07;
byteCount = 4;
expectValueMin = 0x10000;
}
else
{
// invalid first byte
return false;
}
var remainingBytes = byteCount - 1;
while (remainingBytes > 0)
{
// read following three chars
if (sourceIndex == buffer.Length)
{
return false;
}
var nextSourceIndex = sourceIndex;
var nextByte = UnescapePercentEncoding(ref nextSourceIndex, buffer);
if (nextByte == -1)
{
return false;
}
if ((nextByte & 0xC0) != 0x80)
{
// the follow up byte is not in form of 10xx xxxx
return false;
}
currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F);
remainingBytes--;
if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F)
{
// this is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that
// are not allowed in UTF-8;
return false;
}
if (remainingBytes == 2 && currentDecodeBits >= 0x110)
{
// this is going to be out of the upper Unicode bound 0x10FFFF.
return false;
}
sourceIndex = nextSourceIndex;
if (byteCount - remainingBytes == 2)
{
byte2 = nextByte;
}
else if (byteCount - remainingBytes == 3)
{
byte3 = nextByte;
}
else if (byteCount - remainingBytes == 4)
{
byte4 = nextByte;
}
}
if (currentDecodeBits < expectValueMin)
{
// overlong encoding (e.g. using 2 bytes to encode something that only needed 1).
return false;
}
// all bytes are verified, write to the output
// TODO: measure later to determine if the performance of following logic can be improved
// the idea is to combine the bytes into short/int and write to span directly to avoid
// range check cost
if (byteCount > 0)
{
buffer[destinationIndex++] = (byte)byte1;
}
if (byteCount > 1)
{
buffer[destinationIndex++] = (byte)byte2;
}
if (byteCount > 2)
{
buffer[destinationIndex++] = (byte)byte3;
}
if (byteCount > 3)
{
buffer[destinationIndex++] = (byte)byte4;
}
return true;
}
private static void Copy(int begin, int end, ref int writer, Span<byte> buffer)
{
while (begin != end)
{
buffer[writer++] = buffer[begin++];
}
}
/// <summary>
/// Read the percent-encoding and try unescape it.
///
/// The operation first peek at the character the <paramref name="scan"/>
/// iterator points at. If it is % the <paramref name="scan"/> is then
/// moved on to scan the following to characters. If the two following
/// characters are hexadecimal literals they will be unescaped and the
/// value will be returned.
///
/// If the first character is not % the <paramref name="scan"/> iterator
/// will be removed beyond the location of % and -1 will be returned.
///
/// If the following two characters can't be successfully unescaped the
/// <paramref name="scan"/> iterator will be move behind the % and -1
/// will be returned.
/// </summary>
/// <param name="scan">The value to read</param>
/// <param name="buffer">The byte array</param>
/// <returns>The unescaped byte if success. Otherwise return -1.</returns>
private static int UnescapePercentEncoding(ref int scan, Span<byte> buffer)
{
if (buffer[scan++] != '%')
{
return -1;
}
var probe = scan;
var value1 = ReadHex(ref probe, buffer);
if (value1 == -1)
{
return -1;
}
var value2 = ReadHex(ref probe, buffer);
if (value2 == -1)
{
return -1;
}
if (SkipUnescape(value1, value2))
{
return -1;
}
scan = probe;
return (value1 << 4) + value2;
}
/// <summary>
/// Read the next char and convert it into hexadecimal value.
///
/// The <paramref name="scan"/> index will be moved to the next
/// byte no matter no matter whether the operation successes.
/// </summary>
/// <param name="scan">The index of the byte in the buffer to read</param>
/// <param name="buffer">The byte span from which the hex to be read</param>
/// <returns>The hexadecimal value if successes, otherwise -1.</returns>
private static int ReadHex(ref int scan, Span<byte> buffer)
{
if (scan == buffer.Length)
{
return -1;
}
var value = buffer[scan++];
var isHead = ((value >= '0') && (value <= '9')) ||
((value >= 'A') && (value <= 'F')) ||
((value >= 'a') && (value <= 'f'));
if (!isHead)
{
return -1;
}
if (value <= '9')
{
return value - '0';
}
else if (value <= 'F')
{
return (value - 'A') + 10;
}
else // a - f
{
return (value - 'a') + 10;
}
}
private static bool SkipUnescape(int value1, int value2)
{
// skip %2F - '/'
if (value1 == 2 && value2 == 15)
{
return true;
}
return false;
}
static UrlDecoder()
{
// Unreserved
IsAllowed['A'] = true;
IsAllowed['B'] = true;
IsAllowed['C'] = true;
IsAllowed['D'] = true;
IsAllowed['E'] = true;
IsAllowed['F'] = true;
IsAllowed['G'] = true;
IsAllowed['H'] = true;
IsAllowed['I'] = true;
IsAllowed['J'] = true;
IsAllowed['K'] = true;
IsAllowed['L'] = true;
IsAllowed['M'] = true;
IsAllowed['N'] = true;
IsAllowed['O'] = true;
IsAllowed['P'] = true;
IsAllowed['Q'] = true;
IsAllowed['R'] = true;
IsAllowed['S'] = true;
IsAllowed['T'] = true;
IsAllowed['U'] = true;
IsAllowed['V'] = true;
IsAllowed['W'] = true;
IsAllowed['X'] = true;
IsAllowed['Y'] = true;
IsAllowed['Z'] = true;
IsAllowed['a'] = true;
IsAllowed['b'] = true;
IsAllowed['c'] = true;
IsAllowed['d'] = true;
IsAllowed['e'] = true;
IsAllowed['f'] = true;
IsAllowed['g'] = true;
IsAllowed['h'] = true;
IsAllowed['i'] = true;
IsAllowed['j'] = true;
IsAllowed['k'] = true;
IsAllowed['l'] = true;
IsAllowed['m'] = true;
IsAllowed['n'] = true;
IsAllowed['o'] = true;
IsAllowed['p'] = true;
IsAllowed['q'] = true;
IsAllowed['r'] = true;
IsAllowed['s'] = true;
IsAllowed['t'] = true;
IsAllowed['u'] = true;
IsAllowed['v'] = true;
IsAllowed['w'] = true;
IsAllowed['x'] = true;
IsAllowed['y'] = true;
IsAllowed['z'] = true;
IsAllowed['0'] = true;
IsAllowed['1'] = true;
IsAllowed['2'] = true;
IsAllowed['3'] = true;
IsAllowed['4'] = true;
IsAllowed['5'] = true;
IsAllowed['6'] = true;
IsAllowed['7'] = true;
IsAllowed['8'] = true;
IsAllowed['9'] = true;
IsAllowed['-'] = true;
IsAllowed['_'] = true;
IsAllowed['.'] = true;
IsAllowed['~'] = true;
}
}
}

View File

@ -215,7 +215,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
} }
private bool ParsePreface(ReadOnlyBuffer<byte> readableBuffer, out SequencePosition consumed, out SequencePosition examined) private bool ParsePreface(ReadOnlySequence<byte> readableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = readableBuffer.Start; consumed = readableBuffer.Start;
examined = readableBuffer.End; examined = readableBuffer.End;

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public string ConnectionId { get; set; } public string ConnectionId { get; set; }
public ServiceContext ServiceContext { get; set; } public ServiceContext ServiceContext { get; set; }
public IFeatureCollection ConnectionFeatures { get; set; } public IFeatureCollection ConnectionFeatures { get; set; }
public MemoryPool MemoryPool { get; set; } public MemoryPool<byte> MemoryPool { get; set; }
public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; }
public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
@ -8,7 +9,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
public static class Http2FrameReader public static class Http2FrameReader
{ {
public static bool ReadFrame(ReadOnlyBuffer<byte> readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined) public static bool ReadFrame(ReadOnlySequence<byte> readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = readableBuffer.Start; consumed = readableBuffer.Start;
examined = readableBuffer.End; examined = readableBuffer.End;

View File

@ -190,7 +190,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
_outputWriter.Write(data); _outputWriter.Write(data);
_outputWriter.Commit();
} }
// Must be called with _writeLock // Must be called with _writeLock

View File

@ -83,14 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
if (data.Count > 0) if (data.Count > 0)
{ {
try RequestBodyPipe.Writer.Write(data);
{
RequestBodyPipe.Writer.Write(data);
}
finally
{
RequestBodyPipe.Writer.Commit();
}
RequestBodyStarted = true; RequestBodyStarted = true;
await RequestBodyPipe.Writer.FlushAsync(); await RequestBodyPipe.Writer.FlushAsync();

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public int StreamId { get; set; } public int StreamId { get; set; }
public ServiceContext ServiceContext { get; set; } public ServiceContext ServiceContext { get; set; }
public IFeatureCollection ConnectionFeatures { get; set; } public IFeatureCollection ConnectionFeatures { get; set; }
public MemoryPool MemoryPool { get; set; } public MemoryPool<byte> MemoryPool { get; set; }
public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; }
public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; }
public IHttp2StreamLifetimeHandler StreamLifetimeHandler { get; set; } public IHttp2StreamLifetimeHandler StreamLifetimeHandler { get; set; }

View File

@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public IPEndPoint LocalEndPoint => _context.LocalEndPoint; public IPEndPoint LocalEndPoint => _context.LocalEndPoint;
public IPEndPoint RemoteEndPoint => _context.RemoteEndPoint; public IPEndPoint RemoteEndPoint => _context.RemoteEndPoint;
private MemoryPool MemoryPool => _context.MemoryPool; private MemoryPool<byte> MemoryPool => _context.MemoryPool;
// Internal for testing // Internal for testing
internal PipeOptions AdaptedInputPipeOptions => new PipeOptions internal PipeOptions AdaptedInputPipeOptions => new PipeOptions

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public ServiceContext ServiceContext { get; set; } public ServiceContext ServiceContext { get; set; }
public IFeatureCollection ConnectionFeatures { get; set; } public IFeatureCollection ConnectionFeatures { get; set; }
public IList<IConnectionAdapter> ConnectionAdapters { get; set; } public IList<IConnectionAdapter> ConnectionAdapters { get; set; }
public MemoryPool MemoryPool { get; set; } public MemoryPool<byte> MemoryPool { get; set; }
public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; }
public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; }
public IDuplexPipe Transport { get; set; } public IDuplexPipe Transport { get; set; }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.IO.Pipelines;
using System.Threading; using System.Threading;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure

View File

@ -21,6 +21,7 @@
<PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" /> <PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="$(SystemThreadingTasksExtensionsPackageVersion)" /> <PackageReference Include="System.Threading.Tasks.Extensions" Version="$(SystemThreadingTasksExtensionsPackageVersion)" />
<PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" /> <PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Buffers.Sources" Version="$(MicrosoftExtensionsBuffersSourcesPackageVersion)" PrivateAssets="All" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" /> <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" />
<PackageReference Include="System.Security.Cryptography.Cng" Version="$(SystemSecurityCryptographyCngPackageVersion)" /> <PackageReference Include="System.Security.Cryptography.Cng" Version="$(SystemSecurityCryptographyCngPackageVersion)" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +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 System.Buffers;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
{
public static class KestrelMemoryPool
{
public static MemoryPool<byte> Create() => new SlabMemoryPool();
}
}

View File

@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
set => LocalPort = value; set => LocalPort = value;
} }
MemoryPool IConnectionTransportFeature.MemoryPool => MemoryPool; MemoryPool<byte> IConnectionTransportFeature.MemoryPool => MemoryPool;
IDuplexPipe IConnectionTransportFeature.Transport IDuplexPipe IConnectionTransportFeature.Transport
{ {

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
public string ConnectionId { get; set; } public string ConnectionId { get; set; }
public virtual MemoryPool MemoryPool { get; } public virtual MemoryPool<byte> MemoryPool { get; }
public virtual PipeScheduler InputWriterScheduler { get; } public virtual PipeScheduler InputWriterScheduler { get; }
public virtual PipeScheduler OutputReaderScheduler { get; } public virtual PipeScheduler OutputReaderScheduler { get; }

View File

@ -15,5 +15,8 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Protocols.Abstractions\Protocols.Abstractions.csproj" /> <ProjectReference Include="..\Protocols.Abstractions\Protocols.Abstractions.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Buffers.Sources" Version="$(MicrosoftExtensionsBuffersSourcesPackageVersion)" PrivateAssets="All" />
</ItemGroup>
</Project> </Project>

View File

@ -122,7 +122,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{ {
// EAGAIN/EWOULDBLOCK so just return the buffer. // EAGAIN/EWOULDBLOCK so just return the buffer.
// http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb // http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb
Input.Commit();
} }
else if (status > 0) else if (status > 0)
{ {
@ -141,7 +140,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
else else
{ {
// Given a negative status, it's possible that OnAlloc wasn't called. // Given a negative status, it's possible that OnAlloc wasn't called.
Input.Commit();
_socket.ReadStop(); _socket.ReadStop();
IOException error = null; IOException error = null;
@ -175,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
_bufferHandle.Dispose(); _bufferHandle.Dispose();
} }
private async Task ApplyBackpressureAsync(ValueAwaiter<FlushResult> flushTask) private async Task ApplyBackpressureAsync(PipeAwaiter<FlushResult> flushTask)
{ {
Log.ConnectionPause(ConnectionId); Log.ConnectionPause(ConnectionId);
_socket.ReadStop(); _socket.ReadStop();
@ -183,7 +181,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
var result = await flushTask; var result = await flushTask;
// If the reader isn't complete or cancelled then resume reading // If the reader isn't complete or cancelled then resume reading
if (!result.IsCompleted && !result.IsCancelled) if (!result.IsCompleted && !result.IsCanceled)
{ {
Log.ConnectionResume(ConnectionId); Log.ConnectionResume(ConnectionId);
StartReading(); StartReading();

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers; using System.Buffers;
using System.IO.Pipelines;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
public ListenerContext ListenerContext { get; set; } public ListenerContext ListenerContext { get; set; }
public override MemoryPool MemoryPool => ListenerContext.Thread.MemoryPool; public override MemoryPool<byte> MemoryPool => ListenerContext.Thread.MemoryPool;
public override PipeScheduler InputWriterScheduler => ListenerContext.Thread; public override PipeScheduler InputWriterScheduler => ListenerContext.Thread;
public override PipeScheduler OutputReaderScheduler => ListenerContext.Thread; public override PipeScheduler OutputReaderScheduler => ListenerContext.Thread;
} }

View File

@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
try try
{ {
if (result.IsCancelled) if (result.IsCanceled)
{ {
break; break;
} }

View File

@ -5,10 +5,12 @@ using System;
using System.Buffers; using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO.Pipelines;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -55,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
#endif #endif
QueueCloseHandle = PostCloseHandle; QueueCloseHandle = PostCloseHandle;
QueueCloseAsyncHandle = EnqueueCloseHandle; QueueCloseAsyncHandle = EnqueueCloseHandle;
MemoryPool = new MemoryPool(); MemoryPool = KestrelMemoryPool.Create();
WriteReqPool = new WriteReqPool(this, _log); WriteReqPool = new WriteReqPool(this, _log);
} }
@ -68,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
public UvLoopHandle Loop { get { return _loop; } } public UvLoopHandle Loop { get { return _loop; } }
public MemoryPool MemoryPool { get; } public MemoryPool<byte> MemoryPool { get; }
public WriteReqPool WriteReqPool { get; } public WriteReqPool WriteReqPool { get; }

View File

@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
_bufs = handle + requestSize; _bufs = handle + requestSize;
} }
public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlyBuffer<byte> buffer) public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlySequence<byte> buffer)
{ {
Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable); Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable);
return _awaitable; return _awaitable;
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
private unsafe void Write( private unsafe void Write(
UvStreamHandle handle, UvStreamHandle handle,
ReadOnlyBuffer<byte> buffer, ReadOnlySequence<byte> buffer,
Action<UvWriteReq, int, UvException, object> callback, Action<UvWriteReq, int, UvException, object> callback,
object state) object state)
{ {

View File

@ -5,6 +5,7 @@ using System;
using System.Buffers; using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Pipelines;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
private volatile bool _aborted; private volatile bool _aborted;
internal SocketConnection(Socket socket, MemoryPool memoryPool, ISocketsTrace trace) internal SocketConnection(Socket socket, MemoryPool<byte> memoryPool, ISocketsTrace trace)
{ {
Debug.Assert(socket != null); Debug.Assert(socket != null);
Debug.Assert(memoryPool != null); Debug.Assert(memoryPool != null);
@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
_sender = new SocketSender(_socket); _sender = new SocketSender(_socket);
} }
public override MemoryPool MemoryPool { get; } public override MemoryPool<byte> MemoryPool { get; }
public override PipeScheduler InputWriterScheduler => PipeScheduler.Inline; public override PipeScheduler InputWriterScheduler => PipeScheduler.Inline;
public override PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool; public override PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool;
@ -102,24 +103,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
// Ensure we have some reasonable amount of buffer space // Ensure we have some reasonable amount of buffer space
var buffer = Input.GetMemory(MinAllocBufferSize); var buffer = Input.GetMemory(MinAllocBufferSize);
try var bytesReceived = await _receiver.ReceiveAsync(buffer);
{
var bytesReceived = await _receiver.ReceiveAsync(buffer);
if (bytesReceived == 0) if (bytesReceived == 0)
{
// FIN
_trace.ConnectionReadFin(ConnectionId);
break;
}
Input.Advance(bytesReceived);
}
finally
{ {
Input.Commit(); // FIN
_trace.ConnectionReadFin(ConnectionId);
break;
} }
Input.Advance(bytesReceived);
var flushTask = Input.FlushAsync(); var flushTask = Input.FlushAsync();
if (!flushTask.IsCompleted) if (!flushTask.IsCompleted)
@ -197,7 +192,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
var result = await Output.ReadAsync(); var result = await Output.ReadAsync();
var buffer = result.Buffer; var buffer = result.Buffer;
if (result.IsCancelled) if (result.IsCanceled)
{ {
break; break;
} }

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
_eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError); _eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError);
} }
public SocketAwaitable SendAsync(ReadOnlyBuffer<byte> buffers) public SocketAwaitable SendAsync(ReadOnlySequence<byte> buffers)
{ {
if (buffers.IsSingleSegment) if (buffers.IsSingleSegment)
{ {
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
return _awaitable; return _awaitable;
} }
private List<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer<byte> buffer) private List<ArraySegment<byte>> GetBufferList(ReadOnlySequence<byte> buffer)
{ {
Debug.Assert(!buffer.IsEmpty); Debug.Assert(!buffer.IsEmpty);
Debug.Assert(!buffer.IsSingleSegment); Debug.Assert(!buffer.IsSingleSegment);

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
{ {
internal sealed class SocketTransport : ITransport internal sealed class SocketTransport : ITransport
{ {
private readonly MemoryPool _memoryPool = new MemoryPool(); private readonly MemoryPool<byte> _memoryPool = KestrelMemoryPool.Create();
private readonly IEndPointInformation _endPointInformation; private readonly IEndPointInformation _endPointInformation;
private readonly IConnectionHandler _handler; private readonly IConnectionHandler _handler;
private readonly IApplicationLifetime _appLifetime; private readonly IApplicationLifetime _appLifetime;

View File

@ -18,7 +18,7 @@ namespace System.IO.Pipelines
{ {
} }
public static DuplexPipePair CreateConnectionPair(MemoryPool memoryPool) public static DuplexPipePair CreateConnectionPair(MemoryPool<byte> memoryPool)
{ {
return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool)); return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool));
} }

View File

@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Protocols.Features
{ {
public interface IConnectionTransportFeature public interface IConnectionTransportFeature
{ {
MemoryPool MemoryPool { get; } MemoryPool<byte> MemoryPool { get; }
IDuplexPipe Transport { get; set; } IDuplexPipe Transport { get; set; }

View File

@ -17,7 +17,6 @@
<PackageReference Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" /> <PackageReference Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" />
<PackageReference Include="System.Buffers" Version="$(SystemBuffersPackageVersion)" /> <PackageReference Include="System.Buffers" Version="$(SystemBuffersPackageVersion)" />
<PackageReference Include="System.IO.Pipelines" Version="$(SystemIOPipelinesPackageVersion)" /> <PackageReference Include="System.IO.Pipelines" Version="$(SystemIOPipelinesPackageVersion)" />
<PackageReference Include="System.Text.Encodings.Web.Utf8" Version="$(SystemTextEncodingsWebUtf8PackageVersion)" />
<PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" /> <PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" /> <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" />
</ItemGroup> </ItemGroup>

View File

@ -7,6 +7,8 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Protocols.Features; using Microsoft.AspNetCore.Protocols.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Xunit; using Xunit;
@ -51,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Set<IConnectionTransportFeature>(this); Set<IConnectionTransportFeature>(this);
} }
public MemoryPool MemoryPool { get; } = new MemoryPool(); public MemoryPool<byte> MemoryPool { get; } = KestrelMemoryPool.Create();
public IDuplexPipe Transport { get; set; } public IDuplexPipe Transport { get; set; }
public IDuplexPipe Application { get; set; } public IDuplexPipe Application { get; set; }

View File

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@ -32,14 +33,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private readonly TestHttp1Connection _http1Connection; private readonly TestHttp1Connection _http1Connection;
private readonly ServiceContext _serviceContext; private readonly ServiceContext _serviceContext;
private readonly Http1ConnectionContext _http1ConnectionContext; private readonly Http1ConnectionContext _http1ConnectionContext;
private readonly MemoryPool _pipelineFactory; private readonly MemoryPool<byte> _pipelineFactory;
private SequencePosition _consumed; private SequencePosition _consumed;
private SequencePosition _examined; private SequencePosition _examined;
private Mock<ITimeoutControl> _timeoutControl; private Mock<ITimeoutControl> _timeoutControl;
public Http1ConnectionTests() public Http1ConnectionTests()
{ {
_pipelineFactory = new MemoryPool(); _pipelineFactory = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory); var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory);
_transport = pair.Transport; _transport = pair.Transport;
@ -803,7 +804,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_http1Connection.NextMessageBody = mockMessageBody.Object; _http1Connection.NextMessageBody = mockMessageBody.Object;
var requestProcessingTask = _http1Connection.ProcessRequestsAsync(httpApplication); var requestProcessingTask = _http1Connection.ProcessRequestsAsync(httpApplication);
var data = Encoding.ASCII.GetBytes("POST / HTTP/1.1\r\nHost:\r\nConnection: close\r\ncontent-length: 1\r\n\r\n"); var data = Encoding.ASCII.GetBytes("POST / HTTP/1.1\r\nHost:\r\nConnection: close\r\ncontent-length: 1\r\n\r\n");
await _application.Output.WriteAsync(data); await _application.Output.WriteAsync(data);
await requestProcessingTask.TimeoutAfter(TestConstants.DefaultTimeout); await requestProcessingTask.TimeoutAfter(TestConstants.DefaultTimeout);

View File

@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Xunit; using Xunit;
@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private static readonly byte[] _noData = new byte[0]; private static readonly byte[] _noData = new byte[0];
private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize)); private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize));
private readonly MemoryPool _memoryPool = new MemoryPool(); private readonly MemoryPool<byte> _memoryPool = KestrelMemoryPool.Create();
private readonly DuplexPipe.DuplexPipePair _pair; private readonly DuplexPipe.DuplexPipePair _pair;
private readonly TestApplicationErrorLogger _logger; private readonly TestApplicationErrorLogger _logger;
private readonly Http2ConnectionContext _connectionContext; private readonly Http2ConnectionContext _connectionContext;

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Moq; using Moq;
using Xunit; using Xunit;
@ -18,13 +19,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
public class HttpConnectionTests : IDisposable public class HttpConnectionTests : IDisposable
{ {
private readonly MemoryPool _memoryPool; private readonly MemoryPool<byte> _memoryPool;
private readonly HttpConnectionContext _httpConnectionContext; private readonly HttpConnectionContext _httpConnectionContext;
private readonly HttpConnection _httpConnection; private readonly HttpConnection _httpConnection;
public HttpConnectionTests() public HttpConnectionTests()
{ {
_memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(_memoryPool); var pair = DuplexPipe.CreateConnectionPair(_memoryPool);
_httpConnectionContext = new HttpConnectionContext _httpConnectionContext = new HttpConnectionContext

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
string expectedVersion) string expectedVersion)
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
Assert.True(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); Assert.True(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine) public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine)
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine) public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine)
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
.Returns(true); .Returns(true);
var parser = CreateParser(mockTrace.Object); var parser = CreateParser(mockTrace.Object);
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
.Returns(true); .Returns(true);
var parser = CreateParser(mockTrace.Object); var parser = CreateParser(mockTrace.Object);
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -127,7 +127,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
.Returns(true); .Returns(true);
var parser = CreateParser(mockTrace.Object); var parser = CreateParser(mockTrace.Object);
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -178,7 +178,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
Assert.False(parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes)); Assert.False(parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
} }
@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
@ -293,7 +293,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
const string headerLine = "Header: value\r\n\r"; const string headerLine = "Header: value\r\n\r";
var buffer1 = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(headerLine)); var buffer1 = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(headerLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes)); Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes));
@ -301,7 +301,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(buffer1.End, examined); Assert.Equal(buffer1.End, examined);
Assert.Equal(headerLine.Length - 1, consumedBytes); Assert.Equal(headerLine.Length - 1, consumedBytes);
var buffer2 = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("\r\n")); var buffer2 = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("\r\n"));
Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes)); Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes));
Assert.True(buffer2.Slice(consumed).IsEmpty); Assert.True(buffer2.Slice(consumed).IsEmpty);
@ -319,7 +319,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
.Returns(true); .Returns(true);
var parser = CreateParser(mockTrace.Object); var parser = CreateParser(mockTrace.Object);
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -340,7 +340,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var parser = CreateParser(mockTrace.Object); var parser = CreateParser(mockTrace.Object);
// Invalid request line // Invalid request line
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n")); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n"));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -350,7 +350,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode); Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode);
// Unrecognized HTTP version // Unrecognized HTTP version
buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n")); buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n"));
exception = Assert.Throws<BadHttpRequestException>(() => exception = Assert.Throws<BadHttpRequestException>(() =>
parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, (exception as BadHttpRequestException).StatusCode); Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, (exception as BadHttpRequestException).StatusCode);
// Invalid request header // Invalid request header
buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("Header: value\n\r\n")); buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes("Header: value\n\r\n"));
exception = Assert.Throws<BadHttpRequestException>(() => exception = Assert.Throws<BadHttpRequestException>(() =>
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes)); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
@ -388,7 +388,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
string expectedHeaderValue) string expectedHeaderValue)
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n"));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
@ -406,7 +406,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match"); Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match");
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlySequence<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
@ -466,7 +466,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
} }
private static ReadOnlyBuffer<byte> CreateBuffer(params string[] inputs) private static ReadOnlySequence<byte> CreateBuffer(params string[] inputs)
{ {
var buffers = new byte[inputs.Length][]; var buffers = new byte[inputs.Length][];
for (int i = 0; i < inputs.Length; i++) for (int i = 0; i < inputs.Length; i++)
@ -477,7 +477,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
// Copied from https://github.com/dotnet/corefx/blob/master/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.cs // Copied from https://github.com/dotnet/corefx/blob/master/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.cs
private static ReadOnlyBuffer<byte> CreateBuffer(params byte[][] inputs) private static ReadOnlySequence<byte> CreateBuffer(params byte[][] inputs)
{ {
if (inputs == null || inputs.Length == 0) if (inputs == null || inputs.Length == 0)
{ {
@ -516,7 +516,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
i++; i++;
} while (i < inputs.Length); } while (i < inputs.Length);
return new ReadOnlyBuffer<byte>(first, 0, last, last.Memory.Length); return new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length);
} }
// Copied from https://github.com/dotnet/corefx/blob/master/src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs // Copied from https://github.com/dotnet/corefx/blob/master/src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Moq; using Moq;
using Xunit; using Xunit;
@ -23,14 +24,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private readonly TestHttp1Connection _http1Connection; private readonly TestHttp1Connection _http1Connection;
private readonly ServiceContext _serviceContext; private readonly ServiceContext _serviceContext;
private readonly Http1ConnectionContext _http1ConnectionContext; private readonly Http1ConnectionContext _http1ConnectionContext;
private readonly MemoryPool _pipelineFactory; private readonly MemoryPool<byte> _pipelineFactory;
private Mock<ITimeoutControl> _timeoutControl; private Mock<ITimeoutControl> _timeoutControl;
private readonly IFeatureCollection _collection; private readonly IFeatureCollection _collection;
public HttpProtocolFeatureCollectionTests() public HttpProtocolFeatureCollectionTests()
{ {
_pipelineFactory = new MemoryPool(); _pipelineFactory = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory); var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory);
_transport = pair.Transport; _transport = pair.Transport;

View File

@ -9,6 +9,7 @@ using System.IO.Pipelines;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Xunit; using Xunit;
@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[Fact] [Fact]
public void InitialDictionaryIsEmpty() public void InitialDictionaryIsEmpty()
{ {
using (var memoryPool = new MemoryPool()) using (var memoryPool = KestrelMemoryPool.Create())
{ {
var pair = DuplexPipe.CreateConnectionPair(memoryPool); var pair = DuplexPipe.CreateConnectionPair(memoryPool);
var http1ConnectionContext = new Http1ConnectionContext var http1ConnectionContext = new Http1ConnectionContext

View File

@ -7,6 +7,7 @@ using System.IO.Pipelines;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Moq; using Moq;
using Xunit; using Xunit;
@ -15,11 +16,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
public class OutputProducerTests : IDisposable public class OutputProducerTests : IDisposable
{ {
private readonly MemoryPool _memoryPool; private readonly MemoryPool<byte> _memoryPool;
public OutputProducerTests() public OutputProducerTests()
{ {
_memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
} }
public void Dispose() public void Dispose()

View File

@ -2,9 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers; using System.Buffers;
using System.IO.Pipelines;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Moq; using Moq;
using Xunit; using Xunit;
@ -24,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
serviceContext.ThreadPool = new LoggingThreadPool(null); serviceContext.ThreadPool = new LoggingThreadPool(null);
var mockScheduler = Mock.Of<PipeScheduler>(); var mockScheduler = Mock.Of<PipeScheduler>();
var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler); var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, KestrelMemoryPool.Create(), readerScheduler: mockScheduler);
Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.ResumeWriterThreshold); Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.ResumeWriterThreshold);
Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.PauseWriterThreshold); Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.PauseWriterThreshold);
@ -42,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
serviceContext.ThreadPool = new LoggingThreadPool(null); serviceContext.ThreadPool = new LoggingThreadPool(null);
var mockScheduler = Mock.Of<PipeScheduler>(); var mockScheduler = Mock.Of<PipeScheduler>();
var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler); var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, KestrelMemoryPool.Create(), writerScheduler: mockScheduler);
Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.ResumeWriterThreshold); Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.ResumeWriterThreshold);
Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.PauseWriterThreshold); Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.PauseWriterThreshold);

View File

@ -6,6 +6,7 @@ using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private const int _ulongMaxValueLength = 20; private const int _ulongMaxValueLength = 20;
private readonly Pipe _pipe; private readonly Pipe _pipe;
private readonly MemoryPool _memoryPool = new MemoryPool(); private readonly MemoryPool<byte> _memoryPool = KestrelMemoryPool.Create();
public PipelineExtensionTests() public PipelineExtensionTests()
{ {
@ -35,8 +36,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void WritesNumericToAscii(ulong number) public void WritesNumericToAscii(ulong number)
{ {
var writerBuffer = _pipe.Writer; var writerBuffer = _pipe.Writer;
var writer = OutputWriter.Create(writerBuffer); var writer = new BufferWriter<PipeWriter>(writerBuffer);
writer.WriteNumeric(number); writer.WriteNumeric(number);
writer.Commit();
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -52,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void WritesNumericAcrossSpanBoundaries(int gapSize) public void WritesNumericAcrossSpanBoundaries(int gapSize)
{ {
var writerBuffer = _pipe.Writer; var writerBuffer = _pipe.Writer;
var writer = OutputWriter.Create(writerBuffer); var writer = new BufferWriter<PipeWriter>(writerBuffer);
// almost fill up the first block // almost fill up the first block
var spacer = new byte[writer.Span.Length - gapSize]; var spacer = new byte[writer.Span.Length - gapSize];
writer.Write(spacer); writer.Write(spacer);
@ -60,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var bufferLength = writer.Span.Length; var bufferLength = writer.Span.Length;
writer.WriteNumeric(ulong.MaxValue); writer.WriteNumeric(ulong.MaxValue);
Assert.NotEqual(bufferLength, writer.Span.Length); Assert.NotEqual(bufferLength, writer.Span.Length);
writer.Commit();
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -83,8 +85,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void EncodesAsAscii(string input, byte[] expected) public void EncodesAsAscii(string input, byte[] expected)
{ {
var writerBuffer = _pipe.Writer; var writerBuffer = _pipe.Writer;
var writer = OutputWriter.Create(writerBuffer); var writer = new BufferWriter<PipeWriter>(writerBuffer);
writer.WriteAsciiNoValidation(input); writer.WriteAsciiNoValidation(input);
writer.Commit();
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -110,8 +113,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
// WriteAscii doesn't validate if characters are in the ASCII range // WriteAscii doesn't validate if characters are in the ASCII range
// but it shouldn't produce more than one byte per character // but it shouldn't produce more than one byte per character
var writerBuffer = _pipe.Writer; var writerBuffer = _pipe.Writer;
var writer = OutputWriter.Create(writerBuffer); var writer = new BufferWriter<PipeWriter>(writerBuffer);
writer.WriteAsciiNoValidation(input); writer.WriteAsciiNoValidation(input);
writer.Commit();
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -123,11 +127,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
const byte maxAscii = 0x7f; const byte maxAscii = 0x7f;
var writerBuffer = _pipe.Writer; var writerBuffer = _pipe.Writer;
var writer = OutputWriter.Create(writerBuffer); var writer = new BufferWriter<PipeWriter>(writerBuffer);
for (var i = 0; i < maxAscii; i++) for (var i = 0; i < maxAscii; i++)
{ {
writer.WriteAsciiNoValidation(new string((char)i, 1)); writer.WriteAsciiNoValidation(new string((char)i, 1));
} }
writer.Commit();
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -152,7 +157,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
var testString = new string(' ', stringLength); var testString = new string(' ', stringLength);
var writerBuffer = _pipe.Writer; var writerBuffer = _pipe.Writer;
var writer = OutputWriter.Create(writerBuffer); var writer = new BufferWriter<PipeWriter>(writerBuffer);
// almost fill up the first block // almost fill up the first block
var spacer = new byte[writer.Span.Length - gapSize]; var spacer = new byte[writer.Span.Length - gapSize];
writer.Write(spacer); writer.Write(spacer);
@ -161,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var bufferLength = writer.Span.Length; var bufferLength = writer.Span.Length;
writer.WriteAsciiNoValidation(testString); writer.WriteAsciiNoValidation(testString);
Assert.NotEqual(bufferLength, writer.Span.Length); Assert.NotEqual(bufferLength, writer.Span.Length);
writer.Commit();
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();

View File

@ -5,9 +5,11 @@ using System;
using System.Buffers; using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Moq; using Moq;
@ -15,11 +17,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
class TestInput : IDisposable class TestInput : IDisposable
{ {
private MemoryPool _memoryPool; private MemoryPool<byte> _memoryPool;
public TestInput() public TestInput()
{ {
_memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
var pair = DuplexPipe.CreateConnectionPair(_memoryPool); var pair = DuplexPipe.CreateConnectionPair(_memoryPool);
Transport = pair.Transport; Transport = pair.Transport;
Application = pair.Application; Application = pair.Application;
@ -49,7 +51,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void Add(string text) public void Add(string text)
{ {
var data = Encoding.ASCII.GetBytes(text); var data = Encoding.ASCII.GetBytes(text);
Application.Output.WriteAsync(data).Wait(); async Task Write() => await Application.Output.WriteAsync(data);
Write().Wait();
} }
public void Fin() public void Fin()

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{ {
public class LibuvOutputConsumerTests : IDisposable public class LibuvOutputConsumerTests : IDisposable
{ {
private readonly MemoryPool _memoryPool; private readonly MemoryPool<byte> _memoryPool;
private readonly MockLibuv _mockLibuv; private readonly MockLibuv _mockLibuv;
private readonly LibuvThread _libuvThread; private readonly LibuvThread _libuvThread;
@ -38,7 +39,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
public LibuvOutputConsumerTests() public LibuvOutputConsumerTests()
{ {
_memoryPool = new MemoryPool(); _memoryPool = KestrelMemoryPool.Create();
_mockLibuv = new MockLibuv(); _mockLibuv = new MockLibuv();
var libuvTransport = new LibuvTransport(_mockLibuv, new TestLibuvTransportContext(), new ListenOptions((ulong)0)); var libuvTransport = new LibuvTransport(_mockLibuv, new TestLibuvTransportContext(), new ListenOptions((ulong)0));
@ -340,6 +341,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
writerScheduler: PipeScheduler.Inline,
pauseWriterThreshold: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
resumeWriterThreshold: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );

View File

@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
await writeRequest.WriteAsync( await writeRequest.WriteAsync(
serverConnectionPipe, serverConnectionPipe,
new ReadOnlyBuffer<byte>(new byte[] { 1, 2, 3, 4 })); new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4 }));
writeRequest.Dispose(); writeRequest.Dispose();
serverConnectionPipe.Dispose(); serverConnectionPipe.Dispose();

View File

@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{ {
var req = new UvWriteReq(_logger); var req = new UvWriteReq(_logger);
req.DangerousInit(loop); req.DangerousInit(loop);
var block = new ReadOnlyBuffer<byte>(new byte[] { 65, 66, 67, 68, 69 }); var block = new ReadOnlySequence<byte>(new byte[] { 65, 66, 67, 68, 69 });
await req.WriteAsync( await req.WriteAsync(
tcp2, tcp2,

View File

@ -13,8 +13,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{ {
public class MockConnectionHandler : IConnectionHandler public class MockConnectionHandler : IConnectionHandler
{ {
public Func<MemoryPool, PipeOptions> InputOptions { get; set; } = pool => new PipeOptions(pool); public Func<MemoryPool<byte>, PipeOptions> InputOptions { get; set; } = pool => new PipeOptions(pool);
public Func<MemoryPool, PipeOptions> OutputOptions { get; set; } = pool => new PipeOptions(pool); public Func<MemoryPool<byte>, PipeOptions> OutputOptions { get; set; } = pool => new PipeOptions(pool);
public void OnConnection(IFeatureCollection features) public void OnConnection(IFeatureCollection features)
{ {

View File

@ -523,7 +523,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true; return true;
}} }}
{(loop.ClassName == "HttpResponseHeaders" ? $@" {(loop.ClassName == "HttpResponseHeaders" ? $@"
protected void CopyToFast(ref OutputWriter<PipeWriter> output) internal void CopyToFast(ref BufferWriter<PipeWriter> output)
{{ {{
var tempBits = _bits | (_contentLength.HasValue ? {1L << 63}L : 0); var tempBits = _bits | (_contentLength.HasValue ? {1L << 63}L : 0);
{Each(loop.Headers.Where(header => header.Identifier != "ContentLength").OrderBy(h => !h.PrimaryHeader), header => $@" {Each(loop.Headers.Where(header => header.Identifier != "ContentLength").OrderBy(h => !h.PrimaryHeader), header => $@"