React to pipes in corefx (#2337)
This commit is contained in:
parent
a3911269c5
commit
2c108d9ba1
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (result.IsCancelled)
|
if (result.IsCanceled)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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 => $@"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue