React to pipelines changes (#2275)

This commit is contained in:
Pavel Krymets 2018-01-29 14:34:48 -08:00 committed by GitHub
parent 8280c1b73f
commit a84095e5c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 550 additions and 541 deletions

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
private const int InnerLoopCount = 512; private const int InnerLoopCount = 512;
public ReadOnlyBuffer _buffer; public ReadOnlyBuffer<byte> _buffer;
public Http1Connection _http1Connection; public Http1Connection _http1Connection;
[IterationSetup] [IterationSetup]

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask; private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask;
private readonly TestHttp1Connection _http1Connection; private readonly TestHttp1Connection _http1Connection;
private (IPipeConnection Transport, IPipeConnection Application) _pair; private (IDuplexPipe Transport, IDuplexPipe Application) _pair;
private readonly byte[] _writeData; private readonly byte[] _writeData;
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
var reader = _pair.Application.Input; var reader = _pair.Application.Input;
if (reader.TryRead(out var readResult)) if (reader.TryRead(out var readResult))
{ {
reader.Advance(readResult.Buffer.End); reader.AdvanceTo(readResult.Buffer.End);
} }
} }

View File

@ -13,7 +13,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 _buffer; private ReadOnlyBuffer<byte> _buffer;
[Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)] [Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)]
public void PlaintextTechEmpower() public void PlaintextTechEmpower()
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private void InsertData(byte[] data) private void InsertData(byte[] data)
{ {
_buffer = new ReadOnlyBuffer(data); _buffer = new ReadOnlyBuffer<byte>(data);
} }
private void ParseData() private void ParseData()

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Text; using System.Text;
@ -23,7 +24,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 buffer, out Position consumed, out Position examined, out int consumedBytes) public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<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));
@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
return true; return true;
} }
public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined) public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
handler.OnStartLine(HttpMethod.Get, handler.OnStartLine(HttpMethod.Get,
HttpVersion.Http11, HttpVersion.Http11,

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private const int _writeLenght = 57; private const int _writeLenght = 57;
private const int InnerLoopCount = 512; private const int InnerLoopCount = 512;
private IPipe _pipe; private Pipe _pipe;
private MemoryPool _memoryPool; private MemoryPool _memoryPool;
[IterationSetup] [IterationSetup]
@ -30,9 +30,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
for (int i = 0; i < InnerLoopCount; i++) for (int i = 0; i < InnerLoopCount; i++)
{ {
var writableBuffer = _pipe.Writer.Alloc(_writeLenght); _pipe.Writer.GetMemory(_writeLenght);
writableBuffer.Advance(_writeLenght); _pipe.Writer.Advance(_writeLenght);
await writableBuffer.FlushAsync(); await _pipe.Writer.FlushAsync();
} }
}); });
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
var result = await _pipe.Reader.ReadAsync(); var result = await _pipe.Reader.ReadAsync();
remaining -= result.Buffer.Length; remaining -= result.Buffer.Length;
_pipe.Reader.Advance(result.Buffer.End, result.Buffer.End); _pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
} }
}); });
@ -55,11 +55,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
for (int i = 0; i < InnerLoopCount; i++) for (int i = 0; i < InnerLoopCount; i++)
{ {
var writableBuffer = _pipe.Writer.Alloc(_writeLenght); _pipe.Writer.GetMemory(_writeLenght);
writableBuffer.Advance(_writeLenght); _pipe.Writer.Advance(_writeLenght);
writableBuffer.FlushAsync().GetAwaiter().GetResult(); _pipe.Writer.FlushAsync().GetAwaiter().GetResult();
var result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
_pipe.Reader.Advance(result.Buffer.End, result.Buffer.End); _pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
} }
} }
} }

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
public class RequestParsingBenchmark public class RequestParsingBenchmark
{ {
public IPipe Pipe { get; set; } public Pipe Pipe { get; set; }
public Http1Connection Http1Connection { get; set; } public Http1Connection Http1Connection { get; set; }
@ -130,10 +130,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private void InsertData(byte[] bytes) private void InsertData(byte[] bytes)
{ {
var buffer = Pipe.Writer.Alloc(2048); Pipe.Writer.Write(bytes);
buffer.Write(bytes);
// There should not be any backpressure and task completes immediately // There should not be any backpressure and task completes immediately
buffer.FlushAsync().GetAwaiter().GetResult(); Pipe.Writer.FlushAsync().GetAwaiter().GetResult();
} }
private void ParseDataDrainBuffer() private void ParseDataDrainBuffer()
@ -166,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
} }
while (readableBuffer.Length > 0); while (readableBuffer.Length > 0);
Pipe.Reader.Advance(readableBuffer.End); Pipe.Reader.AdvanceTo(readableBuffer.End);
} }
private void ParseData() private void ParseData()
@ -189,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
ErrorUtilities.ThrowInvalidRequestLine(); ErrorUtilities.ThrowInvalidRequestLine();
} }
Pipe.Reader.Advance(consumed, examined); Pipe.Reader.AdvanceTo(consumed, examined);
result = Pipe.Reader.ReadAsync().GetAwaiter().GetResult(); result = Pipe.Reader.ReadAsync().GetAwaiter().GetResult();
readableBuffer = result.Buffer; readableBuffer = result.Buffer;
@ -198,7 +197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{ {
ErrorUtilities.ThrowInvalidRequestHeaders(); ErrorUtilities.ThrowInvalidRequestHeaders();
} }
Pipe.Reader.Advance(consumed, examined); Pipe.Reader.AdvanceTo(consumed, examined);
} }
while (true); while (true);
} }

View File

@ -25,21 +25,21 @@
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsLoggingTestingPackageVersion> <MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsOptionsPackageVersion> <MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion> <MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-26115-03</MicrosoftNETCoreApp21PackageVersion> <MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-26126-02</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview1-28153</MicrosoftNetHttpHeadersPackageVersion> <MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview1-28153</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.3.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-preview1-26112-01</SystemBuffersPackageVersion> <SystemBuffersPackageVersion>4.5.0-preview1-26126-05</SystemBuffersPackageVersion>
<SystemBuffersPrimitivesPackageVersion>0.1.0-e180104-2</SystemBuffersPrimitivesPackageVersion> <SystemBuffersPrimitivesPackageVersion>0.1.0-preview1-180129-1</SystemBuffersPrimitivesPackageVersion>
<SystemIOPipelinesPackageVersion>0.1.0-e180104-2</SystemIOPipelinesPackageVersion> <SystemIOPipelinesPackageVersion>0.1.0-preview1-180129-1</SystemIOPipelinesPackageVersion>
<SystemIOPipelinesTestingPackageVersion>0.1.0-e180104-2</SystemIOPipelinesTestingPackageVersion> <SystemIOPipelinesTestingPackageVersion>0.1.0-preview1-180129-1</SystemIOPipelinesTestingPackageVersion>
<SystemMemoryPackageVersion>4.5.0-preview1-26112-01</SystemMemoryPackageVersion> <SystemMemoryPackageVersion>4.5.0-preview1-26126-05</SystemMemoryPackageVersion>
<SystemNumericsVectorsPackageVersion>4.5.0-preview1-26112-01</SystemNumericsVectorsPackageVersion> <SystemNumericsVectorsPackageVersion>4.5.0-preview1-26126-05</SystemNumericsVectorsPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview1-26112-01</SystemRuntimeCompilerServicesUnsafePackageVersion> <SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview1-26126-05</SystemRuntimeCompilerServicesUnsafePackageVersion>
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview1-26112-01</SystemSecurityCryptographyCngPackageVersion> <SystemSecurityCryptographyCngPackageVersion>4.5.0-preview1-26126-05</SystemSecurityCryptographyCngPackageVersion>
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-e180104-2</SystemTextEncodingsWebUtf8PackageVersion> <SystemTextEncodingsWebUtf8PackageVersion>0.1.0-preview1-180129-1</SystemTextEncodingsWebUtf8PackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview1-26112-01</SystemThreadingTasksExtensionsPackageVersion> <SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview1-26126-05</SystemThreadingTasksExtensionsPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion> <XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion> <XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.3.1</XunitRunnerVisualStudioPackageVersion> <XunitRunnerVisualStudioPackageVersion>2.3.1</XunitRunnerVisualStudioPackageVersion>

View File

@ -10,17 +10,17 @@ using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
{ {
public class AdaptedPipeline : IPipeConnection public class AdaptedPipeline : IDuplexPipe
{ {
private const int MinAllocBufferSize = 2048; private const int MinAllocBufferSize = 2048;
private readonly IPipeConnection _transport; private readonly IDuplexPipe _transport;
private readonly IPipeConnection _application; private readonly IDuplexPipe _application;
public AdaptedPipeline(IPipeConnection transport, public AdaptedPipeline(IDuplexPipe transport,
IPipeConnection application, IDuplexPipe application,
IPipe inputPipe, Pipe inputPipe,
IPipe outputPipe) Pipe outputPipe)
{ {
_transport = transport; _transport = transport;
_application = application; _application = application;
@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
Output = outputPipe; Output = outputPipe;
} }
public IPipe Input { get; } public Pipe Input { get; }
public IPipe Output { get; } public Pipe Output { get; }
IPipeReader IPipeConnection.Input => Input.Reader; PipeReader IDuplexPipe.Input => Input.Reader;
IPipeWriter IPipeConnection.Output => Output.Writer; PipeWriter IDuplexPipe.Output => Output.Writer;
public async Task RunAsync(Stream stream) public async Task RunAsync(Stream stream)
{ {
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
} }
await stream.FlushAsync(); await stream.FlushAsync();
} }
else if (buffer.IsSingleSpan) else if (buffer.IsSingleSegment)
{ {
var array = buffer.First.GetArray(); var array = buffer.First.GetArray();
await stream.WriteAsync(array.Array, array.Offset, array.Count); await stream.WriteAsync(array.Array, array.Offset, array.Count);
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
} }
finally finally
{ {
Output.Reader.Advance(buffer.End); Output.Reader.AdvanceTo(buffer.End);
} }
} }
} }
@ -124,13 +124,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
while (true) while (true)
{ {
var outputBuffer = Input.Writer.Alloc(MinAllocBufferSize); var outputBuffer = Input.Writer.GetMemory(MinAllocBufferSize);
var array = outputBuffer.Buffer.GetArray(); var array = outputBuffer.GetArray();
try try
{ {
var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count); var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count);
outputBuffer.Advance(bytesRead); Input.Writer.Advance(bytesRead);
if (bytesRead == 0) if (bytesRead == 0)
{ {
@ -140,10 +140,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
} }
finally finally
{ {
outputBuffer.Commit(); Input.Writer.Commit();
} }
var result = await outputBuffer.FlushAsync(); var result = await Input.Writer.FlushAsync();
if (result.IsCompleted) if (result.IsCompleted)
{ {

View File

@ -6,15 +6,16 @@ using System.IO.Pipelines;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Buffers;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
{ {
public class RawStream : Stream public class RawStream : Stream
{ {
private readonly IPipeReader _input; private readonly PipeReader _input;
private readonly IPipeWriter _output; private readonly PipeWriter _output;
public RawStream(IPipeReader input, IPipeWriter output) public RawStream(PipeReader input, PipeWriter output)
{ {
_input = input; _input = input;
_output = output; _output = output;
@ -75,14 +76,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token) public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
{ {
var output = _output.Alloc();
if (buffer != null) if (buffer != null)
{ {
output.Write(new ArraySegment<byte>(buffer, offset, count)); _output.Write(new ReadOnlySpan<byte>(buffer, offset, count));
} }
await output.FlushAsync(token); await _output.FlushAsync(token);
} }
public override void Flush() public override void Flush()
@ -118,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
} }
finally finally
{ {
_input.Advance(readableBuffer.End, readableBuffer.End); _input.AdvanceTo(readableBuffer.End, readableBuffer.End);
} }
} }
} }

View File

@ -83,22 +83,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
} }
// Internal for testing // Internal for testing
internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, Scheduler writerScheduler) => new PipeOptions internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler writerScheduler) => new PipeOptions
( (
pool: memoryPool, pool: memoryPool,
readerScheduler: serviceContext.ThreadPool, readerScheduler: serviceContext.ThreadPool,
writerScheduler: writerScheduler, writerScheduler: writerScheduler,
maximumSizeHigh: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, pauseWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
maximumSizeLow: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
); );
internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, Scheduler readerScheduler) => new PipeOptions internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler readerScheduler) => new PipeOptions
( (
pool: memoryPool, pool: memoryPool,
readerScheduler: readerScheduler, readerScheduler: readerScheduler,
writerScheduler: serviceContext.ThreadPool, writerScheduler: serviceContext.ThreadPool,
maximumSizeHigh: GetOutputResponseBufferSize(serviceContext), pauseWriterThreshold: GetOutputResponseBufferSize(serviceContext),
maximumSizeLow: GetOutputResponseBufferSize(serviceContext) resumeWriterThreshold: GetOutputResponseBufferSize(serviceContext)
); );
private static long GetOutputResponseBufferSize(ServiceContext serviceContext) private static long GetOutputResponseBufferSize(ServiceContext serviceContext)

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Text; using System.Text;
@ -47,16 +48,16 @@ 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 WritableBufferWriter start, int dataCount) public static int WriteBeginChunkBytes(ref OutputWriter<PipeWriter> start, int dataCount)
{ {
var chunkSegment = BeginChunkBytes(dataCount); var chunkSegment = BeginChunkBytes(dataCount);
start.Write(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 WritableBufferWriter start) public static void WriteEndChunkBytes(ref OutputWriter<PipeWriter> start)
{ {
start.Write(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count); start.Write(new ReadOnlySpan<byte>(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count));
} }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.Diagnostics; using System.Diagnostics;
using System.IO.Pipelines; using System.IO.Pipelines;
@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Output = new Http1OutputProducer(_context.Application.Input, _context.Transport.Output, _context.ConnectionId, _context.ServiceContext.Log, _context.TimeoutControl); Output = new Http1OutputProducer(_context.Application.Input, _context.Transport.Output, _context.ConnectionId, _context.ServiceContext.Log, _context.TimeoutControl);
} }
public IPipeReader Input => _context.Transport.Input; public PipeReader Input => _context.Transport.Input;
public ITimeoutControl TimeoutControl => _context.TimeoutControl; public ITimeoutControl TimeoutControl => _context.TimeoutControl;
public bool RequestTimedOut => _requestTimedOut; public bool RequestTimedOut => _requestTimedOut;
@ -69,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
Input.CancelPendingRead(); Input.CancelPendingRead();
} }
public void ParseRequest(ReadOnlyBuffer buffer, out Position consumed, out Position examined) public void ParseRequest(ReadOnlyBuffer<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 buffer, out Position consumed, out Position examined) public bool TakeStartLine(ReadOnlyBuffer<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 buffer, out Position consumed, out Position examined) public bool TakeMessageHeaders(ReadOnlyBuffer<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;
@ -453,7 +454,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
finally finally
{ {
Input.Advance(consumed, examined); Input.AdvanceTo(consumed, examined);
} }
if (result.IsCompleted) if (result.IsCompleted)

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
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; }
public IPipeConnection Transport { get; set; } public IDuplexPipe Transport { get; set; }
public IPipeConnection Application { get; set; } public IDuplexPipe Application { get; set; }
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.IO; using System.IO;
using System.IO.Pipelines; using System.IO.Pipelines;
@ -62,19 +63,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
if (!readableBuffer.IsEmpty) if (!readableBuffer.IsEmpty)
{ {
var writableBuffer = _context.RequestBodyPipe.Writer.Alloc(1);
bool done; bool done;
try try
{ {
done = Read(readableBuffer, writableBuffer, out consumed, out examined); done = Read(readableBuffer, _context.RequestBodyPipe.Writer, out consumed, out examined);
} }
finally finally
{ {
writableBuffer.Commit(); _context.RequestBodyPipe.Writer.Commit();
} }
var writeAwaitable = writableBuffer.FlushAsync(); var writeAwaitable = _context.RequestBodyPipe.Writer.FlushAsync();
var backpressure = false; var backpressure = false;
if (!writeAwaitable.IsCompleted) if (!writeAwaitable.IsCompleted)
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
finally finally
{ {
_context.Input.Advance(consumed, examined); _context.Input.AdvanceTo(consumed, examined);
} }
} }
} }
@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
do do
{ {
result = await _context.RequestBodyPipe.Reader.ReadAsync(); result = await _context.RequestBodyPipe.Reader.ReadAsync();
_context.RequestBodyPipe.Reader.Advance(result.Buffer.End); _context.RequestBodyPipe.Reader.AdvanceTo(result.Buffer.End);
} while (!result.IsCompleted); } while (!result.IsCompleted);
} }
finally finally
@ -151,11 +151,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
protected void Copy(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer) protected void Copy(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer)
{ {
_context.TimeoutControl.BytesRead(readableBuffer.Length); _context.TimeoutControl.BytesRead(readableBuffer.Length);
if (readableBuffer.IsSingleSpan) if (readableBuffer.IsSingleSegment)
{ {
writableBuffer.Write(readableBuffer.First.Span); writableBuffer.Write(readableBuffer.First.Span);
} }
@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_pumpTask = PumpAsync(); _pumpTask = PumpAsync();
} }
protected virtual bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) protected virtual bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
RequestUpgrade = true; RequestUpgrade = true;
} }
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
Copy(readableBuffer, writableBuffer); Copy(readableBuffer, writableBuffer);
consumed = readableBuffer.End; consumed = readableBuffer.End;
@ -316,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_inputLength = _contentLength; _inputLength = _contentLength;
} }
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
if (_inputLength == 0) if (_inputLength == 0)
{ {
@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var actual = (int)Math.Min(readableBuffer.Length, _inputLength); var actual = (int)Math.Min(readableBuffer.Length, _inputLength);
_inputLength -= actual; _inputLength -= actual;
consumed = readableBuffer.Move(readableBuffer.Start, actual); consumed = readableBuffer.GetPosition(readableBuffer.Start, actual);
examined = consumed; examined = consumed;
Copy(readableBuffer.Slice(0, actual), writableBuffer); Copy(readableBuffer.Slice(0, actual), writableBuffer);
@ -364,10 +364,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
RequestKeepAlive = keepAlive; RequestKeepAlive = keepAlive;
} }
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = default(Position); consumed = default(SequencePosition);
examined = default(Position); examined = default(SequencePosition);
while (_mode < Mode.Trailer) while (_mode < Mode.Trailer)
{ {
@ -455,13 +455,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private void ParseChunkedPrefix(ReadOnlyBuffer buffer, out Position consumed, out Position examined) private void ParseChunkedPrefix(ReadOnlyBuffer<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 = BufferReader.Create(buffer);
var ch1 = reader.Take(); var ch1 = reader.Read();
var ch2 = reader.Take(); var ch2 = reader.Read();
if (ch1 == -1 || ch2 == -1) if (ch1 == -1 || ch2 == -1)
{ {
@ -485,7 +485,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return; return;
} }
ch2 = reader.Take(); ch2 = reader.Read();
if (ch2 == -1) if (ch2 == -1)
{ {
examined = reader.Position; examined = reader.Position;
@ -511,7 +511,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_context.ThrowRequestRejected(RequestRejectionReason.BadChunkSizeData); _context.ThrowRequestRejected(RequestRejectionReason.BadChunkSizeData);
} }
private void ParseExtension(ReadOnlyBuffer buffer, out Position consumed, out Position examined) private void ParseExtension(ReadOnlyBuffer<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
@ -520,8 +520,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
do do
{ {
Position extensionCursor; SequencePosition? extensionCursorPosition = buffer.PositionOf(ByteCR);
if (ReadOnlyBuffer.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1) if (extensionCursorPosition == null)
{ {
// End marker not found yet // End marker not found yet
consumed = buffer.End; consumed = buffer.End;
@ -530,6 +530,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return; return;
}; };
var extensionCursor = extensionCursorPosition.Value;
var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length; var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;
var sufixBuffer = buffer.Slice(extensionCursor); var sufixBuffer = buffer.Slice(extensionCursor);
@ -563,10 +564,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} while (_mode == Mode.Extension); } while (_mode == Mode.Extension);
} }
private void ReadChunkedData(ReadOnlyBuffer buffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) private void ReadChunkedData(ReadOnlyBuffer<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.Move(buffer.Start, actual); consumed = buffer.GetPosition(buffer.Start, actual);
examined = consumed; examined = consumed;
Copy(buffer.Slice(0, actual), writableBuffer); Copy(buffer.Slice(0, actual), writableBuffer);
@ -580,7 +581,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private void ParseChunkedSuffix(ReadOnlyBuffer buffer, out Position consumed, out Position examined) private void ParseChunkedSuffix(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.Start; examined = buffer.Start;
@ -606,7 +607,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
private void ParseChunkedTrailer(ReadOnlyBuffer buffer, out Position consumed, out Position examined) private void ParseChunkedTrailer(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.Start; examined = buffer.Start;

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -28,8 +29,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private bool _completed = false; private bool _completed = false;
private readonly IPipeWriter _pipeWriter; private readonly PipeWriter _pipeWriter;
private readonly IPipeReader _outputPipeReader; private readonly PipeReader _outputPipeReader;
// https://github.com/dotnet/corefxlab/issues/1334 // https://github.com/dotnet/corefxlab/issues/1334
// Pipelines don't support multiple awaiters on flush // Pipelines don't support multiple awaiters on flush
@ -39,8 +40,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private Action _flushCompleted; private Action _flushCompleted;
public Http1OutputProducer( public Http1OutputProducer(
IPipeReader outputPipeReader, PipeReader outputPipeReader,
IPipeWriter pipeWriter, PipeWriter pipeWriter,
string connectionId, string connectionId,
IKestrelTrace log, IKestrelTrace log,
ITimeoutControl timeoutControl) ITimeoutControl timeoutControl)
@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return WriteAsync(Constants.EmptyData, cancellationToken); return WriteAsync(Constants.EmptyData, cancellationToken);
} }
public void Write<T>(Action<WritableBuffer, T> callback, T state) public void Write<T>(Action<PipeWriter, T> callback, T state)
{ {
lock (_contextLock) lock (_contextLock)
{ {
@ -82,13 +83,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return; return;
} }
var buffer = _pipeWriter.Alloc(1); var buffer = _pipeWriter;
callback(buffer, state); callback(buffer, state);
buffer.Commit(); buffer.Commit();
} }
} }
public Task WriteAsync<T>(Action<WritableBuffer, T> callback, T state) public Task WriteAsync<T>(Action<PipeWriter, T> callback, T state)
{ {
lock (_contextLock) lock (_contextLock)
{ {
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return Task.CompletedTask; return Task.CompletedTask;
} }
var buffer = _pipeWriter.Alloc(1); var buffer = _pipeWriter;
callback(buffer, state); callback(buffer, state);
buffer.Commit(); buffer.Commit();
} }
@ -114,8 +115,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return; return;
} }
var buffer = _pipeWriter.Alloc(1); var buffer = _pipeWriter;
var writer = new WritableBufferWriter(buffer); var writer = OutputWriter.Create(buffer);
writer.Write(_bytesHttpVersion11); writer.Write(_bytesHttpVersion11);
var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase); var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase);
@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
ArraySegment<byte> buffer, ArraySegment<byte> buffer,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var writableBuffer = default(WritableBuffer); var writableBuffer = default(PipeWriter);
long bytesWritten = 0; long bytesWritten = 0;
lock (_contextLock) lock (_contextLock)
{ {
@ -176,11 +177,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return Task.CompletedTask; return Task.CompletedTask;
} }
writableBuffer = _pipeWriter.Alloc(1); writableBuffer = _pipeWriter;
var writer = new WritableBufferWriter(writableBuffer); var writer = OutputWriter.Create(writableBuffer);
if (buffer.Count > 0) if (buffer.Count > 0)
{ {
writer.Write(buffer.Array, buffer.Offset, buffer.Count); writer.Write(new ReadOnlySpan<byte>(buffer.Array, buffer.Offset, buffer.Count));
bytesWritten += buffer.Count; bytesWritten += buffer.Count;
} }
@ -192,7 +193,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// Single caller, at end of method - so inline // Single caller, at end of method - so inline
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Task FlushAsync(WritableBuffer writableBuffer, long bytesWritten, CancellationToken cancellationToken) private Task FlushAsync(PipeWriter writableBuffer, long bytesWritten, CancellationToken cancellationToken)
{ {
var awaitable = writableBuffer.FlushAsync(cancellationToken); var awaitable = writableBuffer.FlushAsync(cancellationToken);
if (awaitable.IsCompleted) if (awaitable.IsCompleted)

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -7753,7 +7754,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true; return true;
} }
protected void CopyToFast(ref WritableBufferWriter output) protected void CopyToFast(ref OutputWriter<PipeWriter> output)
{ {
var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0); var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0);
@ -7771,7 +7772,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Connection[i]; var value = _headers._Connection[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 17, 14); output.Write(new ReadOnlySpan<byte>(_headerBytes, 17, 14));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7797,7 +7798,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Date[i]; var value = _headers._Date[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 31, 8); output.Write(new ReadOnlySpan<byte>(_headerBytes, 31, 8));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7818,7 +7819,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ContentType[i]; var value = _headers._ContentType[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 133, 16); output.Write(new ReadOnlySpan<byte>(_headerBytes, 133, 16));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7844,7 +7845,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Server[i]; var value = _headers._Server[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 350, 10); output.Write(new ReadOnlySpan<byte>(_headerBytes, 350, 10));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7858,7 +7859,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
if ((tempBits & -9223372036854775808L) != 0) if ((tempBits & -9223372036854775808L) != 0)
{ {
output.Write(_headerBytes, 592, 18); output.Write(new ReadOnlySpan<byte>(_headerBytes, 592, 18));
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value); PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
if((tempBits & ~-9223372036854775808L) == 0) if((tempBits & ~-9223372036854775808L) == 0)
@ -7876,7 +7877,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._CacheControl[i]; var value = _headers._CacheControl[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 0, 17); output.Write(new ReadOnlySpan<byte>(_headerBytes, 0, 17));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7897,7 +7898,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._KeepAlive[i]; var value = _headers._KeepAlive[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 39, 14); output.Write(new ReadOnlySpan<byte>(_headerBytes, 39, 14));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7918,7 +7919,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Pragma[i]; var value = _headers._Pragma[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 53, 10); output.Write(new ReadOnlySpan<byte>(_headerBytes, 53, 10));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7939,7 +7940,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Trailer[i]; var value = _headers._Trailer[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 63, 11); output.Write(new ReadOnlySpan<byte>(_headerBytes, 63, 11));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7965,7 +7966,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._TransferEncoding[i]; var value = _headers._TransferEncoding[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 74, 21); output.Write(new ReadOnlySpan<byte>(_headerBytes, 74, 21));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -7986,7 +7987,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Upgrade[i]; var value = _headers._Upgrade[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 95, 11); output.Write(new ReadOnlySpan<byte>(_headerBytes, 95, 11));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8007,7 +8008,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Via[i]; var value = _headers._Via[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 106, 7); output.Write(new ReadOnlySpan<byte>(_headerBytes, 106, 7));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8028,7 +8029,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Warning[i]; var value = _headers._Warning[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 113, 11); output.Write(new ReadOnlySpan<byte>(_headerBytes, 113, 11));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8049,7 +8050,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Allow[i]; var value = _headers._Allow[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 124, 9); output.Write(new ReadOnlySpan<byte>(_headerBytes, 124, 9));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8070,7 +8071,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ContentEncoding[i]; var value = _headers._ContentEncoding[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 149, 20); output.Write(new ReadOnlySpan<byte>(_headerBytes, 149, 20));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8091,7 +8092,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ContentLanguage[i]; var value = _headers._ContentLanguage[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 169, 20); output.Write(new ReadOnlySpan<byte>(_headerBytes, 169, 20));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8112,7 +8113,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ContentLocation[i]; var value = _headers._ContentLocation[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 189, 20); output.Write(new ReadOnlySpan<byte>(_headerBytes, 189, 20));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8133,7 +8134,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ContentMD5[i]; var value = _headers._ContentMD5[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 209, 15); output.Write(new ReadOnlySpan<byte>(_headerBytes, 209, 15));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8154,7 +8155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ContentRange[i]; var value = _headers._ContentRange[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 224, 17); output.Write(new ReadOnlySpan<byte>(_headerBytes, 224, 17));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8175,7 +8176,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Expires[i]; var value = _headers._Expires[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 241, 11); output.Write(new ReadOnlySpan<byte>(_headerBytes, 241, 11));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8196,7 +8197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._LastModified[i]; var value = _headers._LastModified[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 252, 17); output.Write(new ReadOnlySpan<byte>(_headerBytes, 252, 17));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8217,7 +8218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AcceptRanges[i]; var value = _headers._AcceptRanges[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 269, 17); output.Write(new ReadOnlySpan<byte>(_headerBytes, 269, 17));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8238,7 +8239,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Age[i]; var value = _headers._Age[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 286, 7); output.Write(new ReadOnlySpan<byte>(_headerBytes, 286, 7));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8259,7 +8260,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ETag[i]; var value = _headers._ETag[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 293, 8); output.Write(new ReadOnlySpan<byte>(_headerBytes, 293, 8));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8280,7 +8281,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Location[i]; var value = _headers._Location[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 301, 12); output.Write(new ReadOnlySpan<byte>(_headerBytes, 301, 12));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8301,7 +8302,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._ProxyAuthenticate[i]; var value = _headers._ProxyAuthenticate[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 313, 22); output.Write(new ReadOnlySpan<byte>(_headerBytes, 313, 22));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8322,7 +8323,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._RetryAfter[i]; var value = _headers._RetryAfter[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 335, 15); output.Write(new ReadOnlySpan<byte>(_headerBytes, 335, 15));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8343,7 +8344,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._SetCookie[i]; var value = _headers._SetCookie[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 360, 14); output.Write(new ReadOnlySpan<byte>(_headerBytes, 360, 14));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8364,7 +8365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._Vary[i]; var value = _headers._Vary[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 374, 8); output.Write(new ReadOnlySpan<byte>(_headerBytes, 374, 8));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8385,7 +8386,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._WWWAuthenticate[i]; var value = _headers._WWWAuthenticate[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 382, 20); output.Write(new ReadOnlySpan<byte>(_headerBytes, 382, 20));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8406,7 +8407,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AccessControlAllowCredentials[i]; var value = _headers._AccessControlAllowCredentials[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 402, 36); output.Write(new ReadOnlySpan<byte>(_headerBytes, 402, 36));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8427,7 +8428,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AccessControlAllowHeaders[i]; var value = _headers._AccessControlAllowHeaders[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 438, 32); output.Write(new ReadOnlySpan<byte>(_headerBytes, 438, 32));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8448,7 +8449,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AccessControlAllowMethods[i]; var value = _headers._AccessControlAllowMethods[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 470, 32); output.Write(new ReadOnlySpan<byte>(_headerBytes, 470, 32));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8469,7 +8470,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AccessControlAllowOrigin[i]; var value = _headers._AccessControlAllowOrigin[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 502, 31); output.Write(new ReadOnlySpan<byte>(_headerBytes, 502, 31));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8490,7 +8491,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AccessControlExposeHeaders[i]; var value = _headers._AccessControlExposeHeaders[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 533, 33); output.Write(new ReadOnlySpan<byte>(_headerBytes, 533, 33));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }
@ -8511,7 +8512,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._AccessControlMaxAge[i]; var value = _headers._AccessControlMaxAge[i];
if (value != null) if (value != null)
{ {
output.Write(_headerBytes, 566, 26); output.Write(new ReadOnlySpan<byte>(_headerBytes, 566, 26));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -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 buffer, out Position consumed, out Position examined) public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -43,10 +44,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var lineIndex = span.IndexOf(ByteLF); var lineIndex = span.IndexOf(ByteLF);
if (lineIndex >= 0) if (lineIndex >= 0)
{ {
consumed = buffer.Move(consumed, lineIndex + 1); consumed = buffer.GetPosition(consumed, lineIndex + 1);
span = span.Slice(0, lineIndex + 1); span = span.Slice(0, lineIndex + 1);
} }
else if (buffer.IsSingleSpan) else if (buffer.IsSingleSegment)
{ {
// No request line end // No request line end
return false; return false;
@ -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 buffer, out Position consumed, out Position examined, out int consumedBytes) public unsafe bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
{ {
consumed = buffer.Start; consumed = buffer.Start;
examined = buffer.End; examined = buffer.End;
@ -197,21 +198,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var bufferEnd = buffer.End; var bufferEnd = buffer.End;
var reader = BufferReader.Create(buffer); var reader = BufferReader.Create(buffer);
var start = default(BufferReader<ReadOnlyBuffer>); var start = default(BufferReader<ReadOnlyBuffer<byte>>);
var done = false; var done = false;
try try
{ {
while (!reader.End) while (!reader.End)
{ {
var span = reader.Span; var span = reader.CurrentSegment;
var remaining = span.Length - reader.Index; var remaining = span.Length - reader.CurrentSegmentIndex;
fixed (byte* pBuffer = &MemoryMarshal.GetReference(span)) fixed (byte* pBuffer = &MemoryMarshal.GetReference(span))
{ {
while (remaining > 0) while (remaining > 0)
{ {
var index = reader.Index; var index = reader.CurrentSegmentIndex;
int ch1; int ch1;
int ch2; int ch2;
@ -228,8 +229,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
start = reader; start = reader;
// Possibly split across spans // Possibly split across spans
ch1 = reader.Take(); ch1 = reader.Read();
ch2 = reader.Take(); ch2 = reader.Read();
} }
if (ch1 == ByteCR) if (ch1 == ByteCR)
@ -245,9 +246,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
// If we got 2 bytes from the span directly so skip ahead 2 so that // If we got 2 bytes from the span directly so skip ahead 2 so that
// the reader's state matches what we expect // the reader's state matches what we expect
if (index == reader.Index) if (index == reader.CurrentSegmentIndex)
{ {
reader.Skip(2); reader.Advance(2);
} }
done = true; done = true;
@ -260,10 +261,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// We moved the reader so look ahead 2 bytes so reset both the reader // We moved the reader so look ahead 2 bytes so reset both the reader
// and the index // and the index
if (index != reader.Index) if (index != reader.CurrentSegmentIndex)
{ {
reader = start; reader = start;
index = reader.Index; index = reader.CurrentSegmentIndex;
} }
var endIndex = new Span<byte>(pBuffer + index, remaining).IndexOf(ByteLF); var endIndex = new Span<byte>(pBuffer + index, remaining).IndexOf(ByteLF);
@ -279,16 +280,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
else else
{ {
var current = reader.Position; var current = reader.Position;
var currentSlice = buffer.Slice(current, bufferEnd);
var lineEndPosition = currentSlice.PositionOf(ByteLF);
// Split buffers // Split buffers
if (ReadOnlyBuffer.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1) if (lineEndPosition == null)
{ {
// Not there // Not there
return false; return false;
} }
var lineEnd = lineEndPosition.Value;
// Make sure LF is included in lineEnd // Make sure LF is included in lineEnd
lineEnd = buffer.Move(lineEnd, 1); lineEnd = buffer.GetPosition(lineEnd, 1);
var headerSpan = buffer.Slice(current, lineEnd).ToSpan(); var headerSpan = buffer.Slice(current, lineEnd).ToSpan();
length = headerSpan.Length; length = headerSpan.Length;
@ -304,7 +309,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
// Skip the reader forward past the header line // Skip the reader forward past the header line
reader.Skip(length); reader.Advance(length);
remaining -= length; remaining -= length;
} }
} }
@ -414,15 +419,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private static bool TryGetNewLine(ref ReadOnlyBuffer buffer, out Position found) private static bool TryGetNewLine(ref ReadOnlyBuffer<byte> buffer, out SequencePosition found)
{ {
var start = buffer.Start; var byteLfPosition = buffer.PositionOf(ByteLF);
if (ReadOnlyBuffer.Seek(start, buffer.End, out found, ByteLF) != -1) if (byteLfPosition != null)
{ {
// Move 1 byte past the \n // Move 1 byte past the \n
found = buffer.Move(found, 1); found = buffer.GetPosition(byteLfPosition.Value, 1);
return true; return true;
} }
found = default;
return false; return false;
} }

View File

@ -4,31 +4,35 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
public partial class HttpProtocol public partial class HttpProtocol
{ {
private static readonly Type IHttpRequestFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature); private static readonly Type IHttpRequestFeatureType = typeof(IHttpRequestFeature);
private static readonly Type IHttpResponseFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature); private static readonly Type IHttpResponseFeatureType = typeof(IHttpResponseFeature);
private static readonly Type IHttpRequestIdentifierFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature); private static readonly Type IHttpRequestIdentifierFeatureType = typeof(IHttpRequestIdentifierFeature);
private static readonly Type IServiceProvidersFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature); private static readonly Type IServiceProvidersFeatureType = typeof(IServiceProvidersFeature);
private static readonly Type IHttpRequestLifetimeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature); private static readonly Type IHttpRequestLifetimeFeatureType = typeof(IHttpRequestLifetimeFeature);
private static readonly Type IHttpConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature); private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
private static readonly Type IHttpAuthenticationFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature); private static readonly Type IHttpAuthenticationFeatureType = typeof(IHttpAuthenticationFeature);
private static readonly Type IQueryFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IQueryFeature); private static readonly Type IQueryFeatureType = typeof(IQueryFeature);
private static readonly Type IFormFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IFormFeature); private static readonly Type IFormFeatureType = typeof(IFormFeature);
private static readonly Type IHttpUpgradeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature); private static readonly Type IHttpUpgradeFeatureType = typeof(IHttpUpgradeFeature);
private static readonly Type IHttp2StreamIdFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature); private static readonly Type IHttp2StreamIdFeatureType = typeof(IHttp2StreamIdFeature);
private static readonly Type IResponseCookiesFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature); private static readonly Type IResponseCookiesFeatureType = typeof(IResponseCookiesFeature);
private static readonly Type IItemsFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IItemsFeature); private static readonly Type IItemsFeatureType = typeof(IItemsFeature);
private static readonly Type ITlsConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature); private static readonly Type ITlsConnectionFeatureType = typeof(ITlsConnectionFeature);
private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature); private static readonly Type IHttpWebSocketFeatureType = typeof(IHttpWebSocketFeature);
private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ISessionFeature); private static readonly Type ISessionFeatureType = typeof(ISessionFeature);
private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature); private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(IHttpMaxRequestBodySizeFeature);
private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature); private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(IHttpMinRequestBodyDataRateFeature);
private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature); private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(IHttpMinResponseDataRateFeature);
private static readonly Type IHttpBodyControlFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature); private static readonly Type IHttpBodyControlFeatureType = typeof(IHttpBodyControlFeature);
private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature); private static readonly Type IHttpSendFileFeatureType = typeof(IHttpSendFileFeature);
private object _currentIHttpRequestFeature; private object _currentIHttpRequestFeature;
private object _currentIHttpResponseFeature; private object _currentIHttpResponseFeature;
@ -283,87 +287,87 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
if (_currentIHttpRequestFeature != null) if (_currentIHttpRequestFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature); yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as IHttpRequestFeature);
} }
if (_currentIHttpResponseFeature != null) if (_currentIHttpResponseFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature); yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as IHttpResponseFeature);
} }
if (_currentIHttpRequestIdentifierFeature != null) if (_currentIHttpRequestIdentifierFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature); yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as IHttpRequestIdentifierFeature);
} }
if (_currentIServiceProvidersFeature != null) if (_currentIServiceProvidersFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature); yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as IServiceProvidersFeature);
} }
if (_currentIHttpRequestLifetimeFeature != null) if (_currentIHttpRequestLifetimeFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature); yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as IHttpRequestLifetimeFeature);
} }
if (_currentIHttpConnectionFeature != null) if (_currentIHttpConnectionFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature); yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as IHttpConnectionFeature);
} }
if (_currentIHttpAuthenticationFeature != null) if (_currentIHttpAuthenticationFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature); yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as IHttpAuthenticationFeature);
} }
if (_currentIQueryFeature != null) if (_currentIQueryFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as global::Microsoft.AspNetCore.Http.Features.IQueryFeature); yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as IQueryFeature);
} }
if (_currentIFormFeature != null) if (_currentIFormFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as global::Microsoft.AspNetCore.Http.Features.IFormFeature); yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as IFormFeature);
} }
if (_currentIHttpUpgradeFeature != null) if (_currentIHttpUpgradeFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature); yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as IHttpUpgradeFeature);
} }
if (_currentIHttp2StreamIdFeature != null) if (_currentIHttp2StreamIdFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature); yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as IHttp2StreamIdFeature);
} }
if (_currentIResponseCookiesFeature != null) if (_currentIResponseCookiesFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature); yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as IResponseCookiesFeature);
} }
if (_currentIItemsFeature != null) if (_currentIItemsFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as global::Microsoft.AspNetCore.Http.Features.IItemsFeature); yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as IItemsFeature);
} }
if (_currentITlsConnectionFeature != null) if (_currentITlsConnectionFeature != null)
{ {
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature); yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as ITlsConnectionFeature);
} }
if (_currentIHttpWebSocketFeature != null) if (_currentIHttpWebSocketFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature); yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as IHttpWebSocketFeature);
} }
if (_currentISessionFeature != null) if (_currentISessionFeature != null)
{ {
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as global::Microsoft.AspNetCore.Http.Features.ISessionFeature); yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as ISessionFeature);
} }
if (_currentIHttpMaxRequestBodySizeFeature != null) if (_currentIHttpMaxRequestBodySizeFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature); yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as IHttpMaxRequestBodySizeFeature);
} }
if (_currentIHttpMinRequestBodyDataRateFeature != null) if (_currentIHttpMinRequestBodyDataRateFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature); yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as IHttpMinRequestBodyDataRateFeature);
} }
if (_currentIHttpMinResponseDataRateFeature != null) if (_currentIHttpMinResponseDataRateFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature); yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as IHttpMinResponseDataRateFeature);
} }
if (_currentIHttpBodyControlFeature != null) if (_currentIHttpBodyControlFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature); yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as IHttpBodyControlFeature);
} }
if (_currentIHttpSendFileFeature != null) if (_currentIHttpSendFileFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature); yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as IHttpSendFileFeature);
} }
if (MaybeExtra != null) if (MaybeExtra != null)

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive"); private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive");
private static readonly byte[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked"); private static readonly byte[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked");
private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName); private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName);
private static readonly Action<WritableBuffer, ArraySegment<byte>> _writeChunk = WriteChunk; private static readonly Action<PipeWriter, ArraySegment<byte>> _writeChunk = WriteChunk;
private readonly object _onStartingSync = new Object(); private readonly object _onStartingSync = new Object();
private readonly object _onCompletedSync = new Object(); private readonly object _onCompletedSync = new Object();
@ -895,13 +896,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return Output.WriteAsync(_writeChunk, data); return Output.WriteAsync(_writeChunk, data);
} }
private static void WriteChunk(WritableBuffer writableBuffer, ArraySegment<byte> buffer) private static void WriteChunk(PipeWriter writableBuffer, ArraySegment<byte> buffer)
{ {
var writer = new WritableBufferWriter(writableBuffer); var writer = OutputWriter.Create(writableBuffer);
if (buffer.Count > 0) if (buffer.Count > 0)
{ {
ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Count); ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Count);
writer.Write(buffer.Array, buffer.Offset, buffer.Count); writer.Write(new ReadOnlySpan<byte>(buffer.Array, buffer.Offset, buffer.Count));
ChunkWriter.WriteEndChunkBytes(ref writer); ChunkWriter.WriteEndChunkBytes(ref writer);
} }
} }
@ -1297,9 +1298,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
( (
pool: _context.MemoryPool, pool: _context.MemoryPool,
readerScheduler: ServiceContext.ThreadPool, readerScheduler: ServiceContext.ThreadPool,
writerScheduler: Scheduler.Inline, writerScheduler: PipeScheduler.Inline,
maximumSizeHigh: 1, pauseWriterThreshold: 1,
maximumSizeLow: 1 resumeWriterThreshold: 1
)); ));
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return GetEnumerator(); return GetEnumerator();
} }
public void CopyTo(ref WritableBufferWriter output) public void CopyTo(ref OutputWriter<PipeWriter> output)
{ {
CopyToFast(ref output); CopyToFast(ref output);
if (MaybeUnknown != null) if (MaybeUnknown != null)

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public interface IHttpOutputProducer : IDisposable public interface IHttpOutputProducer : IDisposable
{ {
void Abort(Exception error); void Abort(Exception error);
Task WriteAsync<T>(Action<WritableBuffer, T> callback, T state); Task WriteAsync<T>(Action<PipeWriter, T> callback, T state);
Task FlushAsync(CancellationToken cancellationToken); Task FlushAsync(CancellationToken cancellationToken);
Task Write100ContinueAsync(CancellationToken cancellationToken); Task Write100ContinueAsync(CancellationToken cancellationToken);
void WriteResponseHeaders(int statusCode, string ReasonPhrase, HttpResponseHeaders responseHeaders); void WriteResponseHeaders(int statusCode, string ReasonPhrase, HttpResponseHeaders responseHeaders);

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.IO.Pipelines; using System.IO.Pipelines;
@ -9,8 +10,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 buffer, out Position consumed, out Position examined); bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined);
bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes); bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes);
} }
} }

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// buffer.Count is int // buffer.Count is int
var actual = (int) Math.Min(readableBuffer.Length, buffer.Count); var actual = (int) Math.Min(readableBuffer.Length, buffer.Count);
var slice = readableBuffer.Slice(0, actual); var slice = readableBuffer.Slice(0, actual);
consumed = readableBuffer.Move(readableBuffer.Start, actual); consumed = readableBuffer.GetPosition(readableBuffer.Start, actual);
slice.CopyTo(buffer); slice.CopyTo(buffer);
return actual; return actual;
} }
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
finally finally
{ {
_context.RequestBodyPipe.Reader.Advance(consumed); _context.RequestBodyPipe.Reader.AdvanceTo(consumed);
} }
} }
} }
@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
finally finally
{ {
_context.RequestBodyPipe.Reader.Advance(consumed); _context.RequestBodyPipe.Reader.AdvanceTo(consumed);
} }
} }
} }

View File

@ -17,9 +17,9 @@ 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 buffer) public static ReadOnlySpan<byte> ToSpan(this ReadOnlyBuffer<byte> buffer)
{ {
if (buffer.IsSingleSpan) if (buffer.IsSingleSegment)
{ {
return buffer.First.Span; return buffer.First.Span;
} }
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return result; return result;
} }
public unsafe static void WriteAsciiNoValidation(ref this WritableBufferWriter buffer, string data) public unsafe static void WriteAsciiNoValidation(ref this OutputWriter<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 WritableBufferWriter buffer, ulong number) public unsafe static void WriteNumeric(ref this OutputWriter<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 WritableBufferWriter buffer, ulong number) private static void WriteNumericMultiWrite(ref this OutputWriter<PipeWriter> buffer, ulong number)
{ {
const byte AsciiDigitStart = (byte)'0'; const byte AsciiDigitStart = (byte)'0';
@ -141,11 +141,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
while (value != 0); while (value != 0);
var length = _maxULongByteLength - position; var length = _maxULongByteLength - position;
buffer.Write(byteBuffer, position, length); buffer.Write(new ReadOnlySpan<byte>(byteBuffer, position, length));
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private unsafe static void WriteAsciiMultiWrite(ref this WritableBufferWriter buffer, string data) private unsafe static void WriteAsciiMultiWrite(ref this OutputWriter<PipeWriter> buffer, string data)
{ {
var remaining = data.Length; var remaining = data.Length;

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.IO.Pipelines; using System.IO.Pipelines;
@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public string ConnectionId => _context.ConnectionId; public string ConnectionId => _context.ConnectionId;
public IPipeReader Input => _context.Transport.Input; public PipeReader Input => _context.Transport.Input;
public IKestrelTrace Log => _context.ServiceContext.Log; public IKestrelTrace Log => _context.ServiceContext.Log;
@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
finally finally
{ {
Input.Advance(consumed, examined); Input.AdvanceTo(consumed, examined);
} }
} }
@ -165,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
finally finally
{ {
Input.Advance(consumed, examined); Input.AdvanceTo(consumed, examined);
} }
} }
} }
@ -216,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
} }
private bool ParsePreface(ReadOnlyBuffer readableBuffer, out Position consumed, out Position examined) private bool ParsePreface(ReadOnlyBuffer<byte> readableBuffer, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = readableBuffer.Start; consumed = readableBuffer.Start;
examined = readableBuffer.End; examined = readableBuffer.End;
@ -226,7 +227,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
return false; return false;
} }
var span = readableBuffer.IsSingleSpan var span = readableBuffer.IsSingleSegment
? readableBuffer.First.Span ? readableBuffer.First.Span
: readableBuffer.ToSpan(); : readableBuffer.ToSpan();
@ -238,7 +239,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
} }
consumed = examined = readableBuffer.Move(readableBuffer.Start, ClientPreface.Length); consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, ClientPreface.Length);
return true; return true;
} }

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; }
public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; }
public IPipeConnection Transport { get; set; } public IDuplexPipe Transport { get; set; }
public IPipeConnection Application { get; set; } public IDuplexPipe Application { get; set; }
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers; using System.Buffers;
using System.Collections;
using System.Collections.Sequences; using System.Collections.Sequences;
using System.IO.Pipelines; using System.IO.Pipelines;
@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
public static class Http2FrameReader public static class Http2FrameReader
{ {
public static bool ReadFrame(ReadOnlyBuffer readableBuffer, Http2Frame frame, out Position consumed, out Position examined) public static bool ReadFrame(ReadOnlyBuffer<byte> readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined)
{ {
consumed = readableBuffer.Start; consumed = readableBuffer.Start;
examined = readableBuffer.End; examined = readableBuffer.End;
@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
} }
readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload); readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload);
consumed = examined = readableBuffer.Move(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length); consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length);
return true; return true;
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Threading; using System.Threading;
@ -20,12 +21,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
private readonly Http2Frame _outgoingFrame = new Http2Frame(); private readonly Http2Frame _outgoingFrame = new Http2Frame();
private readonly object _writeLock = new object(); private readonly object _writeLock = new object();
private readonly HPackEncoder _hpackEncoder = new HPackEncoder(); private readonly HPackEncoder _hpackEncoder = new HPackEncoder();
private readonly IPipeWriter _outputWriter; private readonly PipeWriter _outputWriter;
private readonly IPipeReader _outputReader; private readonly PipeReader _outputReader;
private bool _completed; private bool _completed;
public Http2FrameWriter(IPipeWriter outputPipeWriter, IPipeReader outputPipeReader) public Http2FrameWriter(PipeWriter outputPipeWriter, PipeReader outputPipeReader)
{ {
_outputWriter = outputPipeWriter; _outputWriter = outputPipeWriter;
_outputReader = outputPipeReader; _outputReader = outputPipeReader;
@ -48,7 +49,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
public Task FlushAsync(CancellationToken cancellationToken) public Task FlushAsync(CancellationToken cancellationToken)
{ {
return WriteAsync(Constants.EmptyData); lock (_writeLock)
{
return WriteAsync(Constants.EmptyData);
}
} }
public Task Write100ContinueAsync(int streamId) public Task Write100ContinueAsync(int streamId)
@ -185,9 +189,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
return; return;
} }
var writeableBuffer = _outputWriter.Alloc(1); _outputWriter.Write(data);
writeableBuffer.Write(data); _outputWriter.Commit();
writeableBuffer.Commit();
} }
// Must be called with _writeLock // Must be called with _writeLock
@ -198,9 +201,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
return; return;
} }
var writeableBuffer = _outputWriter.Alloc(1); _outputWriter.Write(data);
writeableBuffer.Write(data); await _outputWriter.FlushAsync(cancellationToken);
await writeableBuffer.FlushAsync(cancellationToken);
} }
private static IEnumerable<KeyValuePair<string, string>> EnumerateHeaders(IHeaderDictionary headers) private static IEnumerable<KeyValuePair<string, string>> EnumerateHeaders(IHeaderDictionary headers)

View File

@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
// TODO: RST_STREAM? // TODO: RST_STREAM?
} }
public Task WriteAsync<T>(Action<WritableBuffer, T> callback, T state) public Task WriteAsync<T>(Action<PipeWriter, T> callback, T state)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
@ -78,19 +79,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
{ {
if (data.Count > 0) if (data.Count > 0)
{ {
var writableBuffer = RequestBodyPipe.Writer.Alloc(1);
try try
{ {
writableBuffer.Write(data); RequestBodyPipe.Writer.Write(data);
} }
finally finally
{ {
writableBuffer.Commit(); RequestBodyPipe.Writer.Commit();
} }
RequestBodyStarted = true; RequestBodyStarted = true;
await writableBuffer.FlushAsync(); await RequestBodyPipe.Writer.FlushAsync();
} }
if (endStream) if (endStream)

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously); private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
private IList<IAdaptedConnection> _adaptedConnections; private IList<IAdaptedConnection> _adaptedConnections;
private IPipeConnection _adaptedTransport; private IDuplexPipe _adaptedTransport;
private readonly object _protocolSelectionLock = new object(); private readonly object _protocolSelectionLock = new object();
private ProtocolSelectionState _protocolSelectionState = ProtocolSelectionState.Initializing; private ProtocolSelectionState _protocolSelectionState = ProtocolSelectionState.Initializing;
@ -75,18 +75,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
( (
pool: MemoryPool, pool: MemoryPool,
readerScheduler: _context.ServiceContext.ThreadPool, readerScheduler: _context.ServiceContext.ThreadPool,
writerScheduler: Scheduler.Inline, writerScheduler: PipeScheduler.Inline,
maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
); );
internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions
( (
pool: MemoryPool, pool: MemoryPool,
readerScheduler: Scheduler.Inline, readerScheduler: PipeScheduler.Inline,
writerScheduler: Scheduler.Inline, writerScheduler: PipeScheduler.Inline,
maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0,
maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0
); );
private IKestrelTrace Log => _context.ServiceContext.Log; private IKestrelTrace Log => _context.ServiceContext.Log;
@ -196,13 +196,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
} }
// For testing only // For testing only
internal void Initialize(IPipeConnection transport, IPipeConnection application) internal void Initialize(IDuplexPipe transport, IDuplexPipe application)
{ {
_requestProcessor = _http1Connection = CreateHttp1Connection(transport, application); _requestProcessor = _http1Connection = CreateHttp1Connection(transport, application);
_protocolSelectionState = ProtocolSelectionState.Selected; _protocolSelectionState = ProtocolSelectionState.Selected;
} }
private Http1Connection CreateHttp1Connection(IPipeConnection transport, IPipeConnection application) private Http1Connection CreateHttp1Connection(IDuplexPipe transport, IDuplexPipe application)
{ {
return new Http1Connection(new Http1ConnectionContext return new Http1Connection(new Http1ConnectionContext
{ {
@ -218,7 +218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
}); });
} }
private Http2Connection CreateHttp2Connection(IPipeConnection transport, IPipeConnection application) private Http2Connection CreateHttp2Connection(IDuplexPipe transport, IDuplexPipe application)
{ {
return new Http2Connection(new Http2ConnectionContext return new Http2Connection(new Http2ConnectionContext
{ {

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public MemoryPool MemoryPool { get; set; } public MemoryPool MemoryPool { get; set; }
public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; }
public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; }
public IPipeConnection Transport { get; set; } public IDuplexPipe Transport { get; set; }
public IPipeConnection Application { get; set; } public IDuplexPipe Application { get; set; }
} }
} }

View File

@ -2,12 +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; 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
{ {
public abstract class KestrelThreadPool: Scheduler public abstract class KestrelThreadPool : PipeScheduler
{ {
public abstract void Run(Action action); public abstract void Run(Action action);
public abstract void UnsafeRun(WaitCallback action, object state); public abstract void UnsafeRun(WaitCallback action, object state);

View File

@ -42,12 +42,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
public override void Run(Action action) public override void Run(Action action)
{ {
ThreadPool.QueueUserWorkItem(_runAction, action); System.Threading.ThreadPool.QueueUserWorkItem(_runAction, action);
} }
public override void UnsafeRun(WaitCallback action, object state) public override void UnsafeRun(WaitCallback action, object state)
{ {
ThreadPool.QueueUserWorkItem(action, state); System.Threading.ThreadPool.QueueUserWorkItem(action, state);
} }
public override void Schedule(Action action) public override void Schedule(Action action)

View File

@ -98,13 +98,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
MemoryPool IConnectionTransportFeature.MemoryPool => MemoryPool; MemoryPool IConnectionTransportFeature.MemoryPool => MemoryPool;
IPipeConnection IConnectionTransportFeature.Transport IDuplexPipe IConnectionTransportFeature.Transport
{ {
get => Transport; get => Transport;
set => Transport = value; set => Transport = value;
} }
IPipeConnection IConnectionTransportFeature.Application IDuplexPipe IConnectionTransportFeature.Application
{ {
get => Application; get => Application;
set => Application = value; set => Application = value;

View File

@ -23,13 +23,13 @@ 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 MemoryPool { get; }
public virtual Scheduler InputWriterScheduler { get; } public virtual PipeScheduler InputWriterScheduler { get; }
public virtual Scheduler OutputReaderScheduler { get; } public virtual PipeScheduler OutputReaderScheduler { get; }
public IPipeConnection Transport { get; set; } public IDuplexPipe Transport { get; set; }
public IPipeConnection Application { get; set; } public IDuplexPipe Application { get; set; }
public IPipeWriter Input => Application.Output; public PipeWriter Input => Application.Output;
public IPipeReader Output => Application.Input; public PipeReader Output => Application.Input;
} }
} }

View File

@ -27,7 +27,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
private readonly UvStreamHandle _socket; private readonly UvStreamHandle _socket;
private WritableBuffer? _currentWritableBuffer;
private MemoryHandle _bufferHandle; private MemoryHandle _bufferHandle;
public LibuvConnection(ListenerContext context, UvStreamHandle socket) : base(context) public LibuvConnection(ListenerContext context, UvStreamHandle socket) : base(context)
@ -107,13 +106,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
private unsafe LibuvFunctions.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize) private unsafe LibuvFunctions.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
{ {
Debug.Assert(_currentWritableBuffer == null); var currentWritableBuffer = Input.GetMemory(MinAllocBufferSize);
var currentWritableBuffer = Input.Alloc(MinAllocBufferSize); _bufferHandle = currentWritableBuffer.Retain(true);
_currentWritableBuffer = currentWritableBuffer;
_bufferHandle = currentWritableBuffer.Buffer.Retain(true); return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Length);
return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Buffer.Length);
} }
private static void ReadCallback(UvStreamHandle handle, int status, object state) private static void ReadCallback(UvStreamHandle handle, int status, object state)
@ -127,17 +123,14 @@ 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
Debug.Assert(_currentWritableBuffer != null); Input.Commit();
_currentWritableBuffer.Value.Commit();
} }
else if (status > 0) else if (status > 0)
{ {
Log.ConnectionRead(ConnectionId, status); Log.ConnectionRead(ConnectionId, status);
Debug.Assert(_currentWritableBuffer != null); Input.Advance(status);
var currentWritableBuffer = _currentWritableBuffer.Value; var flushTask = Input.FlushAsync();
currentWritableBuffer.Advance(status);
var flushTask = currentWritableBuffer.FlushAsync();
if (!flushTask.IsCompleted) if (!flushTask.IsCompleted)
{ {
@ -149,7 +142,7 @@ 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.
_currentWritableBuffer?.Commit(); Input.Commit();
_socket.ReadStop(); _socket.ReadStop();
IOException error = null; IOException error = null;
@ -180,7 +173,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
} }
// Cleanup state from last OnAlloc. This is safe even if OnAlloc wasn't called. // Cleanup state from last OnAlloc. This is safe even if OnAlloc wasn't called.
_currentWritableBuffer = null;
_bufferHandle.Dispose(); _bufferHandle.Dispose();
} }

View File

@ -19,7 +19,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 MemoryPool => ListenerContext.Thread.MemoryPool;
public override Scheduler InputWriterScheduler => ListenerContext.Thread; public override PipeScheduler InputWriterScheduler => ListenerContext.Thread;
public override Scheduler OutputReaderScheduler => ListenerContext.Thread; public override PipeScheduler OutputReaderScheduler => ListenerContext.Thread;
} }
} }

View File

@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
private readonly UvStreamHandle _socket; private readonly UvStreamHandle _socket;
private readonly string _connectionId; private readonly string _connectionId;
private readonly ILibuvTrace _log; private readonly ILibuvTrace _log;
private readonly IPipeReader _pipe; private readonly PipeReader _pipe;
public LibuvOutputConsumer( public LibuvOutputConsumer(
IPipeReader pipe, PipeReader pipe,
LibuvThread thread, LibuvThread thread,
UvStreamHandle socket, UvStreamHandle socket,
string connectionId, string connectionId,
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
} }
finally finally
{ {
_pipe.Advance(consumed); _pipe.AdvanceTo(consumed);
} }
} }
} }

View File

@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
{ {
public class LibuvThread : Scheduler public class LibuvThread : PipeScheduler
{ {
// maximum times the work queues swapped and are processed in a single pass // maximum times the work queues swapped and are processed in a single pass
// as completing a task may immediately have write data to put on the network // as completing a task may immediately have write data to put on the network

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
_bufs = handle + requestSize; _bufs = handle + requestSize;
} }
public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlyBuffer buffer) public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlyBuffer<byte> buffer)
{ {
Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable); Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable);
return _awaitable; return _awaitable;
@ -63,14 +63,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
private unsafe void Write( private unsafe void Write(
UvStreamHandle handle, UvStreamHandle handle,
ReadOnlyBuffer buffer, ReadOnlyBuffer<byte> buffer,
Action<UvWriteReq, int, UvException, object> callback, Action<UvWriteReq, int, UvException, object> callback,
object state) object state)
{ {
try try
{ {
var nBuffers = 0; var nBuffers = 0;
if (buffer.IsSingleSpan) if (buffer.IsSingleSegment)
{ {
nBuffers = 1; nBuffers = 1;
} }

View File

@ -52,8 +52,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
} }
public override MemoryPool MemoryPool { get; } public override MemoryPool MemoryPool { get; }
public override Scheduler InputWriterScheduler => Scheduler.Inline; public override PipeScheduler InputWriterScheduler => PipeScheduler.Inline;
public override Scheduler OutputReaderScheduler => Scheduler.TaskRun; public override PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool;
public async Task StartAsync(IConnectionHandler connectionHandler) public async Task StartAsync(IConnectionHandler connectionHandler)
{ {
@ -96,11 +96,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
while (true) while (true)
{ {
// Ensure we have some reasonable amount of buffer space // Ensure we have some reasonable amount of buffer space
var buffer = Input.Alloc(MinAllocBufferSize); var buffer = Input.GetMemory(MinAllocBufferSize);
try try
{ {
var bytesReceived = await _receiver.ReceiveAsync(buffer.Buffer); var bytesReceived = await _receiver.ReceiveAsync(buffer);
if (bytesReceived == 0) if (bytesReceived == 0)
{ {
@ -109,14 +109,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
break; break;
} }
buffer.Advance(bytesReceived); Input.Advance(bytesReceived);
} }
finally finally
{ {
buffer.Commit(); Input.Commit();
} }
var flushTask = buffer.FlushAsync(); var flushTask = Input.FlushAsync();
if (!flushTask.IsCompleted) if (!flushTask.IsCompleted)
{ {
@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
} }
finally finally
{ {
Output.Advance(buffer.End); Output.AdvanceTo(buffer.End);
} }
} }
} }

View File

@ -26,9 +26,9 @@ 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 buffers) public SocketAwaitable SendAsync(ReadOnlyBuffer<byte> buffers)
{ {
if (buffers.IsSingleSpan) if (buffers.IsSingleSegment)
{ {
return SendAsync(buffers.First); return SendAsync(buffers.First);
} }
@ -75,10 +75,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
return _awaitable; return _awaitable;
} }
private List<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer buffer) private List<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer<byte> buffer)
{ {
Debug.Assert(!buffer.IsEmpty); Debug.Assert(!buffer.IsEmpty);
Debug.Assert(!buffer.IsSingleSpan); Debug.Assert(!buffer.IsSingleSegment);
if (_bufferList == null) if (_bufferList == null)
{ {

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Protocols
public abstract IFeatureCollection Features { get; } public abstract IFeatureCollection Features { get; }
public abstract IPipeConnection Transport { get; set; } public abstract IDuplexPipe Transport { get; set; }
public abstract MemoryPool MemoryPool { get; } public abstract MemoryPool MemoryPool { get; }
} }

View File

@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Protocols
public override MemoryPool MemoryPool => ConnectionTransportFeature.MemoryPool; public override MemoryPool MemoryPool => ConnectionTransportFeature.MemoryPool;
public override IPipeConnection Transport public override IDuplexPipe Transport
{ {
get => ConnectionTransportFeature.Transport; get => ConnectionTransportFeature.Transport;
set => ConnectionTransportFeature.Transport = value; set => ConnectionTransportFeature.Transport = value;

View File

@ -8,12 +8,12 @@ namespace Microsoft.AspNetCore.Protocols.Features
{ {
MemoryPool MemoryPool { get; } MemoryPool MemoryPool { get; }
IPipeConnection Transport { get; set; } IDuplexPipe Transport { get; set; }
IPipeConnection Application { get; set; } IDuplexPipe Application { get; set; }
Scheduler InputWriterScheduler { get; } PipeScheduler InputWriterScheduler { get; }
Scheduler OutputReaderScheduler { get; } PipeScheduler OutputReaderScheduler { get; }
} }
} }

View File

@ -4,17 +4,17 @@ using System.Text;
namespace System.IO.Pipelines namespace System.IO.Pipelines
{ {
public class PipeConnection : IPipeConnection public class PipeConnection : IDuplexPipe
{ {
public PipeConnection(IPipeReader reader, IPipeWriter writer) public PipeConnection(PipeReader reader, PipeWriter writer)
{ {
Input = reader; Input = reader;
Output = writer; Output = writer;
} }
public IPipeReader Input { get; } public PipeReader Input { get; }
public IPipeWriter Output { get; } public PipeWriter Output { get; }
public void Dispose() public void Dispose()
{ {

View File

@ -4,12 +4,12 @@ namespace System.IO.Pipelines
{ {
public static class PipeFactory public static class PipeFactory
{ {
public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(MemoryPool memoryPool) public static (IDuplexPipe Transport, IDuplexPipe Application) CreateConnectionPair(MemoryPool memoryPool)
{ {
return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool)); return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool));
} }
public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions) public static (IDuplexPipe Transport, IDuplexPipe Application) CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions)
{ {
var input = new Pipe(inputOptions); var input = new Pipe(inputOptions);
var output = new Pipe(outputOptions); var output = new Pipe(outputOptions);

View File

@ -1,9 +1,7 @@
using System; using System.Buffers;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
@ -55,12 +53,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public MemoryPool MemoryPool { get; } = new MemoryPool(); public MemoryPool MemoryPool { get; } = new MemoryPool();
public IPipeConnection Transport { get; set; } public IDuplexPipe Transport { get; set; }
public IPipeConnection Application { get; set; } public IDuplexPipe Application { get; set; }
public Scheduler InputWriterScheduler => Scheduler.TaskRun; public PipeScheduler InputWriterScheduler => PipeScheduler.ThreadPool;
public Scheduler OutputReaderScheduler => Scheduler.TaskRun; public PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool;
public string ConnectionId { get; set; } public string ConnectionId { get; set; }
} }

View File

@ -28,14 +28,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
public class Http1ConnectionTests : IDisposable public class Http1ConnectionTests : IDisposable
{ {
private readonly IPipeConnection _transport; private readonly IDuplexPipe _transport;
private readonly IPipeConnection _application; private readonly IDuplexPipe _application;
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 _pipelineFactory;
private Position _consumed; private SequencePosition _consumed;
private Position _examined; private SequencePosition _examined;
private Mock<ITimeoutControl> _timeoutControl; private Mock<ITimeoutControl> _timeoutControl;
public Http1ConnectionTests() public Http1ConnectionTests()
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined)); var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, exception.Message); Assert.Equal(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, exception.Message);
Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode); Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode);
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined)); var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.BadRequest_TooManyHeaders, exception.Message); Assert.Equal(CoreStrings.BadRequest_TooManyHeaders, exception.Message);
Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode); Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode);
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
var takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined); var takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined);
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.True(takeMessageHeaders); Assert.True(takeMessageHeaders);
Assert.Equal(1, _http1Connection.RequestHeaders.Count); Assert.Equal(1, _http1Connection.RequestHeaders.Count);
@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
readableBuffer = (await _transport.Input.ReadAsync()).Buffer; readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined); takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined);
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.True(takeMessageHeaders); Assert.True(takeMessageHeaders);
Assert.Equal(1, _http1Connection.RequestHeaders.Count); Assert.Equal(1, _http1Connection.RequestHeaders.Count);
@ -342,7 +342,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined); var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined);
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.True(returnValue); Assert.True(returnValue);
Assert.Equal(expectedMethod, _http1Connection.Method); Assert.Equal(expectedMethod, _http1Connection.Method);
@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined); var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined);
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.True(returnValue); Assert.True(returnValue);
Assert.Equal(expectedRawTarget, _http1Connection.RawTarget); Assert.Equal(expectedRawTarget, _http1Connection.RawTarget);
@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("G")); await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("G"));
_http1Connection.ParseRequest((await _transport.Input.ReadAsync()).Buffer, out _consumed, out _examined); _http1Connection.ParseRequest((await _transport.Input.ReadAsync()).Buffer, out _consumed, out _examined);
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
var expectedRequestHeadersTimeout = _serviceContext.ServerOptions.Limits.RequestHeadersTimeout.Ticks; var expectedRequestHeadersTimeout = _serviceContext.ServerOptions.Limits.RequestHeadersTimeout.Ticks;
_timeoutControl.Verify(cc => cc.ResetTimeout(expectedRequestHeadersTimeout, TimeoutAction.SendTimeoutResponse)); _timeoutControl.Verify(cc => cc.ResetTimeout(expectedRequestHeadersTimeout, TimeoutAction.SendTimeoutResponse));
@ -395,7 +395,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.BadRequest_RequestLineTooLong, exception.Message); Assert.Equal(CoreStrings.BadRequest_RequestLineTooLong, exception.Message);
Assert.Equal(StatusCodes.Status414UriTooLong, exception.StatusCode); Assert.Equal(StatusCodes.Status414UriTooLong, exception.StatusCode);
@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target), exception.Message); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target), exception.Message);
} }
@ -424,7 +424,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
} }
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(requestLine.EscapeNonPrintable()), exception.Message); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(requestLine.EscapeNonPrintable()), exception.Message);
} }
@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
} }
@ -472,7 +472,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
} }
@ -486,7 +486,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(405, exception.StatusCode); Assert.Equal(405, exception.StatusCode);
Assert.Equal(CoreStrings.BadRequest_MethodNotAllowed, exception.Message); Assert.Equal(CoreStrings.BadRequest_MethodNotAllowed, exception.Message);
@ -685,7 +685,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined); _transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(string.Empty), exception.Message); Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(string.Empty), exception.Message);
Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
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 _memoryPool = new MemoryPool();
private readonly (IPipeConnection Transport, IPipeConnection Application) _pair; private readonly (IDuplexPipe Transport, IDuplexPipe Application) _pair;
private readonly TestApplicationErrorLogger _logger; private readonly TestApplicationErrorLogger _logger;
private readonly Http2ConnectionContext _connectionContext; private readonly Http2ConnectionContext _connectionContext;
private readonly Http2Connection _connection; private readonly Http2Connection _connection;
@ -2138,7 +2138,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private async Task SendAsync(ArraySegment<byte> span) private async Task SendAsync(ArraySegment<byte> span)
{ {
var writableBuffer = _pair.Application.Output.Alloc(1); var writableBuffer = _pair.Application.Output;
writableBuffer.Write(span); writableBuffer.Write(span);
await writableBuffer.FlushAsync(); await writableBuffer.FlushAsync();
} }
@ -2466,7 +2466,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
finally finally
{ {
_pair.Application.Input.Advance(consumed, examined); _pair.Application.Input.AdvanceTo(consumed, examined);
} }
} }
} }

View File

@ -35,7 +35,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(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlyBuffer<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));
@ -45,8 +45,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(requestHandler.RawTarget, expectedRawTarget); Assert.Equal(requestHandler.RawTarget, expectedRawTarget);
Assert.Equal(requestHandler.RawPath, expectedRawPath); Assert.Equal(requestHandler.RawPath, expectedRawPath);
Assert.Equal(requestHandler.Version, expectedVersion); Assert.Equal(requestHandler.Version, expectedVersion);
Assert.Equal(buffer.End, consumed); Assert.True(buffer.Slice(consumed).IsEmpty);
Assert.Equal(buffer.End, examined); Assert.True(buffer.Slice(examined).IsEmpty);
} }
[Theory] [Theory]
@ -54,7 +54,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(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlyBuffer<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));
@ -65,13 +65,13 @@ 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(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlyBuffer<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));
Assert.Equal(buffer.Start, consumed); Assert.Equal(buffer.Start, consumed);
Assert.Equal(buffer.End, examined); Assert.True(buffer.Slice(examined).IsEmpty);
} }
[Theory] [Theory]
@ -84,7 +84,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(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -106,7 +106,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(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -128,7 +128,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(Encoding.ASCII.GetBytes(requestLine)); var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlyBuffer<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));
} }
@ -204,12 +204,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
var parser = CreateParser(Mock.Of<IKestrelTrace>()); var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlyBuffer<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);
Assert.Equal(buffer.Start, consumed); Assert.Equal(buffer.Length, buffer.Slice(consumed).Length);
Assert.Equal(buffer.End, examined); Assert.True(buffer.Slice(examined).IsEmpty);
Assert.Equal(0, consumedBytes); Assert.Equal(0, consumedBytes);
} }
@ -294,19 +294,19 @@ 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(Encoding.ASCII.GetBytes(headerLine)); var buffer1 = new ReadOnlyBuffer<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));
Assert.Equal(buffer1.Move(buffer1.Start, headerLine.Length - 1), consumed); Assert.Equal(buffer1.GetPosition(buffer1.Start, headerLine.Length - 1), consumed);
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(Encoding.ASCII.GetBytes("\r\n")); var buffer2 = new ReadOnlyBuffer<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.Equal(buffer2.End, consumed); Assert.True(buffer2.Slice(consumed).IsEmpty);
Assert.Equal(buffer2.End, examined); Assert.True(buffer2.Slice(examined).IsEmpty);
Assert.Equal(2, consumedBytes); Assert.Equal(2, consumedBytes);
} }
@ -320,7 +320,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(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler(); var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() => var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -341,7 +341,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(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n")); var buffer = new ReadOnlyBuffer<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>(() =>
@ -351,7 +351,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(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n")); buffer = new ReadOnlyBuffer<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));
@ -360,7 +360,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(Encoding.ASCII.GetBytes("Header: value\n\r\n")); buffer = new ReadOnlyBuffer<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));
@ -375,7 +375,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(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); var buffer = new ReadOnlyBuffer<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);
@ -384,8 +384,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Single(pairs); Assert.Single(pairs);
Assert.Equal(headerName, pairs[0].Key); Assert.Equal(headerName, pairs[0].Key);
Assert.Equal(expectedHeaderValue, pairs[0].Value); Assert.Equal(expectedHeaderValue, pairs[0].Value);
Assert.Equal(buffer.End, consumed); Assert.True(buffer.Slice(consumed).IsEmpty);
Assert.Equal(buffer.End, examined); Assert.True(buffer.Slice(examined).IsEmpty);
} }
private void VerifyRawHeaders(string rawHeaders, IEnumerable<string> expectedHeaderNames, IEnumerable<string> expectedHeaderValues) private void VerifyRawHeaders(string rawHeaders, IEnumerable<string> expectedHeaderNames, IEnumerable<string> expectedHeaderValues)
@ -393,7 +393,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(Encoding.ASCII.GetBytes(rawHeaders)); var buffer = new ReadOnlyBuffer<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);
@ -403,8 +403,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length); Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length);
Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key)); Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key));
Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value)); Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value));
Assert.Equal(buffer.End, consumed); Assert.True(buffer.Slice(consumed).IsEmpty);
Assert.Equal(buffer.End, examined); Assert.True(buffer.Slice(examined).IsEmpty);
} }
private IHttpParser<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log.IsEnabled(LogLevel.Information)); private IHttpParser<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log.IsEnabled(LogLevel.Information));

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -445,23 +446,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
// The block returned by IncomingStart always has at least 2048 available bytes, // The block returned by IncomingStart always has at least 2048 available bytes,
// so no need to bounds check in this test. // so no need to bounds check in this test.
var bytes = Encoding.ASCII.GetBytes(data[0]); var bytes = Encoding.ASCII.GetBytes(data[0]);
var buffer = input.Application.Output.Alloc(2048); var buffer = input.Application.Output.GetMemory(2028);
ArraySegment<byte> block; ArraySegment<byte> block;
Assert.True(buffer.Buffer.TryGetArray(out block)); Assert.True(MemoryMarshal.TryGetArray(buffer, out block));
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length); Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
buffer.Advance(bytes.Length); input.Application.Output.Advance(bytes.Length);
await buffer.FlushAsync(); await input.Application.Output.FlushAsync();
// Verify the block passed to WriteAsync is the same one incoming data was written into. // Verify the block passed to WriteAsync is the same one incoming data was written into.
Assert.Same(block.Array, await writeTcs.Task); Assert.Same(block.Array, await writeTcs.Task);
writeTcs = new TaskCompletionSource<byte[]>(); writeTcs = new TaskCompletionSource<byte[]>();
bytes = Encoding.ASCII.GetBytes(data[1]); bytes = Encoding.ASCII.GetBytes(data[1]);
buffer = input.Application.Output.Alloc(2048); buffer = input.Application.Output.GetMemory(2048);
Assert.True(buffer.Buffer.TryGetArray(out block)); Assert.True(MemoryMarshal.TryGetArray(buffer, out block));
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length); Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
buffer.Advance(bytes.Length); input.Application.Output.Advance(bytes.Length);
await buffer.FlushAsync(); await input.Application.Output.FlushAsync();
Assert.Same(block.Array, await writeTcs.Task); Assert.Same(block.Array, await writeTcs.Task);

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var pipeOptions = new PipeOptions var pipeOptions = new PipeOptions
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: Mock.Of<Scheduler>() readerScheduler: Mock.Of<PipeScheduler>()
); );
using (var socketOutput = CreateOutputProducer(pipeOptions)) using (var socketOutput = CreateOutputProducer(pipeOptions))

View File

@ -26,11 +26,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
serviceContext.ServerOptions.Limits.MaxResponseBufferSize = maxResponseBufferSize; serviceContext.ServerOptions.Limits.MaxResponseBufferSize = maxResponseBufferSize;
serviceContext.ThreadPool = new LoggingThreadPool(null); serviceContext.ThreadPool = new LoggingThreadPool(null);
var mockScheduler = Mock.Of<Scheduler>(); var mockScheduler = Mock.Of<PipeScheduler>();
var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler); var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler);
Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.ResumeWriterThreshold);
Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.MaximumSizeHigh); Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.PauseWriterThreshold);
Assert.Same(mockScheduler, outputPipeOptions.ReaderScheduler); Assert.Same(mockScheduler, outputPipeOptions.ReaderScheduler);
Assert.Same(serviceContext.ThreadPool, outputPipeOptions.WriterScheduler); Assert.Same(serviceContext.ThreadPool, outputPipeOptions.WriterScheduler);
} }
@ -44,11 +44,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize; serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize;
serviceContext.ThreadPool = new LoggingThreadPool(null); serviceContext.ThreadPool = new LoggingThreadPool(null);
var mockScheduler = Mock.Of<Scheduler>(); var mockScheduler = Mock.Of<PipeScheduler>();
var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler); var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler);
Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.ResumeWriterThreshold);
Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.MaximumSizeHigh); Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.PauseWriterThreshold);
Assert.Same(serviceContext.ThreadPool, inputPipeOptions.ReaderScheduler); Assert.Same(serviceContext.ThreadPool, inputPipeOptions.ReaderScheduler);
Assert.Same(mockScheduler, inputPipeOptions.WriterScheduler); Assert.Same(mockScheduler, inputPipeOptions.WriterScheduler);
} }
@ -66,10 +66,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
ServiceContext = serviceContext ServiceContext = serviceContext
}); });
Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.ResumeWriterThreshold);
Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeHigh); Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.PauseWriterThreshold);
Assert.Same(serviceContext.ThreadPool, connectionLifetime.AdaptedInputPipeOptions.ReaderScheduler); Assert.Same(serviceContext.ThreadPool, connectionLifetime.AdaptedInputPipeOptions.ReaderScheduler);
Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler); Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler);
} }
[Theory] [Theory]
@ -85,10 +85,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
ServiceContext = serviceContext ServiceContext = serviceContext
}); });
Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.ResumeWriterThreshold);
Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeHigh); Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.PauseWriterThreshold);
Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler); Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler);
Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler); Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler);
} }
} }
} }

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
// ulong.MaxValue.ToString().Length // ulong.MaxValue.ToString().Length
private const int _ulongMaxValueLength = 20; private const int _ulongMaxValueLength = 20;
private readonly IPipe _pipe; private readonly Pipe _pipe;
private readonly MemoryPool _memoryPool = new MemoryPool(); private readonly MemoryPool _memoryPool = new MemoryPool();
public PipelineExtensionTests() public PipelineExtensionTests()
@ -34,8 +34,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[InlineData(4_8_15_16_23_42)] [InlineData(4_8_15_16_23_42)]
public void WritesNumericToAscii(ulong number) public void WritesNumericToAscii(ulong number)
{ {
var writerBuffer = _pipe.Writer.Alloc(); var writerBuffer = _pipe.Writer;
var writer = new WritableBufferWriter(writerBuffer); var writer = OutputWriter.Create(writerBuffer);
writer.WriteNumeric(number); writer.WriteNumeric(number);
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
@ -51,8 +51,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[InlineData(_ulongMaxValueLength - 1)] [InlineData(_ulongMaxValueLength - 1)]
public void WritesNumericAcrossSpanBoundaries(int gapSize) public void WritesNumericAcrossSpanBoundaries(int gapSize)
{ {
var writerBuffer = _pipe.Writer.Alloc(100); var writerBuffer = _pipe.Writer;
var writer = new WritableBufferWriter(writerBuffer); var writer = OutputWriter.Create(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);
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
var numAsString = ulong.MaxValue.ToString(); var numAsString = ulong.MaxValue.ToString();
var written = reader.Buffer.Slice(spacer.Length, numAsString.Length); var written = reader.Buffer.Slice(spacer.Length, numAsString.Length);
Assert.False(written.IsSingleSpan, "The buffer should cross spans"); Assert.False(written.IsSingleSegment, "The buffer should cross spans");
AssertExtensions.Equal(Encoding.ASCII.GetBytes(numAsString), written.ToArray()); AssertExtensions.Equal(Encoding.ASCII.GetBytes(numAsString), written.ToArray());
} }
@ -82,8 +82,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[InlineData(null, new byte[0])] [InlineData(null, new byte[0])]
public void EncodesAsAscii(string input, byte[] expected) public void EncodesAsAscii(string input, byte[] expected)
{ {
var writerBuffer = _pipe.Writer.Alloc(); var writerBuffer = _pipe.Writer;
var writer = new WritableBufferWriter(writerBuffer); var writer = OutputWriter.Create(writerBuffer);
writer.WriteAsciiNoValidation(input); writer.WriteAsciiNoValidation(input);
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -109,8 +109,8 @@ 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.Alloc(); var writerBuffer = _pipe.Writer;
var writer = new WritableBufferWriter(writerBuffer); var writer = OutputWriter.Create(writerBuffer);
writer.WriteAsciiNoValidation(input); writer.WriteAsciiNoValidation(input);
writerBuffer.FlushAsync().GetAwaiter().GetResult(); writerBuffer.FlushAsync().GetAwaiter().GetResult();
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
@ -122,8 +122,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void WriteAsciiNoValidation() public void WriteAsciiNoValidation()
{ {
const byte maxAscii = 0x7f; const byte maxAscii = 0x7f;
var writerBuffer = _pipe.Writer.Alloc(); var writerBuffer = _pipe.Writer;
var writer = new WritableBufferWriter(writerBuffer); var writer = OutputWriter.Create(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));
@ -151,8 +151,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void WritesAsciiAcrossBlockBoundaries(int stringLength, int gapSize) public void WritesAsciiAcrossBlockBoundaries(int stringLength, int gapSize)
{ {
var testString = new string(' ', stringLength); var testString = new string(' ', stringLength);
var writerBuffer = _pipe.Writer.Alloc(100); var writerBuffer = _pipe.Writer;
var writer = new WritableBufferWriter(writerBuffer); var writer = OutputWriter.Create(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);
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
var written = reader.Buffer.Slice(spacer.Length, stringLength); var written = reader.Buffer.Slice(spacer.Length, stringLength);
Assert.False(written.IsSingleSpan, "The buffer should cross spans"); Assert.False(written.IsSingleSegment, "The buffer should cross spans");
AssertExtensions.Equal(Encoding.ASCII.GetBytes(testString), written.ToArray()); AssertExtensions.Equal(Encoding.ASCII.GetBytes(testString), written.ToArray());
} }
} }

View File

@ -38,9 +38,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Http1Connection.HttpResponseControl = Mock.Of<IHttpResponseControl>(); Http1Connection.HttpResponseControl = Mock.Of<IHttpResponseControl>();
} }
public IPipeConnection Transport { get; } public IDuplexPipe Transport { get; }
public IPipeConnection Application { get; } public IDuplexPipe Application { get; }
public Http1ConnectionContext Http1ConnectionContext { get; } public Http1ConnectionContext Http1ConnectionContext { get; }

View File

@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
mockConnectionHandler.InputOptions = pool => mockConnectionHandler.InputOptions = pool =>
new PipeOptions( new PipeOptions(
pool: pool, pool: pool,
maximumSizeHigh: 3); pauseWriterThreshold: 3);
// We don't set the output writer scheduler here since we want to run the callback inline // We don't set the output writer scheduler here since we want to run the callback inline
@ -117,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler }; var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler };
var transport = new LibuvTransport(mockLibuv, transportContext, null); var transport = new LibuvTransport(mockLibuv, transportContext, null);
var thread = new LibuvThread(transport); var thread = new LibuvThread(transport);
var mockScheduler = new Mock<Scheduler>(); var mockScheduler = new Mock<PipeScheduler>();
Action backPressure = null; Action backPressure = null;
mockScheduler.Setup(m => m.Schedule(It.IsAny<Action>())).Callback<Action>(a => mockScheduler.Setup(m => m.Schedule(It.IsAny<Action>())).Callback<Action>(a =>
{ {
@ -126,8 +126,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
mockConnectionHandler.InputOptions = pool => mockConnectionHandler.InputOptions = pool =>
new PipeOptions( new PipeOptions(
pool: pool, pool: pool,
maximumSizeHigh: 3, pauseWriterThreshold: 3,
maximumSizeLow: 3, resumeWriterThreshold: 3,
writerScheduler: mockScheduler.Object); writerScheduler: mockScheduler.Object);
mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler:thread ); mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler:thread );
@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
var result = await mockConnectionHandler.Input.Reader.ReadAsync(); var result = await mockConnectionHandler.Input.Reader.ReadAsync();
// Calling advance will call into our custom scheduler that captures the back pressure // Calling advance will call into our custom scheduler that captures the back pressure
// callback // callback
mockConnectionHandler.Input.Reader.Advance(result.Buffer.End); mockConnectionHandler.Input.Reader.AdvanceTo(result.Buffer.End);
// Cancel the current pending flush // Cancel the current pending flush
mockConnectionHandler.Input.Writer.CancelPendingFlush(); mockConnectionHandler.Input.Writer.CancelPendingFlush();

View File

@ -60,14 +60,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
// SocketOutput, the write callback would never be invoked for writes larger than // SocketOutput, the write callback would never be invoked for writes larger than
// maxResponseBufferSize even after the write actually completed. // maxResponseBufferSize even after the write actually completed.
// ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null. // ConnectionHandler will set Pause/ResumeWriterThreshold to zero when MaxResponseBufferSize is null.
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
var pipeOptions = new PipeOptions var pipeOptions = new PipeOptions
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize ?? 0, pauseWriterThreshold: maxResponseBufferSize ?? 0,
maximumSizeLow: maxResponseBufferSize ?? 0 resumeWriterThreshold: maxResponseBufferSize ?? 0
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -96,14 +96,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
return 0; return 0;
}; };
// ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null. // ConnectionHandler will set Pause/ResumeWriterThreshold to zero when MaxResponseBufferSize is null.
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
var pipeOptions = new PipeOptions var pipeOptions = new PipeOptions
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: 0, pauseWriterThreshold: 0,
maximumSizeLow: 0 resumeWriterThreshold: 0
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -144,14 +144,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
return 0; return 0;
}; };
// ConnectionHandler will set MaximumSizeHigh/Low to 1 when MaxResponseBufferSize is zero. // ConnectionHandler will set Pause/ResumeWriterThreshold to 1 when MaxResponseBufferSize is zero.
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
var pipeOptions = new PipeOptions var pipeOptions = new PipeOptions
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: 1, pauseWriterThreshold: 1,
maximumSizeLow: 1 resumeWriterThreshold: 1
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -206,8 +206,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
maximumSizeLow: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -270,8 +270,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
maximumSizeLow: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -340,8 +340,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
maximumSizeLow: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );
using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource)) using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource))
@ -433,8 +433,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
maximumSizeLow: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -517,8 +517,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
maximumSizeLow: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -599,8 +599,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize, pauseWriterThreshold: maxResponseBufferSize,
maximumSizeLow: maxResponseBufferSize resumeWriterThreshold: maxResponseBufferSize
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -654,14 +654,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
return 0; return 0;
}; };
// ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null. // ConnectionHandler will set Pause/ResumeWriterThreshold to zero when MaxResponseBufferSize is null.
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
var pipeOptions = new PipeOptions var pipeOptions = new PipeOptions
( (
pool: _memoryPool, pool: _memoryPool,
readerScheduler: _libuvThread, readerScheduler: _libuvThread,
maximumSizeHigh: maxResponseBufferSize ?? 0, pauseWriterThreshold: maxResponseBufferSize ?? 0,
maximumSizeLow: maxResponseBufferSize ?? 0 resumeWriterThreshold: maxResponseBufferSize ?? 0
); );
using (var outputProducer = CreateOutputProducer(pipeOptions)) using (var outputProducer = CreateOutputProducer(pipeOptions))
@ -728,7 +728,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
return (Http1OutputProducer)http1Connection.Output; return (Http1OutputProducer)http1Connection.Output;
} }
private async Task WriteOutputAsync(LibuvOutputConsumer consumer, IPipeReader outputReader, Http1Connection http1Connection) private async Task WriteOutputAsync(LibuvOutputConsumer consumer, PipeReader outputReader, Http1Connection http1Connection)
{ {
// This WriteOutputAsync() calling code is equivalent to that in LibuvConnection. // This WriteOutputAsync() calling code is equivalent to that in LibuvConnection.
try try

View File

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

View File

@ -162,7 +162,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(new byte[] { 65, 66, 67, 68, 69 }); var block = new ReadOnlyBuffer<byte>(new byte[] { 65, 66, 67, 68, 69 });
await req.WriteAsync( await req.WriteAsync(
tcp2, tcp2,

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
feature.Application = new PipeConnection(Output.Reader, Input.Writer); feature.Application = new PipeConnection(Output.Reader, Input.Writer);
} }
public IPipe Input { get; private set; } public Pipe Input { get; private set; }
public IPipe Output { get; private set; } public Pipe Output { get; private set; }
} }
} }

View File

@ -7,9 +7,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Kestrel.Core\Kestrel.Core.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />

View File

@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features; //using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
namespace CodeGenerator namespace CodeGenerator
{ {
@ -23,39 +23,39 @@ namespace CodeGenerator
{ {
var alwaysFeatures = new[] var alwaysFeatures = new[]
{ {
typeof(IHttpRequestFeature), "IHttpRequestFeature",
typeof(IHttpResponseFeature), "IHttpResponseFeature",
typeof(IHttpRequestIdentifierFeature), "IHttpRequestIdentifierFeature",
typeof(IServiceProvidersFeature), "IServiceProvidersFeature",
typeof(IHttpRequestLifetimeFeature), "IHttpRequestLifetimeFeature",
typeof(IHttpConnectionFeature), "IHttpConnectionFeature",
}; };
var commonFeatures = new[] var commonFeatures = new[]
{ {
typeof(IHttpAuthenticationFeature), "IHttpAuthenticationFeature",
typeof(IQueryFeature), "IQueryFeature",
typeof(IFormFeature), "IFormFeature",
}; };
var sometimesFeatures = new[] var sometimesFeatures = new[]
{ {
typeof(IHttpUpgradeFeature), "IHttpUpgradeFeature",
typeof(IHttp2StreamIdFeature), "IHttp2StreamIdFeature",
typeof(IResponseCookiesFeature), "IResponseCookiesFeature",
typeof(IItemsFeature), "IItemsFeature",
typeof(ITlsConnectionFeature), "ITlsConnectionFeature",
typeof(IHttpWebSocketFeature), "IHttpWebSocketFeature",
typeof(ISessionFeature), "ISessionFeature",
typeof(IHttpMaxRequestBodySizeFeature), "IHttpMaxRequestBodySizeFeature",
typeof(IHttpMinRequestBodyDataRateFeature), "IHttpMinRequestBodyDataRateFeature",
typeof(IHttpMinResponseDataRateFeature), "IHttpMinResponseDataRateFeature",
typeof(IHttpBodyControlFeature), "IHttpBodyControlFeature",
}; };
var rareFeatures = new[] var rareFeatures = new[]
{ {
typeof(IHttpSendFileFeature), "IHttpSendFileFeature",
}; };
var allFeatures = alwaysFeatures.Concat(commonFeatures).Concat(sometimesFeatures).Concat(rareFeatures); var allFeatures = alwaysFeatures.Concat(commonFeatures).Concat(sometimesFeatures).Concat(rareFeatures);
@ -64,15 +64,15 @@ namespace CodeGenerator
// See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs // See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs
var implementedFeatures = new[] var implementedFeatures = new[]
{ {
typeof(IHttpRequestFeature), "IHttpRequestFeature",
typeof(IHttpResponseFeature), "IHttpResponseFeature",
typeof(IHttpRequestIdentifierFeature), "IHttpRequestIdentifierFeature",
typeof(IHttpRequestLifetimeFeature), "IHttpRequestLifetimeFeature",
typeof(IHttpConnectionFeature), "IHttpConnectionFeature",
typeof(IHttpMaxRequestBodySizeFeature), "IHttpMaxRequestBodySizeFeature",
typeof(IHttpMinRequestBodyDataRateFeature), "IHttpMinRequestBodyDataRateFeature",
typeof(IHttpMinResponseDataRateFeature), "IHttpMinResponseDataRateFeature",
typeof(IHttpBodyControlFeature), "IHttpBodyControlFeature",
}; };
return $@"// Copyright (c) .NET Foundation. All rights reserved. return $@"// Copyright (c) .NET Foundation. All rights reserved.
@ -81,26 +81,30 @@ namespace CodeGenerator
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{{ {{
public partial class {className} public partial class {className}
{{{Each(allFeatures, feature => $@" {{{Each(allFeatures, feature => $@"
private static readonly Type {feature.Name}Type = typeof(global::{feature.FullName});")} private static readonly Type {feature}Type = typeof({feature});")}
{Each(allFeatures, feature => $@" {Each(allFeatures, feature => $@"
private object _current{feature.Name};")} private object _current{feature};")}
private void FastReset() private void FastReset()
{{{Each(implementedFeatures, feature => $@" {{{Each(implementedFeatures, feature => $@"
_current{feature.Name} = this;")} _current{feature} = this;")}
{Each(allFeatures.Where(f => !implementedFeatures.Contains(f)), feature => $@" {Each(allFeatures.Where(f => !implementedFeatures.Contains(f)), feature => $@"
_current{feature.Name} = null;")} _current{feature} = null;")}
}} }}
internal object FastFeatureGet(Type key) internal object FastFeatureGet(Type key)
{{{Each(allFeatures, feature => $@" {{{Each(allFeatures, feature => $@"
if (key == {feature.Name}Type) if (key == {feature}Type)
{{ {{
return _current{feature.Name}; return _current{feature};
}}")} }}")}
return ExtraFeatureGet(key); return ExtraFeatureGet(key);
}} }}
@ -109,9 +113,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{{ {{
_featureRevision++; _featureRevision++;
{Each(allFeatures, feature => $@" {Each(allFeatures, feature => $@"
if (key == {feature.Name}Type) if (key == {feature}Type)
{{ {{
_current{feature.Name} = feature; _current{feature} = feature;
return; return;
}}")}; }}")};
ExtraFeatureSet(key, feature); ExtraFeatureSet(key, feature);
@ -119,9 +123,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable() private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{{{Each(allFeatures, feature => $@" {{{Each(allFeatures, feature => $@"
if (_current{feature.Name} != null) if (_current{feature} != null)
{{ {{
yield return new KeyValuePair<Type, object>({feature.Name}Type, _current{feature.Name} as global::{feature.FullName}); yield return new KeyValuePair<Type, object>({feature}Type, _current{feature} as {feature});
}}")} }}")}
if (MaybeExtra != null) if (MaybeExtra != null)

View File

@ -7,7 +7,6 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
namespace CodeGenerator.HttpUtilities namespace CodeGenerator.HttpUtilities
{ {
@ -17,27 +16,27 @@ namespace CodeGenerator.HttpUtilities
{ {
var httpMethods = new [] var httpMethods = new []
{ {
new Tuple<string, HttpMethod>("CONNECT ", HttpMethod.Connect), new Tuple<string, String>("CONNECT ", "Connect"),
new Tuple<string, HttpMethod>("DELETE ", HttpMethod.Delete), new Tuple<string, String>("DELETE ", "Delete"),
new Tuple<string, HttpMethod>("HEAD ", HttpMethod.Head), new Tuple<string, String>("HEAD ", "Head"),
new Tuple<string, HttpMethod>("PATCH ", HttpMethod.Patch), new Tuple<string, String>("PATCH ", "Patch"),
new Tuple<string, HttpMethod>("POST ", HttpMethod.Post), new Tuple<string, String>("POST ", "Post"),
new Tuple<string, HttpMethod>("PUT ", HttpMethod.Put), new Tuple<string, String>("PUT ", "Put"),
new Tuple<string, HttpMethod>("OPTIONS ", HttpMethod.Options), new Tuple<string, String>("OPTIONS ", "Options"),
new Tuple<string, HttpMethod>("TRACE ", HttpMethod.Trace), new Tuple<string, String>("TRACE ", "Trace"),
new Tuple<string, HttpMethod>("GET ", HttpMethod.Get) new Tuple<string, String>("GET ", "Get")
}; };
return GenerateFile(httpMethods); return GenerateFile(httpMethods);
} }
private static string GenerateFile(Tuple<string, HttpMethod>[] httpMethods) private static string GenerateFile(Tuple<string, String>[] httpMethods)
{ {
var maskLength = (byte)Math.Ceiling(Math.Log(httpMethods.Length, 2)); var maskLength = (byte)Math.Ceiling(Math.Log(httpMethods.Length, 2));
var methodsInfo = httpMethods.Select(GetMethodStringAndUlongAndMaskLength).ToList(); var methodsInfo = httpMethods.Select(GetMethodStringAndUlongAndMaskLength).ToList();
var methodsInfoWithoutGet = methodsInfo.Where(m => m.HttpMethod != HttpMethod.Get.ToString()).ToList(); var methodsInfoWithoutGet = methodsInfo.Where(m => m.HttpMethod != "Get".ToString()).ToList();
var methodsAsciiStringAsLong = methodsInfo.Select(m => m.AsciiStringAsLong).ToArray(); var methodsAsciiStringAsLong = methodsInfo.Select(m => m.AsciiStringAsLong).ToArray();
@ -158,7 +157,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
var maskFieldName = GetMaskFieldName(methodInfo.MaskLength); var maskFieldName = GetMaskFieldName(methodInfo.MaskLength);
var httpMethodFieldName = GetHttpMethodFieldName(methodInfo); var httpMethodFieldName = GetHttpMethodFieldName(methodInfo);
result.AppendFormat(" SetKnownMethod({0}, {1}, {2}.{3}, {4});", maskFieldName, httpMethodFieldName, typeof(HttpMethod).Name, methodInfo.HttpMethod, methodInfo.MaskLength - 1); result.AppendFormat(" SetKnownMethod({0}, {1}, HttpMethod.{3}, {4});", maskFieldName, httpMethodFieldName, typeof(String).Name, methodInfo.HttpMethod, methodInfo.MaskLength - 1);
if (index < methodsInfo.Count - 1) if (index < methodsInfo.Count - 1)
{ {
@ -181,7 +180,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
{ {
var methodInfo = methodsInfo[index]; var methodInfo = methodsInfo[index];
result.AppendFormat(" _methodNames[(byte){0}.{1}] = {2}.{3};", typeof(HttpMethod).Name, methodInfo.HttpMethod, typeof(HttpMethods).Name, methodInfo.HttpMethod); result.AppendFormat(" _methodNames[(byte)HttpMethod.{1}] = {2}.{3};", typeof(String).Name, methodInfo.HttpMethod, typeof(HttpMethods).Name, methodInfo.HttpMethod);
if (index < methodsInfo.Count - 1) if (index < methodsInfo.Count - 1)
{ {
@ -281,7 +280,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
public int MaskLength; public int MaskLength;
} }
private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple<string, HttpMethod> method) private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple<string, string> method)
{ {
var methodString = GetMethodString(method.Item1); var methodString = GetMethodString(method.Item1);

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
namespace CodeGenerator namespace CodeGenerator
{ {
@ -266,14 +265,14 @@ namespace CodeGenerator
{ {
Headers = requestHeaders, Headers = requestHeaders,
HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length), HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length),
ClassName = nameof(HttpRequestHeaders), ClassName = "HttpRequestHeaders",
Bytes = default(byte[]) Bytes = default(byte[])
}, },
new new
{ {
Headers = responseHeaders, Headers = responseHeaders,
HeadersByLength = responseHeaders.GroupBy(x => x.Name.Length), HeadersByLength = responseHeaders.GroupBy(x => x.Name.Length),
ClassName = nameof(HttpResponseHeaders), ClassName = "HttpResponseHeaders",
Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray() Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray()
} }
}; };
@ -293,6 +292,7 @@ namespace CodeGenerator
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -384,7 +384,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}} }}
protected override void SetValueFast(string key, StringValues value) protected override void SetValueFast(string key, StringValues value)
{{{(loop.ClassName == nameof(HttpResponseHeaders) ? @" {{{(loop.ClassName == "HttpResponseHeaders" ? @"
ValidateHeaderCharacters(value);" : "")} ValidateHeaderCharacters(value);" : "")}
switch (key.Length) switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
@ -406,7 +406,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}} }}
protected override bool AddValueFast(string key, StringValues value) protected override bool AddValueFast(string key, StringValues value)
{{{(loop.ClassName == nameof(HttpResponseHeaders) ? @" {{{(loop.ClassName == "HttpResponseHeaders" ? @"
ValidateHeaderCharacters(value);" : "")} ValidateHeaderCharacters(value);" : "")}
switch (key.Length) switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@" {{{Each(loop.HeadersByLength, byLength => $@"
@ -432,7 +432,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}} }}
break;")} break;")}
}} }}
{(loop.ClassName == nameof(HttpResponseHeaders) ? @" {(loop.ClassName == "HttpResponseHeaders" ? @"
ValidateHeaderCharacters(key);" : "")} ValidateHeaderCharacters(key);" : "")}
Unknown.Add(key, value); Unknown.Add(key, value);
// Return true, above will throw and exit for false // Return true, above will throw and exit for false
@ -522,8 +522,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true; return true;
}} }}
{(loop.ClassName == nameof(HttpResponseHeaders) ? $@" {(loop.ClassName == "HttpResponseHeaders" ? $@"
protected void CopyToFast(ref WritableBufferWriter output) protected void CopyToFast(ref OutputWriter<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 => $@"
@ -541,7 +541,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
var value = _headers._{header.Identifier}[i]; var value = _headers._{header.Identifier}[i];
if (value != null) if (value != null)
{{ {{
output.Write(_headerBytes, {header.BytesOffset}, {header.BytesCount}); output.Write(new ReadOnlySpan<byte>(_headerBytes, {header.BytesOffset}, {header.BytesCount}));
PipelineExtensions.WriteAsciiNoValidation(ref output, value); PipelineExtensions.WriteAsciiNoValidation(ref output, value);
}} }}
}} }}
@ -555,7 +555,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}}{(header.Identifier == "Server" ? $@" }}{(header.Identifier == "Server" ? $@"
if ((tempBits & {1L << 63}L) != 0) if ((tempBits & {1L << 63}L) != 0)
{{ {{
output.Write(_headerBytes, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesOffset}, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesCount}); output.Write(new ReadOnlySpan<byte>(_headerBytes, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesOffset}, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesCount}));
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value); PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
if((tempBits & ~{1L << 63}L) == 0) if((tempBits & ~{1L << 63}L) == 0)
@ -565,7 +565,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
tempBits &= ~{1L << 63}L; tempBits &= ~{1L << 63}L;
}}" : "")}")} }}" : "")}")}
}}" : "")} }}" : "")}
{(loop.ClassName == nameof(HttpRequestHeaders) ? $@" {(loop.ClassName == "HttpRequestHeaders" ? $@"
public unsafe void Append(byte* pKeyBytes, int keyLength, string value) public unsafe void Append(byte* pKeyBytes, int keyLength, string value)
{{ {{
var pUB = pKeyBytes; var pUB = pKeyBytes;

View File

@ -3,8 +3,6 @@
using System; using System;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
namespace CodeGenerator namespace CodeGenerator
{ {
@ -36,7 +34,7 @@ namespace CodeGenerator
public static void Run(string knownHeadersPath, string httpProtocolFeatureCollectionPath, string httpUtilitiesPath) public static void Run(string knownHeadersPath, string httpProtocolFeatureCollectionPath, string httpUtilitiesPath)
{ {
var knownHeadersContent = KnownHeaders.GeneratedFile(); var knownHeadersContent = KnownHeaders.GeneratedFile();
var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile(nameof(HttpProtocol)); var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile("HttpProtocol");
var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile(); var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile();
var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : ""; var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";