From a84095e5c3a61a329bca5819183de608067d0394 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 29 Jan 2018 14:34:48 -0800 Subject: [PATCH] React to pipelines changes (#2275) --- ...Http1ConnectionParsingOverheadBenchmark.cs | 2 +- .../Http1WritingBenchmark.cs | 4 +- .../HttpParserBenchmark.cs | 4 +- .../Kestrel.Performance/Mocks/NullParser.cs | 5 +- .../PipeThroughputBenchmark.cs | 18 ++-- .../RequestParsingBenchmark.cs | 13 ++- build/dependencies.props | 22 ++--- .../Adapter/Internal/AdaptedPipeline.cs | 36 ++++---- .../Adapter/Internal/RawStream.cs | 15 ++-- .../Internal/ConnectionHandler.cs | 12 +-- src/Kestrel.Core/Internal/Http/ChunkWriter.cs | 9 +- .../Internal/Http/Http1Connection.cs | 11 +-- .../Internal/Http/Http1ConnectionContext.cs | 4 +- .../Internal/Http/Http1MessageBody.cs | 53 +++++------ .../Internal/Http/Http1OutputProducer.cs | 31 +++---- .../Internal/Http/HttpHeaders.Generated.cs | 75 ++++++++-------- src/Kestrel.Core/Internal/Http/HttpParser.cs | 49 ++++++----- .../Internal/Http/HttpProtocol.Generated.cs | 88 ++++++++++--------- .../Internal/Http/HttpProtocol.cs | 15 ++-- .../Internal/Http/HttpResponseHeaders.cs | 3 +- .../Internal/Http/IHttpOutputProducer.cs | 2 +- src/Kestrel.Core/Internal/Http/IHttpParser.cs | 5 +- src/Kestrel.Core/Internal/Http/MessageBody.cs | 6 +- .../Internal/Http/PipelineExtensions.cs | 14 +-- .../Internal/Http2/Http2Connection.cs | 13 +-- .../Internal/Http2/Http2ConnectionContext.cs | 4 +- .../Internal/Http2/Http2FrameReader.cs | 5 +- .../Internal/Http2/Http2FrameWriter.cs | 22 ++--- .../Internal/Http2/Http2OutputProducer.cs | 2 +- .../Internal/Http2/Http2Stream.cs | 9 +- src/Kestrel.Core/Internal/HttpConnection.cs | 22 ++--- .../Internal/HttpConnectionContext.cs | 4 +- .../Infrastructure/KestrelThreadPool.cs | 3 +- .../Infrastructure/LoggingThreadPool.cs | 4 +- .../Internal/TransportConnection.Features.cs | 4 +- .../Internal/TransportConnection.cs | 12 +-- .../Internal/LibuvConnection.cs | 22 ++--- .../Internal/LibuvConnectionContext.cs | 4 +- .../Internal/LibuvOutputConsumer.cs | 6 +- .../Internal/LibuvThread.cs | 2 +- .../Internal/Networking/UvWriteReq.cs | 6 +- .../Internal/SocketConnection.cs | 16 ++-- .../Internal/SocketSender.cs | 8 +- .../ConnectionContext.cs | 2 +- .../DefaultConnectionContext.cs | 2 +- .../Features/IConnectionTransportFeature.cs | 8 +- src/Protocols.Abstractions/PipeConnection.cs | 8 +- .../PipeFactoryExtensions.cs | 4 +- .../ConnectionHandlerTests.cs | 12 ++- .../Http1ConnectionTests.cs | 38 ++++---- .../Http2ConnectionTests.cs | 6 +- test/Kestrel.Core.Tests/HttpParserTests.cs | 56 ++++++------ test/Kestrel.Core.Tests/MessageBodyTests.cs | 17 ++-- .../Kestrel.Core.Tests/OutputProducerTests.cs | 2 +- test/Kestrel.Core.Tests/PipeOptionsTests.cs | 26 +++--- .../PipelineExtensionTests.cs | 30 +++---- test/Kestrel.Core.Tests/TestInput.cs | 4 +- .../LibuvConnectionTests.cs | 10 +-- .../LibuvOutputConsumerTests.cs | 50 +++++------ .../MultipleLoopTests.cs | 2 +- .../NetworkingTests.cs | 2 +- .../TestHelpers/MockConnectionHandler.cs | 4 +- tools/CodeGenerator/CodeGenerator.csproj | 3 - .../HttpProtocolFeatureCollection.cs | 86 +++++++++--------- .../HttpUtilities/HttpUtilities.cs | 29 +++--- tools/CodeGenerator/KnownHeaders.cs | 22 ++--- tools/CodeGenerator/Program.cs | 4 +- 67 files changed, 550 insertions(+), 541 deletions(-) diff --git a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs index f3ef888b9a..b4979f4a3b 100644 --- a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs +++ b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { private const int InnerLoopCount = 512; - public ReadOnlyBuffer _buffer; + public ReadOnlyBuffer _buffer; public Http1Connection _http1Connection; [IterationSetup] diff --git a/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs b/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs index 3904523c02..325b27c0e7 100644 --- a/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private static readonly Func _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask; private readonly TestHttp1Connection _http1Connection; - private (IPipeConnection Transport, IPipeConnection Application) _pair; + private (IDuplexPipe Transport, IDuplexPipe Application) _pair; private readonly byte[] _writeData; @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance var reader = _pair.Application.Input; if (reader.TryRead(out var readResult)) { - reader.Advance(readResult.Buffer.End); + reader.AdvanceTo(readResult.Buffer.End); } } diff --git a/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs b/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs index 4d63b75b91..2c42151f34 100644 --- a/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs +++ b/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { private readonly HttpParser _parser = new HttpParser(); - private ReadOnlyBuffer _buffer; + private ReadOnlyBuffer _buffer; [Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)] public void PlaintextTechEmpower() @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private void InsertData(byte[] data) { - _buffer = new ReadOnlyBuffer(data); + _buffer = new ReadOnlyBuffer(data); } private void ParseData() diff --git a/benchmarks/Kestrel.Performance/Mocks/NullParser.cs b/benchmarks/Kestrel.Performance/Mocks/NullParser.cs index f091f67320..3f83491dd8 100644 --- a/benchmarks/Kestrel.Performance/Mocks/NullParser.cs +++ b/benchmarks/Kestrel.Performance/Mocks/NullParser.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.IO.Pipelines; using System.Text; @@ -23,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public static readonly NullParser Instance = new NullParser(); - public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes) + public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes) { handler.OnHeader(new Span(_hostHeaderName), new Span(_hostHeaderValue)); handler.OnHeader(new Span(_acceptHeaderName), new Span(_acceptHeaderValue)); @@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance return true; } - public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined) + public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out SequencePosition consumed, out SequencePosition examined) { handler.OnStartLine(HttpMethod.Get, HttpVersion.Http11, diff --git a/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs b/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs index 999fa0a8e1..80e331ea5a 100644 --- a/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs +++ b/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private const int _writeLenght = 57; private const int InnerLoopCount = 512; - private IPipe _pipe; + private Pipe _pipe; private MemoryPool _memoryPool; [IterationSetup] @@ -30,9 +30,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { for (int i = 0; i < InnerLoopCount; i++) { - var writableBuffer = _pipe.Writer.Alloc(_writeLenght); - writableBuffer.Advance(_writeLenght); - await writableBuffer.FlushAsync(); + _pipe.Writer.GetMemory(_writeLenght); + _pipe.Writer.Advance(_writeLenght); + await _pipe.Writer.FlushAsync(); } }); @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { var result = await _pipe.Reader.ReadAsync(); 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++) { - var writableBuffer = _pipe.Writer.Alloc(_writeLenght); - writableBuffer.Advance(_writeLenght); - writableBuffer.FlushAsync().GetAwaiter().GetResult(); + _pipe.Writer.GetMemory(_writeLenght); + _pipe.Writer.Advance(_writeLenght); + _pipe.Writer.FlushAsync().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); } } } diff --git a/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs b/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs index 7762902258..3c7d4caaf7 100644 --- a/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { public class RequestParsingBenchmark { - public IPipe Pipe { get; set; } + public Pipe Pipe { get; set; } public Http1Connection Http1Connection { get; set; } @@ -130,10 +130,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private void InsertData(byte[] bytes) { - var buffer = Pipe.Writer.Alloc(2048); - buffer.Write(bytes); + Pipe.Writer.Write(bytes); // There should not be any backpressure and task completes immediately - buffer.FlushAsync().GetAwaiter().GetResult(); + Pipe.Writer.FlushAsync().GetAwaiter().GetResult(); } private void ParseDataDrainBuffer() @@ -166,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance } while (readableBuffer.Length > 0); - Pipe.Reader.Advance(readableBuffer.End); + Pipe.Reader.AdvanceTo(readableBuffer.End); } private void ParseData() @@ -189,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { ErrorUtilities.ThrowInvalidRequestLine(); } - Pipe.Reader.Advance(consumed, examined); + Pipe.Reader.AdvanceTo(consumed, examined); result = Pipe.Reader.ReadAsync().GetAwaiter().GetResult(); readableBuffer = result.Buffer; @@ -198,7 +197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { ErrorUtilities.ThrowInvalidRequestHeaders(); } - Pipe.Reader.Advance(consumed, examined); + Pipe.Reader.AdvanceTo(consumed, examined); } while (true); } diff --git a/build/dependencies.props b/build/dependencies.props index bf97f3a333..67964d04ce 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -25,21 +25,21 @@ 2.1.0-preview1-28153 2.1.0-preview1-28153 2.0.0 - 2.1.0-preview1-26115-03 + 2.1.0-preview1-26126-02 2.1.0-preview1-28153 15.3.0 4.7.49 10.0.1 - 4.5.0-preview1-26112-01 - 0.1.0-e180104-2 - 0.1.0-e180104-2 - 0.1.0-e180104-2 - 4.5.0-preview1-26112-01 - 4.5.0-preview1-26112-01 - 4.5.0-preview1-26112-01 - 4.5.0-preview1-26112-01 - 0.1.0-e180104-2 - 4.5.0-preview1-26112-01 + 4.5.0-preview1-26126-05 + 0.1.0-preview1-180129-1 + 0.1.0-preview1-180129-1 + 0.1.0-preview1-180129-1 + 4.5.0-preview1-26126-05 + 4.5.0-preview1-26126-05 + 4.5.0-preview1-26126-05 + 4.5.0-preview1-26126-05 + 0.1.0-preview1-180129-1 + 4.5.0-preview1-26126-05 0.8.0 2.3.1 2.3.1 diff --git a/src/Kestrel.Core/Adapter/Internal/AdaptedPipeline.cs b/src/Kestrel.Core/Adapter/Internal/AdaptedPipeline.cs index 43526c8243..2cebf61741 100644 --- a/src/Kestrel.Core/Adapter/Internal/AdaptedPipeline.cs +++ b/src/Kestrel.Core/Adapter/Internal/AdaptedPipeline.cs @@ -10,17 +10,17 @@ using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal { - public class AdaptedPipeline : IPipeConnection + public class AdaptedPipeline : IDuplexPipe { private const int MinAllocBufferSize = 2048; - private readonly IPipeConnection _transport; - private readonly IPipeConnection _application; + private readonly IDuplexPipe _transport; + private readonly IDuplexPipe _application; - public AdaptedPipeline(IPipeConnection transport, - IPipeConnection application, - IPipe inputPipe, - IPipe outputPipe) + public AdaptedPipeline(IDuplexPipe transport, + IDuplexPipe application, + Pipe inputPipe, + Pipe outputPipe) { _transport = transport; _application = application; @@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal 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) { @@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal } await stream.FlushAsync(); } - else if (buffer.IsSingleSpan) + else if (buffer.IsSingleSegment) { var array = buffer.First.GetArray(); await stream.WriteAsync(array.Array, array.Offset, array.Count); @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal } 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) { - var outputBuffer = Input.Writer.Alloc(MinAllocBufferSize); + var outputBuffer = Input.Writer.GetMemory(MinAllocBufferSize); - var array = outputBuffer.Buffer.GetArray(); + var array = outputBuffer.GetArray(); try { var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count); - outputBuffer.Advance(bytesRead); + Input.Writer.Advance(bytesRead); if (bytesRead == 0) { @@ -140,10 +140,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal } finally { - outputBuffer.Commit(); + Input.Writer.Commit(); } - var result = await outputBuffer.FlushAsync(); + var result = await Input.Writer.FlushAsync(); if (result.IsCompleted) { diff --git a/src/Kestrel.Core/Adapter/Internal/RawStream.cs b/src/Kestrel.Core/Adapter/Internal/RawStream.cs index fdd4470637..87a0932c32 100644 --- a/src/Kestrel.Core/Adapter/Internal/RawStream.cs +++ b/src/Kestrel.Core/Adapter/Internal/RawStream.cs @@ -6,15 +6,16 @@ using System.IO.Pipelines; using System.IO; using System.Threading; using System.Threading.Tasks; +using System.Buffers; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal { public class RawStream : Stream { - private readonly IPipeReader _input; - private readonly IPipeWriter _output; + private readonly PipeReader _input; + private readonly PipeWriter _output; - public RawStream(IPipeReader input, IPipeWriter output) + public RawStream(PipeReader input, PipeWriter output) { _input = input; _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) { - var output = _output.Alloc(); - if (buffer != null) { - output.Write(new ArraySegment(buffer, offset, count)); + _output.Write(new ReadOnlySpan(buffer, offset, count)); } - await output.FlushAsync(token); + await _output.FlushAsync(token); } public override void Flush() @@ -118,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal } finally { - _input.Advance(readableBuffer.End, readableBuffer.End); + _input.AdvanceTo(readableBuffer.End, readableBuffer.End); } } } diff --git a/src/Kestrel.Core/Internal/ConnectionHandler.cs b/src/Kestrel.Core/Internal/ConnectionHandler.cs index d968fce78c..bf8b598866 100644 --- a/src/Kestrel.Core/Internal/ConnectionHandler.cs +++ b/src/Kestrel.Core/Internal/ConnectionHandler.cs @@ -83,22 +83,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal } // 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, readerScheduler: serviceContext.ThreadPool, writerScheduler: writerScheduler, - maximumSizeHigh: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, - maximumSizeLow: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 + pauseWriterThreshold: 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, readerScheduler: readerScheduler, writerScheduler: serviceContext.ThreadPool, - maximumSizeHigh: GetOutputResponseBufferSize(serviceContext), - maximumSizeLow: GetOutputResponseBufferSize(serviceContext) + pauseWriterThreshold: GetOutputResponseBufferSize(serviceContext), + resumeWriterThreshold: GetOutputResponseBufferSize(serviceContext) ); private static long GetOutputResponseBufferSize(ServiceContext serviceContext) diff --git a/src/Kestrel.Core/Internal/Http/ChunkWriter.cs b/src/Kestrel.Core/Internal/Http/ChunkWriter.cs index a394fb414e..d37f6d48df 100644 --- a/src/Kestrel.Core/Internal/Http/ChunkWriter.cs +++ b/src/Kestrel.Core/Internal/Http/ChunkWriter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Text; @@ -47,16 +48,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return new ArraySegment(bytes, offset, 10 - offset); } - public static int WriteBeginChunkBytes(ref WritableBufferWriter start, int dataCount) + public static int WriteBeginChunkBytes(ref OutputWriter start, int dataCount) { var chunkSegment = BeginChunkBytes(dataCount); - start.Write(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count); + start.Write(new ReadOnlySpan(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count)); return chunkSegment.Count; } - public static void WriteEndChunkBytes(ref WritableBufferWriter start) + public static void WriteEndChunkBytes(ref OutputWriter start) { - start.Write(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count); + start.Write(new ReadOnlySpan(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count)); } } } diff --git a/src/Kestrel.Core/Internal/Http/Http1Connection.cs b/src/Kestrel.Core/Internal/Http/Http1Connection.cs index 84890c4137..e0e5c7d438 100644 --- a/src/Kestrel.Core/Internal/Http/Http1Connection.cs +++ b/src/Kestrel.Core/Internal/Http/Http1Connection.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.Diagnostics; 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); } - public IPipeReader Input => _context.Transport.Input; + public PipeReader Input => _context.Transport.Input; public ITimeoutControl TimeoutControl => _context.TimeoutControl; public bool RequestTimedOut => _requestTimedOut; @@ -69,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http Input.CancelPendingRead(); } - public void ParseRequest(ReadOnlyBuffer buffer, out Position consumed, out Position examined) + public void ParseRequest(ReadOnlyBuffer buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; 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 buffer, out SequencePosition consumed, out SequencePosition examined) { var overLength = false; if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize) @@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return result; } - public bool TakeMessageHeaders(ReadOnlyBuffer buffer, out Position consumed, out Position examined) + public bool TakeMessageHeaders(ReadOnlyBuffer buffer, out SequencePosition consumed, out SequencePosition examined) { // Make sure the buffer is limited bool overLength = false; @@ -453,7 +454,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } finally { - Input.Advance(consumed, examined); + Input.AdvanceTo(consumed, examined); } if (result.IsCompleted) diff --git a/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs b/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs index b30be13924..cb3d9a2cef 100644 --- a/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs +++ b/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; } public ITimeoutControl TimeoutControl { get; set; } - public IPipeConnection Transport { get; set; } - public IPipeConnection Application { get; set; } + public IDuplexPipe Transport { get; set; } + public IDuplexPipe Application { get; set; } } } diff --git a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs index 3d808838b9..521a9c58f8 100644 --- a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs +++ b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.IO; using System.IO.Pipelines; @@ -62,19 +63,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (!readableBuffer.IsEmpty) { - var writableBuffer = _context.RequestBodyPipe.Writer.Alloc(1); bool done; try { - done = Read(readableBuffer, writableBuffer, out consumed, out examined); + done = Read(readableBuffer, _context.RequestBodyPipe.Writer, out consumed, out examined); } finally { - writableBuffer.Commit(); + _context.RequestBodyPipe.Writer.Commit(); } - var writeAwaitable = writableBuffer.FlushAsync(); + var writeAwaitable = _context.RequestBodyPipe.Writer.FlushAsync(); var backpressure = false; if (!writeAwaitable.IsCompleted) @@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } finally { - _context.Input.Advance(consumed, examined); + _context.Input.AdvanceTo(consumed, examined); } } } @@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http do { result = await _context.RequestBodyPipe.Reader.ReadAsync(); - _context.RequestBodyPipe.Reader.Advance(result.Buffer.End); + _context.RequestBodyPipe.Reader.AdvanceTo(result.Buffer.End); } while (!result.IsCompleted); } finally @@ -151,11 +151,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } } - protected void Copy(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer) + protected void Copy(ReadOnlyBuffer readableBuffer, PipeWriter writableBuffer) { _context.TimeoutControl.BytesRead(readableBuffer.Length); - if (readableBuffer.IsSingleSpan) + if (readableBuffer.IsSingleSegment) { writableBuffer.Write(readableBuffer.First.Span); } @@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _pumpTask = PumpAsync(); } - protected virtual bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) + protected virtual bool Read(ReadOnlyBuffer readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { throw new NotImplementedException(); } @@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http RequestUpgrade = true; } - protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) + protected override bool Read(ReadOnlyBuffer readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { Copy(readableBuffer, writableBuffer); consumed = readableBuffer.End; @@ -316,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _inputLength = _contentLength; } - protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) + protected override bool Read(ReadOnlyBuffer readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { if (_inputLength == 0) { @@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var actual = (int)Math.Min(readableBuffer.Length, _inputLength); _inputLength -= actual; - consumed = readableBuffer.Move(readableBuffer.Start, actual); + consumed = readableBuffer.GetPosition(readableBuffer.Start, actual); examined = consumed; Copy(readableBuffer.Slice(0, actual), writableBuffer); @@ -364,10 +364,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http RequestKeepAlive = keepAlive; } - protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) + protected override bool Read(ReadOnlyBuffer readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { - consumed = default(Position); - examined = default(Position); + consumed = default(SequencePosition); + examined = default(SequencePosition); 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 buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; var reader = BufferReader.Create(buffer); - var ch1 = reader.Take(); - var ch2 = reader.Take(); + var ch1 = reader.Read(); + var ch2 = reader.Read(); if (ch1 == -1 || ch2 == -1) { @@ -485,7 +485,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return; } - ch2 = reader.Take(); + ch2 = reader.Read(); if (ch2 == -1) { examined = reader.Position; @@ -511,7 +511,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _context.ThrowRequestRejected(RequestRejectionReason.BadChunkSizeData); } - private void ParseExtension(ReadOnlyBuffer buffer, out Position consumed, out Position examined) + private void ParseExtension(ReadOnlyBuffer buffer, out SequencePosition consumed, out SequencePosition examined) { // Chunk-extensions not currently parsed // Just drain the data @@ -520,8 +520,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http do { - Position extensionCursor; - if (ReadOnlyBuffer.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1) + SequencePosition? extensionCursorPosition = buffer.PositionOf(ByteCR); + if (extensionCursorPosition == null) { // End marker not found yet consumed = buffer.End; @@ -530,6 +530,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return; }; + var extensionCursor = extensionCursorPosition.Value; var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length; var sufixBuffer = buffer.Slice(extensionCursor); @@ -563,10 +564,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } while (_mode == Mode.Extension); } - private void ReadChunkedData(ReadOnlyBuffer buffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) + private void ReadChunkedData(ReadOnlyBuffer buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { var actual = Math.Min(buffer.Length, _inputLength); - consumed = buffer.Move(buffer.Start, actual); + consumed = buffer.GetPosition(buffer.Start, actual); examined = consumed; 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 buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = 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 buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; diff --git a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs index 466f17f64e..a3781075c5 100644 --- a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs +++ b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Diagnostics; using System.IO.Pipelines; using System.Runtime.CompilerServices; @@ -28,8 +29,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private bool _completed = false; - private readonly IPipeWriter _pipeWriter; - private readonly IPipeReader _outputPipeReader; + private readonly PipeWriter _pipeWriter; + private readonly PipeReader _outputPipeReader; // https://github.com/dotnet/corefxlab/issues/1334 // Pipelines don't support multiple awaiters on flush @@ -39,8 +40,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private Action _flushCompleted; public Http1OutputProducer( - IPipeReader outputPipeReader, - IPipeWriter pipeWriter, + PipeReader outputPipeReader, + PipeWriter pipeWriter, string connectionId, IKestrelTrace log, ITimeoutControl timeoutControl) @@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return WriteAsync(Constants.EmptyData, cancellationToken); } - public void Write(Action callback, T state) + public void Write(Action callback, T state) { lock (_contextLock) { @@ -82,13 +83,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return; } - var buffer = _pipeWriter.Alloc(1); + var buffer = _pipeWriter; callback(buffer, state); buffer.Commit(); } } - public Task WriteAsync(Action callback, T state) + public Task WriteAsync(Action callback, T state) { lock (_contextLock) { @@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return Task.CompletedTask; } - var buffer = _pipeWriter.Alloc(1); + var buffer = _pipeWriter; callback(buffer, state); buffer.Commit(); } @@ -114,8 +115,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return; } - var buffer = _pipeWriter.Alloc(1); - var writer = new WritableBufferWriter(buffer); + var buffer = _pipeWriter; + var writer = OutputWriter.Create(buffer); writer.Write(_bytesHttpVersion11); var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase); @@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http ArraySegment buffer, CancellationToken cancellationToken) { - var writableBuffer = default(WritableBuffer); + var writableBuffer = default(PipeWriter); long bytesWritten = 0; lock (_contextLock) { @@ -176,11 +177,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return Task.CompletedTask; } - writableBuffer = _pipeWriter.Alloc(1); - var writer = new WritableBufferWriter(writableBuffer); + writableBuffer = _pipeWriter; + var writer = OutputWriter.Create(writableBuffer); if (buffer.Count > 0) { - writer.Write(buffer.Array, buffer.Offset, buffer.Count); + writer.Write(new ReadOnlySpan(buffer.Array, buffer.Offset, 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 [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); if (awaitable.IsCompleted) diff --git a/src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs b/src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs index 0da75ae65f..80bf03c4fd 100644 --- a/src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs +++ b/src/Kestrel.Core/Internal/Http/HttpHeaders.Generated.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; +using System.Buffers; using System.IO.Pipelines; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; @@ -7753,7 +7754,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return true; } - protected void CopyToFast(ref WritableBufferWriter output) + protected void CopyToFast(ref OutputWriter output) { var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0); @@ -7771,7 +7772,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Connection[i]; if (value != null) { - output.Write(_headerBytes, 17, 14); + output.Write(new ReadOnlySpan(_headerBytes, 17, 14)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7797,7 +7798,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Date[i]; if (value != null) { - output.Write(_headerBytes, 31, 8); + output.Write(new ReadOnlySpan(_headerBytes, 31, 8)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7818,7 +7819,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ContentType[i]; if (value != null) { - output.Write(_headerBytes, 133, 16); + output.Write(new ReadOnlySpan(_headerBytes, 133, 16)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7844,7 +7845,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Server[i]; if (value != null) { - output.Write(_headerBytes, 350, 10); + output.Write(new ReadOnlySpan(_headerBytes, 350, 10)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7858,7 +7859,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } if ((tempBits & -9223372036854775808L) != 0) { - output.Write(_headerBytes, 592, 18); + output.Write(new ReadOnlySpan(_headerBytes, 592, 18)); PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value); if((tempBits & ~-9223372036854775808L) == 0) @@ -7876,7 +7877,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._CacheControl[i]; if (value != null) { - output.Write(_headerBytes, 0, 17); + output.Write(new ReadOnlySpan(_headerBytes, 0, 17)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7897,7 +7898,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._KeepAlive[i]; if (value != null) { - output.Write(_headerBytes, 39, 14); + output.Write(new ReadOnlySpan(_headerBytes, 39, 14)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7918,7 +7919,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Pragma[i]; if (value != null) { - output.Write(_headerBytes, 53, 10); + output.Write(new ReadOnlySpan(_headerBytes, 53, 10)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7939,7 +7940,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Trailer[i]; if (value != null) { - output.Write(_headerBytes, 63, 11); + output.Write(new ReadOnlySpan(_headerBytes, 63, 11)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7965,7 +7966,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._TransferEncoding[i]; if (value != null) { - output.Write(_headerBytes, 74, 21); + output.Write(new ReadOnlySpan(_headerBytes, 74, 21)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -7986,7 +7987,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Upgrade[i]; if (value != null) { - output.Write(_headerBytes, 95, 11); + output.Write(new ReadOnlySpan(_headerBytes, 95, 11)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8007,7 +8008,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Via[i]; if (value != null) { - output.Write(_headerBytes, 106, 7); + output.Write(new ReadOnlySpan(_headerBytes, 106, 7)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8028,7 +8029,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Warning[i]; if (value != null) { - output.Write(_headerBytes, 113, 11); + output.Write(new ReadOnlySpan(_headerBytes, 113, 11)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8049,7 +8050,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Allow[i]; if (value != null) { - output.Write(_headerBytes, 124, 9); + output.Write(new ReadOnlySpan(_headerBytes, 124, 9)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8070,7 +8071,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ContentEncoding[i]; if (value != null) { - output.Write(_headerBytes, 149, 20); + output.Write(new ReadOnlySpan(_headerBytes, 149, 20)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8091,7 +8092,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ContentLanguage[i]; if (value != null) { - output.Write(_headerBytes, 169, 20); + output.Write(new ReadOnlySpan(_headerBytes, 169, 20)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8112,7 +8113,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ContentLocation[i]; if (value != null) { - output.Write(_headerBytes, 189, 20); + output.Write(new ReadOnlySpan(_headerBytes, 189, 20)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8133,7 +8134,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ContentMD5[i]; if (value != null) { - output.Write(_headerBytes, 209, 15); + output.Write(new ReadOnlySpan(_headerBytes, 209, 15)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8154,7 +8155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ContentRange[i]; if (value != null) { - output.Write(_headerBytes, 224, 17); + output.Write(new ReadOnlySpan(_headerBytes, 224, 17)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8175,7 +8176,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Expires[i]; if (value != null) { - output.Write(_headerBytes, 241, 11); + output.Write(new ReadOnlySpan(_headerBytes, 241, 11)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8196,7 +8197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._LastModified[i]; if (value != null) { - output.Write(_headerBytes, 252, 17); + output.Write(new ReadOnlySpan(_headerBytes, 252, 17)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8217,7 +8218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AcceptRanges[i]; if (value != null) { - output.Write(_headerBytes, 269, 17); + output.Write(new ReadOnlySpan(_headerBytes, 269, 17)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8238,7 +8239,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Age[i]; if (value != null) { - output.Write(_headerBytes, 286, 7); + output.Write(new ReadOnlySpan(_headerBytes, 286, 7)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8259,7 +8260,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ETag[i]; if (value != null) { - output.Write(_headerBytes, 293, 8); + output.Write(new ReadOnlySpan(_headerBytes, 293, 8)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8280,7 +8281,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Location[i]; if (value != null) { - output.Write(_headerBytes, 301, 12); + output.Write(new ReadOnlySpan(_headerBytes, 301, 12)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8301,7 +8302,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._ProxyAuthenticate[i]; if (value != null) { - output.Write(_headerBytes, 313, 22); + output.Write(new ReadOnlySpan(_headerBytes, 313, 22)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8322,7 +8323,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._RetryAfter[i]; if (value != null) { - output.Write(_headerBytes, 335, 15); + output.Write(new ReadOnlySpan(_headerBytes, 335, 15)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8343,7 +8344,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._SetCookie[i]; if (value != null) { - output.Write(_headerBytes, 360, 14); + output.Write(new ReadOnlySpan(_headerBytes, 360, 14)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8364,7 +8365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._Vary[i]; if (value != null) { - output.Write(_headerBytes, 374, 8); + output.Write(new ReadOnlySpan(_headerBytes, 374, 8)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8385,7 +8386,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._WWWAuthenticate[i]; if (value != null) { - output.Write(_headerBytes, 382, 20); + output.Write(new ReadOnlySpan(_headerBytes, 382, 20)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8406,7 +8407,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AccessControlAllowCredentials[i]; if (value != null) { - output.Write(_headerBytes, 402, 36); + output.Write(new ReadOnlySpan(_headerBytes, 402, 36)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8427,7 +8428,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AccessControlAllowHeaders[i]; if (value != null) { - output.Write(_headerBytes, 438, 32); + output.Write(new ReadOnlySpan(_headerBytes, 438, 32)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8448,7 +8449,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AccessControlAllowMethods[i]; if (value != null) { - output.Write(_headerBytes, 470, 32); + output.Write(new ReadOnlySpan(_headerBytes, 470, 32)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8469,7 +8470,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AccessControlAllowOrigin[i]; if (value != null) { - output.Write(_headerBytes, 502, 31); + output.Write(new ReadOnlySpan(_headerBytes, 502, 31)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8490,7 +8491,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AccessControlExposeHeaders[i]; if (value != null) { - output.Write(_headerBytes, 533, 33); + output.Write(new ReadOnlySpan(_headerBytes, 533, 33)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } @@ -8511,7 +8512,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var value = _headers._AccessControlMaxAge[i]; if (value != null) { - output.Write(_headerBytes, 566, 26); + output.Write(new ReadOnlySpan(_headerBytes, 566, 26)); PipelineExtensions.WriteAsciiNoValidation(ref output, value); } } diff --git a/src/Kestrel.Core/Internal/Http/HttpParser.cs b/src/Kestrel.Core/Internal/Http/HttpParser.cs index 13297094f3..ece56ac7ed 100644 --- a/src/Kestrel.Core/Internal/Http/HttpParser.cs +++ b/src/Kestrel.Core/Internal/Http/HttpParser.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.IO.Pipelines; using System.Runtime.CompilerServices; @@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private const byte ByteQuestionMark = (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 buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.End; @@ -43,10 +44,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var lineIndex = span.IndexOf(ByteLF); if (lineIndex >= 0) { - consumed = buffer.Move(consumed, lineIndex + 1); + consumed = buffer.GetPosition(consumed, lineIndex + 1); span = span.Slice(0, lineIndex + 1); } - else if (buffer.IsSingleSpan) + else if (buffer.IsSingleSegment) { // No request line end return false; @@ -188,7 +189,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http 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 buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes) { consumed = buffer.Start; examined = buffer.End; @@ -197,21 +198,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var bufferEnd = buffer.End; var reader = BufferReader.Create(buffer); - var start = default(BufferReader); + var start = default(BufferReader>); var done = false; try { while (!reader.End) { - var span = reader.Span; - var remaining = span.Length - reader.Index; + var span = reader.CurrentSegment; + var remaining = span.Length - reader.CurrentSegmentIndex; fixed (byte* pBuffer = &MemoryMarshal.GetReference(span)) { while (remaining > 0) { - var index = reader.Index; + var index = reader.CurrentSegmentIndex; int ch1; int ch2; @@ -228,8 +229,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http start = reader; // Possibly split across spans - ch1 = reader.Take(); - ch2 = reader.Take(); + ch1 = reader.Read(); + ch2 = reader.Read(); } 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 // the reader's state matches what we expect - if (index == reader.Index) + if (index == reader.CurrentSegmentIndex) { - reader.Skip(2); + reader.Advance(2); } 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 // and the index - if (index != reader.Index) + if (index != reader.CurrentSegmentIndex) { reader = start; - index = reader.Index; + index = reader.CurrentSegmentIndex; } var endIndex = new Span(pBuffer + index, remaining).IndexOf(ByteLF); @@ -279,16 +280,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http else { var current = reader.Position; + var currentSlice = buffer.Slice(current, bufferEnd); + var lineEndPosition = currentSlice.PositionOf(ByteLF); // Split buffers - if (ReadOnlyBuffer.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1) + if (lineEndPosition == null) { // Not there return false; } + var lineEnd = lineEndPosition.Value; + // Make sure LF is included in lineEnd - lineEnd = buffer.Move(lineEnd, 1); + lineEnd = buffer.GetPosition(lineEnd, 1); var headerSpan = buffer.Slice(current, lineEnd).ToSpan(); length = headerSpan.Length; @@ -304,7 +309,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } // Skip the reader forward past the header line - reader.Skip(length); + reader.Advance(length); remaining -= length; } } @@ -414,15 +419,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.NoInlining)] - private static bool TryGetNewLine(ref ReadOnlyBuffer buffer, out Position found) + private static bool TryGetNewLine(ref ReadOnlyBuffer buffer, out SequencePosition found) { - var start = buffer.Start; - if (ReadOnlyBuffer.Seek(start, buffer.End, out found, ByteLF) != -1) + var byteLfPosition = buffer.PositionOf(ByteLF); + if (byteLfPosition != null) { // Move 1 byte past the \n - found = buffer.Move(found, 1); + found = buffer.GetPosition(byteLfPosition.Value, 1); return true; } + + found = default; return false; } diff --git a/src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs b/src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs index 5c57080c1f..319d36865b 100644 --- a/src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs +++ b/src/Kestrel.Core/Internal/Http/HttpProtocol.Generated.cs @@ -4,31 +4,35 @@ using System; 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 { public partial class HttpProtocol { - private static readonly Type IHttpRequestFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature); - private static readonly Type IHttpResponseFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature); - private static readonly Type IHttpRequestIdentifierFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature); - private static readonly Type IServiceProvidersFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature); - private static readonly Type IHttpRequestLifetimeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature); - private static readonly Type IHttpConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature); - private static readonly Type IHttpAuthenticationFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature); - private static readonly Type IQueryFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IQueryFeature); - private static readonly Type IFormFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IFormFeature); - private static readonly Type IHttpUpgradeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature); - private static readonly Type IHttp2StreamIdFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature); - private static readonly Type IResponseCookiesFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature); - private static readonly Type IItemsFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IItemsFeature); - private static readonly Type ITlsConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature); - private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature); - private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ISessionFeature); - private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature); - private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature); - private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature); - private static readonly Type IHttpBodyControlFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature); - private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature); + private static readonly Type IHttpRequestFeatureType = typeof(IHttpRequestFeature); + private static readonly Type IHttpResponseFeatureType = typeof(IHttpResponseFeature); + private static readonly Type IHttpRequestIdentifierFeatureType = typeof(IHttpRequestIdentifierFeature); + private static readonly Type IServiceProvidersFeatureType = typeof(IServiceProvidersFeature); + private static readonly Type IHttpRequestLifetimeFeatureType = typeof(IHttpRequestLifetimeFeature); + private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature); + private static readonly Type IHttpAuthenticationFeatureType = typeof(IHttpAuthenticationFeature); + private static readonly Type IQueryFeatureType = typeof(IQueryFeature); + private static readonly Type IFormFeatureType = typeof(IFormFeature); + private static readonly Type IHttpUpgradeFeatureType = typeof(IHttpUpgradeFeature); + private static readonly Type IHttp2StreamIdFeatureType = typeof(IHttp2StreamIdFeature); + private static readonly Type IResponseCookiesFeatureType = typeof(IResponseCookiesFeature); + private static readonly Type IItemsFeatureType = typeof(IItemsFeature); + private static readonly Type ITlsConnectionFeatureType = typeof(ITlsConnectionFeature); + private static readonly Type IHttpWebSocketFeatureType = typeof(IHttpWebSocketFeature); + private static readonly Type ISessionFeatureType = typeof(ISessionFeature); + private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(IHttpMaxRequestBodySizeFeature); + private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(IHttpMinRequestBodyDataRateFeature); + private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(IHttpMinResponseDataRateFeature); + private static readonly Type IHttpBodyControlFeatureType = typeof(IHttpBodyControlFeature); + private static readonly Type IHttpSendFileFeatureType = typeof(IHttpSendFileFeature); private object _currentIHttpRequestFeature; private object _currentIHttpResponseFeature; @@ -283,87 +287,87 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { if (_currentIHttpRequestFeature != null) { - yield return new KeyValuePair(IHttpRequestFeatureType, _currentIHttpRequestFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature); + yield return new KeyValuePair(IHttpRequestFeatureType, _currentIHttpRequestFeature as IHttpRequestFeature); } if (_currentIHttpResponseFeature != null) { - yield return new KeyValuePair(IHttpResponseFeatureType, _currentIHttpResponseFeature as global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature); + yield return new KeyValuePair(IHttpResponseFeatureType, _currentIHttpResponseFeature as IHttpResponseFeature); } if (_currentIHttpRequestIdentifierFeature != null) { - yield return new KeyValuePair(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature); + yield return new KeyValuePair(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as IHttpRequestIdentifierFeature); } if (_currentIServiceProvidersFeature != null) { - yield return new KeyValuePair(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature); + yield return new KeyValuePair(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as IServiceProvidersFeature); } if (_currentIHttpRequestLifetimeFeature != null) { - yield return new KeyValuePair(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature); + yield return new KeyValuePair(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as IHttpRequestLifetimeFeature); } if (_currentIHttpConnectionFeature != null) { - yield return new KeyValuePair(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature); + yield return new KeyValuePair(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as IHttpConnectionFeature); } if (_currentIHttpAuthenticationFeature != null) { - yield return new KeyValuePair(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature); + yield return new KeyValuePair(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as IHttpAuthenticationFeature); } if (_currentIQueryFeature != null) { - yield return new KeyValuePair(IQueryFeatureType, _currentIQueryFeature as global::Microsoft.AspNetCore.Http.Features.IQueryFeature); + yield return new KeyValuePair(IQueryFeatureType, _currentIQueryFeature as IQueryFeature); } if (_currentIFormFeature != null) { - yield return new KeyValuePair(IFormFeatureType, _currentIFormFeature as global::Microsoft.AspNetCore.Http.Features.IFormFeature); + yield return new KeyValuePair(IFormFeatureType, _currentIFormFeature as IFormFeature); } if (_currentIHttpUpgradeFeature != null) { - yield return new KeyValuePair(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature); + yield return new KeyValuePair(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as IHttpUpgradeFeature); } if (_currentIHttp2StreamIdFeature != null) { - yield return new KeyValuePair(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature); + yield return new KeyValuePair(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as IHttp2StreamIdFeature); } if (_currentIResponseCookiesFeature != null) { - yield return new KeyValuePair(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature); + yield return new KeyValuePair(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as IResponseCookiesFeature); } if (_currentIItemsFeature != null) { - yield return new KeyValuePair(IItemsFeatureType, _currentIItemsFeature as global::Microsoft.AspNetCore.Http.Features.IItemsFeature); + yield return new KeyValuePair(IItemsFeatureType, _currentIItemsFeature as IItemsFeature); } if (_currentITlsConnectionFeature != null) { - yield return new KeyValuePair(ITlsConnectionFeatureType, _currentITlsConnectionFeature as global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature); + yield return new KeyValuePair(ITlsConnectionFeatureType, _currentITlsConnectionFeature as ITlsConnectionFeature); } if (_currentIHttpWebSocketFeature != null) { - yield return new KeyValuePair(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature); + yield return new KeyValuePair(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as IHttpWebSocketFeature); } if (_currentISessionFeature != null) { - yield return new KeyValuePair(ISessionFeatureType, _currentISessionFeature as global::Microsoft.AspNetCore.Http.Features.ISessionFeature); + yield return new KeyValuePair(ISessionFeatureType, _currentISessionFeature as ISessionFeature); } if (_currentIHttpMaxRequestBodySizeFeature != null) { - yield return new KeyValuePair(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature); + yield return new KeyValuePair(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as IHttpMaxRequestBodySizeFeature); } if (_currentIHttpMinRequestBodyDataRateFeature != null) { - yield return new KeyValuePair(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature); + yield return new KeyValuePair(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as IHttpMinRequestBodyDataRateFeature); } if (_currentIHttpMinResponseDataRateFeature != null) { - yield return new KeyValuePair(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature); + yield return new KeyValuePair(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as IHttpMinResponseDataRateFeature); } if (_currentIHttpBodyControlFeature != null) { - yield return new KeyValuePair(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature); + yield return new KeyValuePair(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as IHttpBodyControlFeature); } if (_currentIHttpSendFileFeature != null) { - yield return new KeyValuePair(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature); + yield return new KeyValuePair(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as IHttpSendFileFeature); } if (MaybeExtra != null) diff --git a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs index cc34dfef3c..f8ada6f76e 100644 --- a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs +++ b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; 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[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked"); private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName); - private static readonly Action> _writeChunk = WriteChunk; + private static readonly Action> _writeChunk = WriteChunk; private readonly object _onStartingSync = 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); } - private static void WriteChunk(WritableBuffer writableBuffer, ArraySegment buffer) + private static void WriteChunk(PipeWriter writableBuffer, ArraySegment buffer) { - var writer = new WritableBufferWriter(writableBuffer); + var writer = OutputWriter.Create(writableBuffer); if (buffer.Count > 0) { ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Count); - writer.Write(buffer.Array, buffer.Offset, buffer.Count); + writer.Write(new ReadOnlySpan(buffer.Array, buffer.Offset, buffer.Count)); ChunkWriter.WriteEndChunkBytes(ref writer); } } @@ -1297,9 +1298,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http ( pool: _context.MemoryPool, readerScheduler: ServiceContext.ThreadPool, - writerScheduler: Scheduler.Inline, - maximumSizeHigh: 1, - maximumSizeLow: 1 + writerScheduler: PipeScheduler.Inline, + pauseWriterThreshold: 1, + resumeWriterThreshold: 1 )); } } diff --git a/src/Kestrel.Core/Internal/Http/HttpResponseHeaders.cs b/src/Kestrel.Core/Internal/Http/HttpResponseHeaders.cs index 41bc6ea29b..9a75ff780a 100644 --- a/src/Kestrel.Core/Internal/Http/HttpResponseHeaders.cs +++ b/src/Kestrel.Core/Internal/Http/HttpResponseHeaders.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Collections; using System.Collections.Generic; @@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return GetEnumerator(); } - public void CopyTo(ref WritableBufferWriter output) + public void CopyTo(ref OutputWriter output) { CopyToFast(ref output); if (MaybeUnknown != null) diff --git a/src/Kestrel.Core/Internal/Http/IHttpOutputProducer.cs b/src/Kestrel.Core/Internal/Http/IHttpOutputProducer.cs index adab288186..019fa9fe77 100644 --- a/src/Kestrel.Core/Internal/Http/IHttpOutputProducer.cs +++ b/src/Kestrel.Core/Internal/Http/IHttpOutputProducer.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public interface IHttpOutputProducer : IDisposable { void Abort(Exception error); - Task WriteAsync(Action callback, T state); + Task WriteAsync(Action callback, T state); Task FlushAsync(CancellationToken cancellationToken); Task Write100ContinueAsync(CancellationToken cancellationToken); void WriteResponseHeaders(int statusCode, string ReasonPhrase, HttpResponseHeaders responseHeaders); diff --git a/src/Kestrel.Core/Internal/Http/IHttpParser.cs b/src/Kestrel.Core/Internal/Http/IHttpParser.cs index 07dff45a84..62c2c131b3 100644 --- a/src/Kestrel.Core/Internal/Http/IHttpParser.cs +++ b/src/Kestrel.Core/Internal/Http/IHttpParser.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.IO.Pipelines; @@ -9,8 +10,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { public interface IHttpParser where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler { - bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined); + bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer 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 buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes); } } diff --git a/src/Kestrel.Core/Internal/Http/MessageBody.cs b/src/Kestrel.Core/Internal/Http/MessageBody.cs index 2fd8c12e60..08054b35aa 100644 --- a/src/Kestrel.Core/Internal/Http/MessageBody.cs +++ b/src/Kestrel.Core/Internal/Http/MessageBody.cs @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http // buffer.Count is int var actual = (int) Math.Min(readableBuffer.Length, buffer.Count); var slice = readableBuffer.Slice(0, actual); - consumed = readableBuffer.Move(readableBuffer.Start, actual); + consumed = readableBuffer.GetPosition(readableBuffer.Start, actual); slice.CopyTo(buffer); return actual; } @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } finally { - _context.RequestBodyPipe.Reader.Advance(consumed); + _context.RequestBodyPipe.Reader.AdvanceTo(consumed); } } } @@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } finally { - _context.RequestBodyPipe.Reader.Advance(consumed); + _context.RequestBodyPipe.Reader.AdvanceTo(consumed); } } } diff --git a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs index e45d8ef5c5..4caefd3a95 100644 --- a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs +++ b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs @@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private static byte[] _numericBytesScratch; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan ToSpan(this ReadOnlyBuffer buffer) + public static ReadOnlySpan ToSpan(this ReadOnlyBuffer buffer) { - if (buffer.IsSingleSpan) + if (buffer.IsSingleSegment) { return buffer.First.Span; } @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return result; } - public unsafe static void WriteAsciiNoValidation(ref this WritableBufferWriter buffer, string data) + public unsafe static void WriteAsciiNoValidation(ref this OutputWriter buffer, string data) { if (string.IsNullOrEmpty(data)) { @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe static void WriteNumeric(ref this WritableBufferWriter buffer, ulong number) + public unsafe static void WriteNumeric(ref this OutputWriter buffer, ulong number) { const byte AsciiDigitStart = (byte)'0'; @@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.NoInlining)] - private static void WriteNumericMultiWrite(ref this WritableBufferWriter buffer, ulong number) + private static void WriteNumericMultiWrite(ref this OutputWriter buffer, ulong number) { const byte AsciiDigitStart = (byte)'0'; @@ -141,11 +141,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http while (value != 0); var length = _maxULongByteLength - position; - buffer.Write(byteBuffer, position, length); + buffer.Write(new ReadOnlySpan(byteBuffer, position, length)); } [MethodImpl(MethodImplOptions.NoInlining)] - private unsafe static void WriteAsciiMultiWrite(ref this WritableBufferWriter buffer, string data) + private unsafe static void WriteAsciiMultiWrite(ref this OutputWriter buffer, string data) { var remaining = data.Length; diff --git a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs index c1cb104f50..ca788861ed 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.Collections.Concurrent; using System.IO.Pipelines; @@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 public string ConnectionId => _context.ConnectionId; - public IPipeReader Input => _context.Transport.Input; + public PipeReader Input => _context.Transport.Input; public IKestrelTrace Log => _context.ServiceContext.Log; @@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } finally { - Input.Advance(consumed, examined); + Input.AdvanceTo(consumed, examined); } } @@ -165,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } 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 readableBuffer, out SequencePosition consumed, out SequencePosition examined) { consumed = readableBuffer.Start; examined = readableBuffer.End; @@ -226,7 +227,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 return false; } - var span = readableBuffer.IsSingleSpan + var span = readableBuffer.IsSingleSegment ? readableBuffer.First.Span : 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; } diff --git a/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs b/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs index 929bef9f92..73e4217a5c 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; } - public IPipeConnection Transport { get; set; } - public IPipeConnection Application { get; set; } + public IDuplexPipe Transport { get; set; } + public IDuplexPipe Application { get; set; } } } diff --git a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs index 0a2ae72aa0..9673ad57d5 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Buffers; +using System.Collections; using System.Collections.Sequences; using System.IO.Pipelines; @@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 { public static class Http2FrameReader { - public static bool ReadFrame(ReadOnlyBuffer readableBuffer, Http2Frame frame, out Position consumed, out Position examined) + public static bool ReadFrame(ReadOnlyBuffer readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined) { consumed = readableBuffer.Start; examined = readableBuffer.End; @@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } 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; } diff --git a/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs b/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs index a34bf0ef53..0540beb0fa 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2FrameWriter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; using System.Threading; @@ -20,12 +21,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 private readonly Http2Frame _outgoingFrame = new Http2Frame(); private readonly object _writeLock = new object(); private readonly HPackEncoder _hpackEncoder = new HPackEncoder(); - private readonly IPipeWriter _outputWriter; - private readonly IPipeReader _outputReader; + private readonly PipeWriter _outputWriter; + private readonly PipeReader _outputReader; private bool _completed; - public Http2FrameWriter(IPipeWriter outputPipeWriter, IPipeReader outputPipeReader) + public Http2FrameWriter(PipeWriter outputPipeWriter, PipeReader outputPipeReader) { _outputWriter = outputPipeWriter; _outputReader = outputPipeReader; @@ -48,7 +49,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 public Task FlushAsync(CancellationToken cancellationToken) { - return WriteAsync(Constants.EmptyData); + lock (_writeLock) + { + return WriteAsync(Constants.EmptyData); + } } public Task Write100ContinueAsync(int streamId) @@ -185,9 +189,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 return; } - var writeableBuffer = _outputWriter.Alloc(1); - writeableBuffer.Write(data); - writeableBuffer.Commit(); + _outputWriter.Write(data); + _outputWriter.Commit(); } // Must be called with _writeLock @@ -198,9 +201,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 return; } - var writeableBuffer = _outputWriter.Alloc(1); - writeableBuffer.Write(data); - await writeableBuffer.FlushAsync(cancellationToken); + _outputWriter.Write(data); + await _outputWriter.FlushAsync(cancellationToken); } private static IEnumerable> EnumerateHeaders(IHeaderDictionary headers) diff --git a/src/Kestrel.Core/Internal/Http2/Http2OutputProducer.cs b/src/Kestrel.Core/Internal/Http2/Http2OutputProducer.cs index 93f549b5ce..d1aa31df72 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2OutputProducer.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2OutputProducer.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 // TODO: RST_STREAM? } - public Task WriteAsync(Action callback, T state) + public Task WriteAsync(Action callback, T state) { throw new NotImplementedException(); } diff --git a/src/Kestrel.Core/Internal/Http2/Http2Stream.cs b/src/Kestrel.Core/Internal/Http2/Http2Stream.cs index 1d96e3f7be..6d8fc9136f 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2Stream.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2Stream.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.Kestrel.Core.Features; @@ -78,19 +79,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 { if (data.Count > 0) { - var writableBuffer = RequestBodyPipe.Writer.Alloc(1); - try { - writableBuffer.Write(data); + RequestBodyPipe.Writer.Write(data); } finally { - writableBuffer.Commit(); + RequestBodyPipe.Writer.Commit(); } RequestBodyStarted = true; - await writableBuffer.FlushAsync(); + await RequestBodyPipe.Writer.FlushAsync(); } if (endStream) diff --git a/src/Kestrel.Core/Internal/HttpConnection.cs b/src/Kestrel.Core/Internal/HttpConnection.cs index c927017622..471d8194a2 100644 --- a/src/Kestrel.Core/Internal/HttpConnection.cs +++ b/src/Kestrel.Core/Internal/HttpConnection.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal private readonly TaskCompletionSource _socketClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); private IList _adaptedConnections; - private IPipeConnection _adaptedTransport; + private IDuplexPipe _adaptedTransport; private readonly object _protocolSelectionLock = new object(); private ProtocolSelectionState _protocolSelectionState = ProtocolSelectionState.Initializing; @@ -75,18 +75,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal ( pool: MemoryPool, readerScheduler: _context.ServiceContext.ThreadPool, - writerScheduler: Scheduler.Inline, - maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, - maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 + writerScheduler: PipeScheduler.Inline, + pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, + resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 ); internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions ( pool: MemoryPool, - readerScheduler: Scheduler.Inline, - writerScheduler: Scheduler.Inline, - maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, - maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 + readerScheduler: PipeScheduler.Inline, + writerScheduler: PipeScheduler.Inline, + pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, + resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 ); private IKestrelTrace Log => _context.ServiceContext.Log; @@ -196,13 +196,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal } // For testing only - internal void Initialize(IPipeConnection transport, IPipeConnection application) + internal void Initialize(IDuplexPipe transport, IDuplexPipe application) { _requestProcessor = _http1Connection = CreateHttp1Connection(transport, application); _protocolSelectionState = ProtocolSelectionState.Selected; } - private Http1Connection CreateHttp1Connection(IPipeConnection transport, IPipeConnection application) + private Http1Connection CreateHttp1Connection(IDuplexPipe transport, IDuplexPipe application) { 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 { diff --git a/src/Kestrel.Core/Internal/HttpConnectionContext.cs b/src/Kestrel.Core/Internal/HttpConnectionContext.cs index dcd5563e79..445d07a644 100644 --- a/src/Kestrel.Core/Internal/HttpConnectionContext.cs +++ b/src/Kestrel.Core/Internal/HttpConnectionContext.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal public MemoryPool MemoryPool { get; set; } public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; } - public IPipeConnection Transport { get; set; } - public IPipeConnection Application { get; set; } + public IDuplexPipe Transport { get; set; } + public IDuplexPipe Application { get; set; } } } diff --git a/src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs index 54375c3aaa..6fe8810a3f 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs @@ -2,12 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.IO.Pipelines; using System.Threading; 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 UnsafeRun(WaitCallback action, object state); diff --git a/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs index 1d90a7b681..70c90bd1ea 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs @@ -42,12 +42,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure public override void Run(Action action) { - ThreadPool.QueueUserWorkItem(_runAction, action); + System.Threading.ThreadPool.QueueUserWorkItem(_runAction, action); } public override void UnsafeRun(WaitCallback action, object state) { - ThreadPool.QueueUserWorkItem(action, state); + System.Threading.ThreadPool.QueueUserWorkItem(action, state); } public override void Schedule(Action action) diff --git a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs index 5af87f3293..98308725e6 100644 --- a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs +++ b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs @@ -98,13 +98,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal MemoryPool IConnectionTransportFeature.MemoryPool => MemoryPool; - IPipeConnection IConnectionTransportFeature.Transport + IDuplexPipe IConnectionTransportFeature.Transport { get => Transport; set => Transport = value; } - IPipeConnection IConnectionTransportFeature.Application + IDuplexPipe IConnectionTransportFeature.Application { get => Application; set => Application = value; diff --git a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs index 3889bff14f..bd5193738f 100644 --- a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs +++ b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs @@ -23,13 +23,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal public string ConnectionId { get; set; } public virtual MemoryPool MemoryPool { get; } - public virtual Scheduler InputWriterScheduler { get; } - public virtual Scheduler OutputReaderScheduler { get; } + public virtual PipeScheduler InputWriterScheduler { get; } + public virtual PipeScheduler OutputReaderScheduler { get; } - public IPipeConnection Transport { get; set; } - public IPipeConnection Application { get; set; } + public IDuplexPipe Transport { get; set; } + public IDuplexPipe Application { get; set; } - public IPipeWriter Input => Application.Output; - public IPipeReader Output => Application.Input; + public PipeWriter Input => Application.Output; + public PipeReader Output => Application.Input; } } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs index 35cbdf0771..a606d32f07 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs @@ -27,7 +27,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal private readonly UvStreamHandle _socket; - private WritableBuffer? _currentWritableBuffer; private MemoryHandle _bufferHandle; 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) { - Debug.Assert(_currentWritableBuffer == null); - var currentWritableBuffer = Input.Alloc(MinAllocBufferSize); - _currentWritableBuffer = currentWritableBuffer; + var currentWritableBuffer = Input.GetMemory(MinAllocBufferSize); + _bufferHandle = currentWritableBuffer.Retain(true); - _bufferHandle = currentWritableBuffer.Buffer.Retain(true); - - return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Buffer.Length); + return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Length); } 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. // http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb - Debug.Assert(_currentWritableBuffer != null); - _currentWritableBuffer.Value.Commit(); + Input.Commit(); } else if (status > 0) { Log.ConnectionRead(ConnectionId, status); - Debug.Assert(_currentWritableBuffer != null); - var currentWritableBuffer = _currentWritableBuffer.Value; - currentWritableBuffer.Advance(status); - var flushTask = currentWritableBuffer.FlushAsync(); + Input.Advance(status); + var flushTask = Input.FlushAsync(); if (!flushTask.IsCompleted) { @@ -149,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal else { // Given a negative status, it's possible that OnAlloc wasn't called. - _currentWritableBuffer?.Commit(); + Input.Commit(); _socket.ReadStop(); 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. - _currentWritableBuffer = null; _bufferHandle.Dispose(); } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs index be2ca1d255..075a57752c 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal public ListenerContext ListenerContext { get; set; } public override MemoryPool MemoryPool => ListenerContext.Thread.MemoryPool; - public override Scheduler InputWriterScheduler => ListenerContext.Thread; - public override Scheduler OutputReaderScheduler => ListenerContext.Thread; + public override PipeScheduler InputWriterScheduler => ListenerContext.Thread; + public override PipeScheduler OutputReaderScheduler => ListenerContext.Thread; } } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs index ccf1362b6f..298c333d05 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs @@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal private readonly UvStreamHandle _socket; private readonly string _connectionId; private readonly ILibuvTrace _log; - private readonly IPipeReader _pipe; + private readonly PipeReader _pipe; public LibuvOutputConsumer( - IPipeReader pipe, + PipeReader pipe, LibuvThread thread, UvStreamHandle socket, string connectionId, @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal } finally { - _pipe.Advance(consumed); + _pipe.AdvanceTo(consumed); } } } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs index ba4396fe32..db3682fe32 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; 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 // as completing a task may immediately have write data to put on the network diff --git a/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs b/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs index c25f2aec28..e720f2700c 100644 --- a/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs +++ b/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin _bufs = handle + requestSize; } - public LibuvAwaitable WriteAsync(UvStreamHandle handle, ReadOnlyBuffer buffer) + public LibuvAwaitable WriteAsync(UvStreamHandle handle, ReadOnlyBuffer buffer) { Write(handle, buffer, LibuvAwaitable.Callback, _awaitable); return _awaitable; @@ -63,14 +63,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin private unsafe void Write( UvStreamHandle handle, - ReadOnlyBuffer buffer, + ReadOnlyBuffer buffer, Action callback, object state) { try { var nBuffers = 0; - if (buffer.IsSingleSpan) + if (buffer.IsSingleSegment) { nBuffers = 1; } diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs index ff7c678cd7..cf128c05f3 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs @@ -52,8 +52,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal } public override MemoryPool MemoryPool { get; } - public override Scheduler InputWriterScheduler => Scheduler.Inline; - public override Scheduler OutputReaderScheduler => Scheduler.TaskRun; + public override PipeScheduler InputWriterScheduler => PipeScheduler.Inline; + public override PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool; public async Task StartAsync(IConnectionHandler connectionHandler) { @@ -96,11 +96,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal while (true) { // Ensure we have some reasonable amount of buffer space - var buffer = Input.Alloc(MinAllocBufferSize); + var buffer = Input.GetMemory(MinAllocBufferSize); try { - var bytesReceived = await _receiver.ReceiveAsync(buffer.Buffer); + var bytesReceived = await _receiver.ReceiveAsync(buffer); if (bytesReceived == 0) { @@ -109,14 +109,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal break; } - buffer.Advance(bytesReceived); + Input.Advance(bytesReceived); } finally { - buffer.Commit(); + Input.Commit(); } - var flushTask = buffer.FlushAsync(); + var flushTask = Input.FlushAsync(); if (!flushTask.IsCompleted) { @@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal } finally { - Output.Advance(buffer.End); + Output.AdvanceTo(buffer.End); } } } diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs b/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs index 8f5197f2ad..be71f3f9df 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs @@ -26,9 +26,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal _eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError); } - public SocketAwaitable SendAsync(ReadOnlyBuffer buffers) + public SocketAwaitable SendAsync(ReadOnlyBuffer buffers) { - if (buffers.IsSingleSpan) + if (buffers.IsSingleSegment) { return SendAsync(buffers.First); } @@ -75,10 +75,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal return _awaitable; } - private List> GetBufferList(ReadOnlyBuffer buffer) + private List> GetBufferList(ReadOnlyBuffer buffer) { Debug.Assert(!buffer.IsEmpty); - Debug.Assert(!buffer.IsSingleSpan); + Debug.Assert(!buffer.IsSingleSegment); if (_bufferList == null) { diff --git a/src/Protocols.Abstractions/ConnectionContext.cs b/src/Protocols.Abstractions/ConnectionContext.cs index afe2149576..f4fb2dbae9 100644 --- a/src/Protocols.Abstractions/ConnectionContext.cs +++ b/src/Protocols.Abstractions/ConnectionContext.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Protocols public abstract IFeatureCollection Features { get; } - public abstract IPipeConnection Transport { get; set; } + public abstract IDuplexPipe Transport { get; set; } public abstract MemoryPool MemoryPool { get; } } diff --git a/src/Protocols.Abstractions/DefaultConnectionContext.cs b/src/Protocols.Abstractions/DefaultConnectionContext.cs index 047ed92eab..18ac26c673 100644 --- a/src/Protocols.Abstractions/DefaultConnectionContext.cs +++ b/src/Protocols.Abstractions/DefaultConnectionContext.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Protocols public override MemoryPool MemoryPool => ConnectionTransportFeature.MemoryPool; - public override IPipeConnection Transport + public override IDuplexPipe Transport { get => ConnectionTransportFeature.Transport; set => ConnectionTransportFeature.Transport = value; diff --git a/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs b/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs index 2d7f3b5746..54e21226e4 100644 --- a/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs +++ b/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs @@ -8,12 +8,12 @@ namespace Microsoft.AspNetCore.Protocols.Features { 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; } } } diff --git a/src/Protocols.Abstractions/PipeConnection.cs b/src/Protocols.Abstractions/PipeConnection.cs index 31b3a7a74c..5b3ab2a50b 100644 --- a/src/Protocols.Abstractions/PipeConnection.cs +++ b/src/Protocols.Abstractions/PipeConnection.cs @@ -4,17 +4,17 @@ using System.Text; 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; Output = writer; } - public IPipeReader Input { get; } + public PipeReader Input { get; } - public IPipeWriter Output { get; } + public PipeWriter Output { get; } public void Dispose() { diff --git a/src/Protocols.Abstractions/PipeFactoryExtensions.cs b/src/Protocols.Abstractions/PipeFactoryExtensions.cs index e6b11e5654..01abf37428 100644 --- a/src/Protocols.Abstractions/PipeFactoryExtensions.cs +++ b/src/Protocols.Abstractions/PipeFactoryExtensions.cs @@ -4,12 +4,12 @@ namespace System.IO.Pipelines { 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)); } - 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 output = new Pipe(outputOptions); diff --git a/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs b/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs index 42264410db..13aabd72ad 100644 --- a/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs +++ b/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs @@ -1,9 +1,7 @@ -using System; -using System.Buffers; +using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; @@ -55,12 +53,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public MemoryPool MemoryPool { get; } = new MemoryPool(); - public IPipeConnection Transport { get; set; } - public IPipeConnection Application { get; set; } + public IDuplexPipe Transport { 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; } } diff --git a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs index 3c1eba171b..53f54e3a5e 100644 --- a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs @@ -28,14 +28,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { public class Http1ConnectionTests : IDisposable { - private readonly IPipeConnection _transport; - private readonly IPipeConnection _application; + private readonly IDuplexPipe _transport; + private readonly IDuplexPipe _application; private readonly TestHttp1Connection _http1Connection; private readonly ServiceContext _serviceContext; private readonly Http1ConnectionContext _http1ConnectionContext; private readonly MemoryPool _pipelineFactory; - private Position _consumed; - private Position _examined; + private SequencePosition _consumed; + private SequencePosition _examined; private Mock _timeoutControl; public Http1ConnectionTests() @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var exception = Assert.Throws(() => _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(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode); @@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var exception = Assert.Throws(() => _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(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode); @@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined); - _transport.Input.Advance(_consumed, _examined); + _transport.Input.AdvanceTo(_consumed, _examined); Assert.True(takeMessageHeaders); Assert.Equal(1, _http1Connection.RequestHeaders.Count); @@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests readableBuffer = (await _transport.Input.ReadAsync()).Buffer; takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined); - _transport.Input.Advance(_consumed, _examined); + _transport.Input.AdvanceTo(_consumed, _examined); Assert.True(takeMessageHeaders); 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 returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined); - _transport.Input.Advance(_consumed, _examined); + _transport.Input.AdvanceTo(_consumed, _examined); Assert.True(returnValue); Assert.Equal(expectedMethod, _http1Connection.Method); @@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var readableBuffer = (await _transport.Input.ReadAsync()).Buffer; var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined); - _transport.Input.Advance(_consumed, _examined); + _transport.Input.AdvanceTo(_consumed, _examined); Assert.True(returnValue); Assert.Equal(expectedRawTarget, _http1Connection.RawTarget); @@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("G")); _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; _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 exception = Assert.Throws(() => _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(StatusCodes.Status414UriTooLong, exception.StatusCode); @@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _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); } @@ -424,7 +424,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _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); } @@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _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); } @@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _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); } @@ -472,7 +472,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _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); } @@ -486,7 +486,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined)); - _transport.Input.Advance(_consumed, _examined); + _transport.Input.AdvanceTo(_consumed, _examined); Assert.Equal(405, exception.StatusCode); Assert.Equal(CoreStrings.BadRequest_MethodNotAllowed, exception.Message); @@ -685,7 +685,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var exception = Assert.Throws(() => _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(StatusCodes.Status400BadRequest, exception.StatusCode); diff --git a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs index a9976e08fb..462e7160e2 100644 --- a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs @@ -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 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 Http2ConnectionContext _connectionContext; private readonly Http2Connection _connection; @@ -2138,7 +2138,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private async Task SendAsync(ArraySegment span) { - var writableBuffer = _pair.Application.Output.Alloc(1); + var writableBuffer = _pair.Application.Output; writableBuffer.Write(span); await writableBuffer.FlushAsync(); } @@ -2466,7 +2466,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests } finally { - _pair.Application.Input.Advance(consumed, examined); + _pair.Application.Input.AdvanceTo(consumed, examined); } } } diff --git a/test/Kestrel.Core.Tests/HttpParserTests.cs b/test/Kestrel.Core.Tests/HttpParserTests.cs index 2a1d3dd142..48f3406533 100644 --- a/test/Kestrel.Core.Tests/HttpParserTests.cs +++ b/test/Kestrel.Core.Tests/HttpParserTests.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests string expectedVersion) { var parser = CreateParser(Mock.Of()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); 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.RawPath, expectedRawPath); Assert.Equal(requestHandler.Version, expectedVersion); - Assert.Equal(buffer.End, consumed); - Assert.Equal(buffer.End, examined); + Assert.True(buffer.Slice(consumed).IsEmpty); + Assert.True(buffer.Slice(examined).IsEmpty); } [Theory] @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine) { var parser = CreateParser(Mock.Of()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); 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) { var parser = CreateParser(Mock.Of()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); Assert.Equal(buffer.Start, consumed); - Assert.Equal(buffer.End, examined); + Assert.True(buffer.Slice(examined).IsEmpty); } [Theory] @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests .Returns(true); var parser = CreateParser(mockTrace.Object); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); var exception = Assert.Throws(() => @@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests .Returns(true); var parser = CreateParser(mockTrace.Object); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); var exception = Assert.Throws(() => @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests .Returns(true); var parser = CreateParser(mockTrace.Object); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); var exception = Assert.Throws(() => @@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { var parser = CreateParser(Mock.Of()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); 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()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); - Assert.Equal(buffer.Start, consumed); - Assert.Equal(buffer.End, examined); + Assert.Equal(buffer.Length, buffer.Slice(consumed).Length); + Assert.True(buffer.Slice(examined).IsEmpty); Assert.Equal(0, consumedBytes); } @@ -294,19 +294,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var parser = CreateParser(Mock.Of()); const string headerLine = "Header: value\r\n\r"; - var buffer1 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(headerLine)); + var buffer1 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(headerLine)); var requestHandler = new RequestHandler(); 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(headerLine.Length - 1, consumedBytes); - var buffer2 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("\r\n")); + var buffer2 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("\r\n")); Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes)); - Assert.Equal(buffer2.End, consumed); - Assert.Equal(buffer2.End, examined); + Assert.True(buffer2.Slice(consumed).IsEmpty); + Assert.True(buffer2.Slice(examined).IsEmpty); Assert.Equal(2, consumedBytes); } @@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests .Returns(true); var parser = CreateParser(mockTrace.Object); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); var exception = Assert.Throws(() => @@ -341,7 +341,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var parser = CreateParser(mockTrace.Object); // Invalid request line - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n")); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n")); var requestHandler = new RequestHandler(); var exception = Assert.Throws(() => @@ -351,7 +351,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode); // Unrecognized HTTP version - buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n")); + buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n")); exception = Assert.Throws(() => 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); // Invalid request header - buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("Header: value\n\r\n")); + buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("Header: value\n\r\n")); exception = Assert.Throws(() => 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) { var parser = CreateParser(Mock.Of()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); var requestHandler = new RequestHandler(); 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.Equal(headerName, pairs[0].Key); Assert.Equal(expectedHeaderValue, pairs[0].Value); - Assert.Equal(buffer.End, consumed); - Assert.Equal(buffer.End, examined); + Assert.True(buffer.Slice(consumed).IsEmpty); + Assert.True(buffer.Slice(examined).IsEmpty); } private void VerifyRawHeaders(string rawHeaders, IEnumerable expectedHeaderNames, IEnumerable 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"); var parser = CreateParser(Mock.Of()); - var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); + var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); 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, parsedHeaders.Select(t => t.Key)); Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value)); - Assert.Equal(buffer.End, consumed); - Assert.Equal(buffer.End, examined); + Assert.True(buffer.Slice(consumed).IsEmpty); + Assert.True(buffer.Slice(examined).IsEmpty); } private IHttpParser CreateParser(IKestrelTrace log) => new HttpParser(log.IsEnabled(LogLevel.Information)); diff --git a/test/Kestrel.Core.Tests/MessageBodyTests.cs b/test/Kestrel.Core.Tests/MessageBodyTests.cs index 9fa5b6ef1a..148fb56630 100644 --- a/test/Kestrel.Core.Tests/MessageBodyTests.cs +++ b/test/Kestrel.Core.Tests/MessageBodyTests.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; 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, // so no need to bounds check in this test. var bytes = Encoding.ASCII.GetBytes(data[0]); - var buffer = input.Application.Output.Alloc(2048); + var buffer = input.Application.Output.GetMemory(2028); ArraySegment 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.Advance(bytes.Length); - await buffer.FlushAsync(); + input.Application.Output.Advance(bytes.Length); + await input.Application.Output.FlushAsync(); // Verify the block passed to WriteAsync is the same one incoming data was written into. Assert.Same(block.Array, await writeTcs.Task); writeTcs = new TaskCompletionSource(); bytes = Encoding.ASCII.GetBytes(data[1]); - buffer = input.Application.Output.Alloc(2048); - Assert.True(buffer.Buffer.TryGetArray(out block)); + buffer = input.Application.Output.GetMemory(2048); + Assert.True(MemoryMarshal.TryGetArray(buffer, out block)); Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length); - buffer.Advance(bytes.Length); - await buffer.FlushAsync(); + input.Application.Output.Advance(bytes.Length); + await input.Application.Output.FlushAsync(); Assert.Same(block.Array, await writeTcs.Task); diff --git a/test/Kestrel.Core.Tests/OutputProducerTests.cs b/test/Kestrel.Core.Tests/OutputProducerTests.cs index 71a4b7712b..8c489537ec 100644 --- a/test/Kestrel.Core.Tests/OutputProducerTests.cs +++ b/test/Kestrel.Core.Tests/OutputProducerTests.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var pipeOptions = new PipeOptions ( pool: _memoryPool, - readerScheduler: Mock.Of() + readerScheduler: Mock.Of() ); using (var socketOutput = CreateOutputProducer(pipeOptions)) diff --git a/test/Kestrel.Core.Tests/PipeOptionsTests.cs b/test/Kestrel.Core.Tests/PipeOptionsTests.cs index 397fbdbbc8..519c266d5b 100644 --- a/test/Kestrel.Core.Tests/PipeOptionsTests.cs +++ b/test/Kestrel.Core.Tests/PipeOptionsTests.cs @@ -26,11 +26,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests serviceContext.ServerOptions.Limits.MaxResponseBufferSize = maxResponseBufferSize; serviceContext.ThreadPool = new LoggingThreadPool(null); - var mockScheduler = Mock.Of(); + var mockScheduler = Mock.Of(); var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler); - Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.MaximumSizeLow); - Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.MaximumSizeHigh); + Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.ResumeWriterThreshold); + Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.PauseWriterThreshold); Assert.Same(mockScheduler, outputPipeOptions.ReaderScheduler); Assert.Same(serviceContext.ThreadPool, outputPipeOptions.WriterScheduler); } @@ -44,11 +44,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize; serviceContext.ThreadPool = new LoggingThreadPool(null); - var mockScheduler = Mock.Of(); + var mockScheduler = Mock.Of(); var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler); - Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.MaximumSizeLow); - Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.MaximumSizeHigh); + Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.ResumeWriterThreshold); + Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.PauseWriterThreshold); Assert.Same(serviceContext.ThreadPool, inputPipeOptions.ReaderScheduler); Assert.Same(mockScheduler, inputPipeOptions.WriterScheduler); } @@ -66,10 +66,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests ServiceContext = serviceContext }); - Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeLow); - Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeHigh); + Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.ResumeWriterThreshold); + Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.PauseWriterThreshold); Assert.Same(serviceContext.ThreadPool, connectionLifetime.AdaptedInputPipeOptions.ReaderScheduler); - Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler); + Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler); } [Theory] @@ -85,10 +85,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests ServiceContext = serviceContext }); - Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeLow); - Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeHigh); - Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler); - Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler); + Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.ResumeWriterThreshold); + Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.PauseWriterThreshold); + Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler); + Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler); } } } diff --git a/test/Kestrel.Core.Tests/PipelineExtensionTests.cs b/test/Kestrel.Core.Tests/PipelineExtensionTests.cs index 00cc9d1c2e..286dff7cbe 100644 --- a/test/Kestrel.Core.Tests/PipelineExtensionTests.cs +++ b/test/Kestrel.Core.Tests/PipelineExtensionTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // ulong.MaxValue.ToString().Length private const int _ulongMaxValueLength = 20; - private readonly IPipe _pipe; + private readonly Pipe _pipe; private readonly MemoryPool _memoryPool = new MemoryPool(); public PipelineExtensionTests() @@ -34,8 +34,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData(4_8_15_16_23_42)] public void WritesNumericToAscii(ulong number) { - var writerBuffer = _pipe.Writer.Alloc(); - var writer = new WritableBufferWriter(writerBuffer); + var writerBuffer = _pipe.Writer; + var writer = OutputWriter.Create(writerBuffer); writer.WriteNumeric(number); writerBuffer.FlushAsync().GetAwaiter().GetResult(); @@ -51,8 +51,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData(_ulongMaxValueLength - 1)] public void WritesNumericAcrossSpanBoundaries(int gapSize) { - var writerBuffer = _pipe.Writer.Alloc(100); - var writer = new WritableBufferWriter(writerBuffer); + var writerBuffer = _pipe.Writer; + var writer = OutputWriter.Create(writerBuffer); // almost fill up the first block var spacer = new byte[writer.Span.Length - gapSize]; writer.Write(spacer); @@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); var numAsString = ulong.MaxValue.ToString(); 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()); } @@ -82,8 +82,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData(null, new byte[0])] public void EncodesAsAscii(string input, byte[] expected) { - var writerBuffer = _pipe.Writer.Alloc(); - var writer = new WritableBufferWriter(writerBuffer); + var writerBuffer = _pipe.Writer; + var writer = OutputWriter.Create(writerBuffer); writer.WriteAsciiNoValidation(input); writerBuffer.FlushAsync().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 // but it shouldn't produce more than one byte per character - var writerBuffer = _pipe.Writer.Alloc(); - var writer = new WritableBufferWriter(writerBuffer); + var writerBuffer = _pipe.Writer; + var writer = OutputWriter.Create(writerBuffer); writer.WriteAsciiNoValidation(input); writerBuffer.FlushAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); @@ -122,8 +122,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void WriteAsciiNoValidation() { const byte maxAscii = 0x7f; - var writerBuffer = _pipe.Writer.Alloc(); - var writer = new WritableBufferWriter(writerBuffer); + var writerBuffer = _pipe.Writer; + var writer = OutputWriter.Create(writerBuffer); for (var i = 0; i < maxAscii; i++) { 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) { var testString = new string(' ', stringLength); - var writerBuffer = _pipe.Writer.Alloc(100); - var writer = new WritableBufferWriter(writerBuffer); + var writerBuffer = _pipe.Writer; + var writer = OutputWriter.Create(writerBuffer); // almost fill up the first block var spacer = new byte[writer.Span.Length - gapSize]; writer.Write(spacer); @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); 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()); } } diff --git a/test/Kestrel.Core.Tests/TestInput.cs b/test/Kestrel.Core.Tests/TestInput.cs index ba644e4bf8..6153e8d2a5 100644 --- a/test/Kestrel.Core.Tests/TestInput.cs +++ b/test/Kestrel.Core.Tests/TestInput.cs @@ -38,9 +38,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Http1Connection.HttpResponseControl = Mock.Of(); } - public IPipeConnection Transport { get; } + public IDuplexPipe Transport { get; } - public IPipeConnection Application { get; } + public IDuplexPipe Application { get; } public Http1ConnectionContext Http1ConnectionContext { get; } diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs index 4c79bddf19..2dfc7a1ad4 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs @@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests mockConnectionHandler.InputOptions = pool => new PipeOptions( pool: pool, - maximumSizeHigh: 3); + pauseWriterThreshold: 3); // 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 transport = new LibuvTransport(mockLibuv, transportContext, null); var thread = new LibuvThread(transport); - var mockScheduler = new Mock(); + var mockScheduler = new Mock(); Action backPressure = null; mockScheduler.Setup(m => m.Schedule(It.IsAny())).Callback(a => { @@ -126,8 +126,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests mockConnectionHandler.InputOptions = pool => new PipeOptions( pool: pool, - maximumSizeHigh: 3, - maximumSizeLow: 3, + pauseWriterThreshold: 3, + resumeWriterThreshold: 3, writerScheduler: mockScheduler.Object); 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(); // Calling advance will call into our custom scheduler that captures the back pressure // callback - mockConnectionHandler.Input.Reader.Advance(result.Buffer.End); + mockConnectionHandler.Input.Reader.AdvanceTo(result.Buffer.End); // Cancel the current pending flush mockConnectionHandler.Input.Writer.CancelPendingFlush(); diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs index 06576890d4..36554bb133 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs @@ -60,14 +60,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests // SocketOutput, the write callback would never be invoked for writes larger than // 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. var pipeOptions = new PipeOptions ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize ?? 0, - maximumSizeLow: maxResponseBufferSize ?? 0 + pauseWriterThreshold: maxResponseBufferSize ?? 0, + resumeWriterThreshold: maxResponseBufferSize ?? 0 ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -96,14 +96,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests 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. var pipeOptions = new PipeOptions ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: 0, - maximumSizeLow: 0 + pauseWriterThreshold: 0, + resumeWriterThreshold: 0 ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -144,14 +144,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests 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. var pipeOptions = new PipeOptions ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: 1, - maximumSizeLow: 1 + pauseWriterThreshold: 1, + resumeWriterThreshold: 1 ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -206,8 +206,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize, - maximumSizeLow: maxResponseBufferSize + pauseWriterThreshold: maxResponseBufferSize, + resumeWriterThreshold: maxResponseBufferSize ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -270,8 +270,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize, - maximumSizeLow: maxResponseBufferSize + pauseWriterThreshold: maxResponseBufferSize, + resumeWriterThreshold: maxResponseBufferSize ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -340,8 +340,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize, - maximumSizeLow: maxResponseBufferSize + pauseWriterThreshold: maxResponseBufferSize, + resumeWriterThreshold: maxResponseBufferSize ); using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource)) @@ -433,8 +433,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize, - maximumSizeLow: maxResponseBufferSize + pauseWriterThreshold: maxResponseBufferSize, + resumeWriterThreshold: maxResponseBufferSize ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -517,8 +517,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize, - maximumSizeLow: maxResponseBufferSize + pauseWriterThreshold: maxResponseBufferSize, + resumeWriterThreshold: maxResponseBufferSize ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -599,8 +599,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize, - maximumSizeLow: maxResponseBufferSize + pauseWriterThreshold: maxResponseBufferSize, + resumeWriterThreshold: maxResponseBufferSize ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -654,14 +654,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests 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. var pipeOptions = new PipeOptions ( pool: _memoryPool, readerScheduler: _libuvThread, - maximumSizeHigh: maxResponseBufferSize ?? 0, - maximumSizeLow: maxResponseBufferSize ?? 0 + pauseWriterThreshold: maxResponseBufferSize ?? 0, + resumeWriterThreshold: maxResponseBufferSize ?? 0 ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -728,7 +728,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests 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. try diff --git a/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs b/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs index 001b4343e1..e5972077c9 100644 --- a/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests await writeRequest.WriteAsync( serverConnectionPipe, - new ReadOnlyBuffer(new byte[] { 1, 2, 3, 4 })); + new ReadOnlyBuffer(new byte[] { 1, 2, 3, 4 })); writeRequest.Dispose(); serverConnectionPipe.Dispose(); diff --git a/test/Kestrel.Transport.Libuv.Tests/NetworkingTests.cs b/test/Kestrel.Transport.Libuv.Tests/NetworkingTests.cs index dfe9681a0b..bf25af4392 100644 --- a/test/Kestrel.Transport.Libuv.Tests/NetworkingTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/NetworkingTests.cs @@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests { var req = new UvWriteReq(_logger); req.DangerousInit(loop); - var block = new ReadOnlyBuffer(new byte[] { 65, 66, 67, 68, 69 }); + var block = new ReadOnlyBuffer(new byte[] { 65, 66, 67, 68, 69 }); await req.WriteAsync( tcp2, diff --git a/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs b/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs index 1efb0bedab..d52a868b67 100644 --- a/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs +++ b/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers feature.Application = new PipeConnection(Output.Reader, Input.Writer); } - public IPipe Input { get; private set; } - public IPipe Output { get; private set; } + public Pipe Input { get; private set; } + public Pipe Output { get; private set; } } } diff --git a/tools/CodeGenerator/CodeGenerator.csproj b/tools/CodeGenerator/CodeGenerator.csproj index e7cf3a993f..c85676e21d 100644 --- a/tools/CodeGenerator/CodeGenerator.csproj +++ b/tools/CodeGenerator/CodeGenerator.csproj @@ -7,9 +7,6 @@ true - - - diff --git a/tools/CodeGenerator/HttpProtocolFeatureCollection.cs b/tools/CodeGenerator/HttpProtocolFeatureCollection.cs index 6582f445e9..b960180f26 100644 --- a/tools/CodeGenerator/HttpProtocolFeatureCollection.cs +++ b/tools/CodeGenerator/HttpProtocolFeatureCollection.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.AspNetCore.Server.Kestrel.Core.Features; +//using Microsoft.AspNetCore.Server.Kestrel.Core.Features; namespace CodeGenerator { @@ -23,39 +23,39 @@ namespace CodeGenerator { var alwaysFeatures = new[] { - typeof(IHttpRequestFeature), - typeof(IHttpResponseFeature), - typeof(IHttpRequestIdentifierFeature), - typeof(IServiceProvidersFeature), - typeof(IHttpRequestLifetimeFeature), - typeof(IHttpConnectionFeature), + "IHttpRequestFeature", + "IHttpResponseFeature", + "IHttpRequestIdentifierFeature", + "IServiceProvidersFeature", + "IHttpRequestLifetimeFeature", + "IHttpConnectionFeature", }; var commonFeatures = new[] { - typeof(IHttpAuthenticationFeature), - typeof(IQueryFeature), - typeof(IFormFeature), + "IHttpAuthenticationFeature", + "IQueryFeature", + "IFormFeature", }; var sometimesFeatures = new[] { - typeof(IHttpUpgradeFeature), - typeof(IHttp2StreamIdFeature), - typeof(IResponseCookiesFeature), - typeof(IItemsFeature), - typeof(ITlsConnectionFeature), - typeof(IHttpWebSocketFeature), - typeof(ISessionFeature), - typeof(IHttpMaxRequestBodySizeFeature), - typeof(IHttpMinRequestBodyDataRateFeature), - typeof(IHttpMinResponseDataRateFeature), - typeof(IHttpBodyControlFeature), + "IHttpUpgradeFeature", + "IHttp2StreamIdFeature", + "IResponseCookiesFeature", + "IItemsFeature", + "ITlsConnectionFeature", + "IHttpWebSocketFeature", + "ISessionFeature", + "IHttpMaxRequestBodySizeFeature", + "IHttpMinRequestBodyDataRateFeature", + "IHttpMinResponseDataRateFeature", + "IHttpBodyControlFeature", }; var rareFeatures = new[] { - typeof(IHttpSendFileFeature), + "IHttpSendFileFeature", }; var allFeatures = alwaysFeatures.Concat(commonFeatures).Concat(sometimesFeatures).Concat(rareFeatures); @@ -64,15 +64,15 @@ namespace CodeGenerator // See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs var implementedFeatures = new[] { - typeof(IHttpRequestFeature), - typeof(IHttpResponseFeature), - typeof(IHttpRequestIdentifierFeature), - typeof(IHttpRequestLifetimeFeature), - typeof(IHttpConnectionFeature), - typeof(IHttpMaxRequestBodySizeFeature), - typeof(IHttpMinRequestBodyDataRateFeature), - typeof(IHttpMinResponseDataRateFeature), - typeof(IHttpBodyControlFeature), + "IHttpRequestFeature", + "IHttpResponseFeature", + "IHttpRequestIdentifierFeature", + "IHttpRequestLifetimeFeature", + "IHttpConnectionFeature", + "IHttpMaxRequestBodySizeFeature", + "IHttpMinRequestBodyDataRateFeature", + "IHttpMinResponseDataRateFeature", + "IHttpBodyControlFeature", }; return $@"// Copyright (c) .NET Foundation. All rights reserved. @@ -81,26 +81,30 @@ namespace CodeGenerator using System; 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 {{ public partial class {className} {{{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 => $@" - private object _current{feature.Name};")} + private object _current{feature};")} private void FastReset() {{{Each(implementedFeatures, feature => $@" - _current{feature.Name} = this;")} + _current{feature} = this;")} {Each(allFeatures.Where(f => !implementedFeatures.Contains(f)), feature => $@" - _current{feature.Name} = null;")} + _current{feature} = null;")} }} internal object FastFeatureGet(Type key) {{{Each(allFeatures, feature => $@" - if (key == {feature.Name}Type) + if (key == {feature}Type) {{ - return _current{feature.Name}; + return _current{feature}; }}")} return ExtraFeatureGet(key); }} @@ -109,9 +113,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http {{ _featureRevision++; {Each(allFeatures, feature => $@" - if (key == {feature.Name}Type) + if (key == {feature}Type) {{ - _current{feature.Name} = feature; + _current{feature} = feature; return; }}")}; ExtraFeatureSet(key, feature); @@ -119,9 +123,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private IEnumerable> FastEnumerable() {{{Each(allFeatures, feature => $@" - if (_current{feature.Name} != null) + if (_current{feature} != null) {{ - yield return new KeyValuePair({feature.Name}Type, _current{feature.Name} as global::{feature.FullName}); + yield return new KeyValuePair({feature}Type, _current{feature} as {feature}); }}")} if (MaybeExtra != null) diff --git a/tools/CodeGenerator/HttpUtilities/HttpUtilities.cs b/tools/CodeGenerator/HttpUtilities/HttpUtilities.cs index 4d8c2ca922..7263d1fd16 100644 --- a/tools/CodeGenerator/HttpUtilities/HttpUtilities.cs +++ b/tools/CodeGenerator/HttpUtilities/HttpUtilities.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; namespace CodeGenerator.HttpUtilities { @@ -17,27 +16,27 @@ namespace CodeGenerator.HttpUtilities { var httpMethods = new [] { - new Tuple("CONNECT ", HttpMethod.Connect), - new Tuple("DELETE ", HttpMethod.Delete), - new Tuple("HEAD ", HttpMethod.Head), - new Tuple("PATCH ", HttpMethod.Patch), - new Tuple("POST ", HttpMethod.Post), - new Tuple("PUT ", HttpMethod.Put), - new Tuple("OPTIONS ", HttpMethod.Options), - new Tuple("TRACE ", HttpMethod.Trace), - new Tuple("GET ", HttpMethod.Get) + new Tuple("CONNECT ", "Connect"), + new Tuple("DELETE ", "Delete"), + new Tuple("HEAD ", "Head"), + new Tuple("PATCH ", "Patch"), + new Tuple("POST ", "Post"), + new Tuple("PUT ", "Put"), + new Tuple("OPTIONS ", "Options"), + new Tuple("TRACE ", "Trace"), + new Tuple("GET ", "Get") }; return GenerateFile(httpMethods); } - private static string GenerateFile(Tuple[] httpMethods) + private static string GenerateFile(Tuple[] httpMethods) { var maskLength = (byte)Math.Ceiling(Math.Log(httpMethods.Length, 2)); 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(); @@ -158,7 +157,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure var maskFieldName = GetMaskFieldName(methodInfo.MaskLength); 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) { @@ -181,7 +180,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure { 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) { @@ -281,7 +280,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure public int MaskLength; } - private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple method) + private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple method) { var methodString = GetMethodString(method.Item1); diff --git a/tools/CodeGenerator/KnownHeaders.cs b/tools/CodeGenerator/KnownHeaders.cs index 89a66fc2ac..8571143b3f 100644 --- a/tools/CodeGenerator/KnownHeaders.cs +++ b/tools/CodeGenerator/KnownHeaders.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; namespace CodeGenerator { @@ -266,14 +265,14 @@ namespace CodeGenerator { Headers = requestHeaders, HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length), - ClassName = nameof(HttpRequestHeaders), + ClassName = "HttpRequestHeaders", Bytes = default(byte[]) }, new { Headers = responseHeaders, HeadersByLength = responseHeaders.GroupBy(x => x.Name.Length), - ClassName = nameof(HttpResponseHeaders), + ClassName = "HttpResponseHeaders", Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray() } }; @@ -293,6 +292,7 @@ namespace CodeGenerator using System; using System.Collections.Generic; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; +using System.Buffers; using System.IO.Pipelines; using Microsoft.Extensions.Primitives; 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) - {{{(loop.ClassName == nameof(HttpResponseHeaders) ? @" + {{{(loop.ClassName == "HttpResponseHeaders" ? @" ValidateHeaderCharacters(value);" : "")} switch (key.Length) {{{Each(loop.HeadersByLength, byLength => $@" @@ -406,7 +406,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http }} protected override bool AddValueFast(string key, StringValues value) - {{{(loop.ClassName == nameof(HttpResponseHeaders) ? @" + {{{(loop.ClassName == "HttpResponseHeaders" ? @" ValidateHeaderCharacters(value);" : "")} switch (key.Length) {{{Each(loop.HeadersByLength, byLength => $@" @@ -432,7 +432,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http }} break;")} }} -{(loop.ClassName == nameof(HttpResponseHeaders) ? @" +{(loop.ClassName == "HttpResponseHeaders" ? @" ValidateHeaderCharacters(key);" : "")} Unknown.Add(key, value); // Return true, above will throw and exit for false @@ -522,8 +522,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return true; }} - {(loop.ClassName == nameof(HttpResponseHeaders) ? $@" - protected void CopyToFast(ref WritableBufferWriter output) + {(loop.ClassName == "HttpResponseHeaders" ? $@" + protected void CopyToFast(ref OutputWriter output) {{ var tempBits = _bits | (_contentLength.HasValue ? {1L << 63}L : 0); {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]; if (value != null) {{ - output.Write(_headerBytes, {header.BytesOffset}, {header.BytesCount}); + output.Write(new ReadOnlySpan(_headerBytes, {header.BytesOffset}, {header.BytesCount})); PipelineExtensions.WriteAsciiNoValidation(ref output, value); }} }} @@ -555,7 +555,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http }}{(header.Identifier == "Server" ? $@" 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(_headerBytes, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesOffset}, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesCount})); PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value); if((tempBits & ~{1L << 63}L) == 0) @@ -565,7 +565,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http tempBits &= ~{1L << 63}L; }}" : "")}")} }}" : "")} - {(loop.ClassName == nameof(HttpRequestHeaders) ? $@" + {(loop.ClassName == "HttpRequestHeaders" ? $@" public unsafe void Append(byte* pKeyBytes, int keyLength, string value) {{ var pUB = pKeyBytes; diff --git a/tools/CodeGenerator/Program.cs b/tools/CodeGenerator/Program.cs index 1d8596890e..a7870adec4 100644 --- a/tools/CodeGenerator/Program.cs +++ b/tools/CodeGenerator/Program.cs @@ -3,8 +3,6 @@ using System; using System.IO; -using Microsoft.AspNetCore.Server.Kestrel.Core.Features; -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; namespace CodeGenerator { @@ -36,7 +34,7 @@ namespace CodeGenerator public static void Run(string knownHeadersPath, string httpProtocolFeatureCollectionPath, string httpUtilitiesPath) { var knownHeadersContent = KnownHeaders.GeneratedFile(); - var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile(nameof(HttpProtocol)); + var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile("HttpProtocol"); var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile(); var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";