From 1fa001e7db3d7eb93d42f7e0ef4c6c114a831d64 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 4 Jan 2018 09:54:42 -0800 Subject: [PATCH] React to pipeline changes (#2234) React to pipeline changes --- ...Http1ConnectionParsingOverheadBenchmark.cs | 2 +- .../HttpParserBenchmark.cs | 5 +- .../Kestrel.Performance/Mocks/NullParser.cs | 6 ++- build/dependencies.props | 21 ++++---- .../Adapter/Internal/AdaptedPipeline.cs | 1 + .../Internal/ConnectionHandler.cs | 4 +- .../Internal/Http/Http1Connection.cs | 11 +++-- .../Internal/Http/Http1MessageBody.cs | 44 +++++++++-------- .../Internal/Http/Http1OutputProducer.cs | 2 +- src/Kestrel.Core/Internal/Http/HttpParser.cs | 20 ++++---- .../Internal/Http/HttpProtocol.cs | 4 +- src/Kestrel.Core/Internal/Http/IHttpParser.cs | 8 ++-- .../Internal/Http/PipelineExtensions.cs | 12 ++++- .../Internal/Http2/Http2Connection.cs | 4 +- .../Internal/Http2/Http2FrameReader.cs | 4 +- src/Kestrel.Core/Internal/HttpConnection.cs | 6 +-- .../Infrastructure/InlineLoggingThreadPool.cs | 13 +++-- .../{IThreadPool.cs => KestrelThreadPool.cs} | 6 +-- .../Infrastructure/LoggingThreadPool.cs | 13 +++-- src/Kestrel.Core/Internal/ServiceContext.cs | 2 +- src/Kestrel.Core/KestrelServer.cs | 2 +- .../Internal/TransportConnection.cs | 4 +- .../Internal/LibuvConnection.cs | 3 +- .../Internal/LibuvConnectionContext.cs | 4 +- .../Internal/LibuvThread.cs | 9 +++- .../Internal/Networking/UvWriteReq.cs | 4 +- .../Internal/BufferExtensions.cs | 15 ++++-- .../Internal/SocketConnection.cs | 4 +- .../Internal/SocketSender.cs | 12 +++-- .../Features/IConnectionTransportFeature.cs | 4 +- .../ConnectionHandlerTests.cs | 4 +- .../Http1ConnectionTests.cs | 5 +- test/Kestrel.Core.Tests/HttpParserTests.cs | 48 +++++++------------ .../Kestrel.Core.Tests/OutputProducerTests.cs | 2 +- test/Kestrel.Core.Tests/PipeOptionsTests.cs | 10 ++-- .../LibuvConnectionTests.cs | 6 +-- .../MultipleLoopTests.cs | 3 +- .../NetworkingTests.cs | 3 +- 38 files changed, 187 insertions(+), 143 deletions(-) rename src/Kestrel.Core/Internal/Infrastructure/{IThreadPool.cs => KestrelThreadPool.cs} (64%) diff --git a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs index 4747c696ee..f3ef888b9a 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 ReadableBuffer _buffer; + public ReadOnlyBuffer _buffer; public Http1Connection _http1Connection; [IterationSetup] diff --git a/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs b/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs index 429dc358e7..4d63b75b91 100644 --- a/benchmarks/Kestrel.Performance/HttpParserBenchmark.cs +++ b/benchmarks/Kestrel.Performance/HttpParserBenchmark.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 BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { private readonly HttpParser _parser = new HttpParser(); - private ReadableBuffer _buffer; + private ReadOnlyBuffer _buffer; [Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)] public void PlaintextTechEmpower() @@ -46,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private void InsertData(byte[] data) { - _buffer = ReadableBuffer.Create(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 e9380cda77..f091f67320 100644 --- a/benchmarks/Kestrel.Performance/Mocks/NullParser.cs +++ b/benchmarks/Kestrel.Performance/Mocks/NullParser.cs @@ -2,6 +2,8 @@ // 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.Sequences; using System.IO.Pipelines; using System.Text; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; @@ -21,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public static readonly NullParser Instance = new NullParser(); - public bool ParseHeaders(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) + public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes) { handler.OnHeader(new Span(_hostHeaderName), new Span(_hostHeaderValue)); handler.OnHeader(new Span(_acceptHeaderName), new Span(_acceptHeaderValue)); @@ -34,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance return true; } - public bool ParseRequestLine(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined) { handler.OnStartLine(HttpMethod.Get, HttpVersion.Http11, diff --git a/build/dependencies.props b/build/dependencies.props index 8693cc95ac..e0c9c9a59b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -25,20 +25,21 @@ 2.1.0-preview1-27965 2.1.0-preview1-27965 2.0.0 - 2.1.0-preview1-26016-05 + 2.1.0-preview1-26102-01 2.1.0-preview1-27965 15.3.0 4.7.49 10.0.1 - 4.5.0-preview1-26016-05 - 0.1.0-e171215-1 - 0.1.0-e171215-1 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 - 0.1.0-e171215-1 - 4.5.0-preview2-25707-02 + 4.5.0-preview1-26102-01 + 0.1.0-e180104-2 + 0.1.0-e180104-2 + 0.1.0-e180104-2 + 4.5.0-preview1-26102-01 + 4.5.0-preview1-26102-01 + 4.5.0-preview1-26102-01 + 4.5.0-preview1-26102-01 + 0.1.0-e180104-2 + 4.5.0-preview1-26102-01 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 72c1780d08..43526c8243 100644 --- a/src/Kestrel.Core/Adapter/Internal/AdaptedPipeline.cs +++ b/src/Kestrel.Core/Adapter/Internal/AdaptedPipeline.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using System.IO.Pipelines; +using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal { diff --git a/src/Kestrel.Core/Internal/ConnectionHandler.cs b/src/Kestrel.Core/Internal/ConnectionHandler.cs index ee49a5b239..d968fce78c 100644 --- a/src/Kestrel.Core/Internal/ConnectionHandler.cs +++ b/src/Kestrel.Core/Internal/ConnectionHandler.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal } // Internal for testing - internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, IScheduler writerScheduler) => new PipeOptions + internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, Scheduler writerScheduler) => new PipeOptions ( pool: memoryPool, readerScheduler: serviceContext.ThreadPool, @@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal maximumSizeLow: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 ); - internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, IScheduler readerScheduler) => new PipeOptions + internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, Scheduler readerScheduler) => new PipeOptions ( pool: memoryPool, readerScheduler: readerScheduler, diff --git a/src/Kestrel.Core/Internal/Http/Http1Connection.cs b/src/Kestrel.Core/Internal/Http/Http1Connection.cs index 5168bf7d61..84890c4137 100644 --- a/src/Kestrel.Core/Internal/Http/Http1Connection.cs +++ b/src/Kestrel.Core/Internal/Http/Http1Connection.cs @@ -2,11 +2,14 @@ // 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.Sequences; using System.Diagnostics; using System.IO.Pipelines; using System.Runtime.InteropServices; using System.Text; using System.Text.Encodings.Web.Utf8; +using System.Threading; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; @@ -66,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http Input.CancelPendingRead(); } - public void ParseRequest(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + public void ParseRequest(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { consumed = buffer.Start; examined = buffer.End; @@ -104,7 +107,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } } - public bool TakeStartLine(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + public bool TakeStartLine(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { var overLength = false; if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize) @@ -122,7 +125,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return result; } - public bool TakeMessageHeaders(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + public bool TakeMessageHeaders(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { // Make sure the buffer is limited bool overLength = false; @@ -424,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutAction.StopProcessingNextRequest); } - protected override bool BeginRead(out ReadableBufferAwaitable awaitable) + protected override bool BeginRead(out ValueAwaiter awaitable) { awaitable = Input.ReadAsync(); return true; diff --git a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs index 9b50aba2e3..e75f7e7255 100644 --- a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs +++ b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs @@ -2,6 +2,8 @@ // 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.Sequences; using System.IO; using System.IO.Pipelines; using System.Threading.Tasks; @@ -149,7 +151,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } } - protected void Copy(ReadableBuffer readableBuffer, WritableBuffer writableBuffer) + protected void Copy(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer) { _context.TimeoutControl.BytesRead(readableBuffer.Length); @@ -171,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _pumpTask = PumpAsync(); } - protected virtual bool Read(ReadableBuffer readableBuffer, WritableBuffer writableBuffer, out ReadCursor consumed, out ReadCursor examined) + protected virtual bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { throw new NotImplementedException(); } @@ -296,7 +298,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http RequestUpgrade = true; } - protected override bool Read(ReadableBuffer readableBuffer, WritableBuffer writableBuffer, out ReadCursor consumed, out ReadCursor examined) + protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { Copy(readableBuffer, writableBuffer); consumed = readableBuffer.End; @@ -318,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _inputLength = _contentLength; } - protected override bool Read(ReadableBuffer readableBuffer, WritableBuffer writableBuffer, out ReadCursor consumed, out ReadCursor examined) + protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { if (_inputLength == 0) { @@ -366,10 +368,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http RequestKeepAlive = keepAlive; } - protected override bool Read(ReadableBuffer readableBuffer, WritableBuffer writableBuffer, out ReadCursor consumed, out ReadCursor examined) + protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { - consumed = default(ReadCursor); - examined = default(ReadCursor); + consumed = default(Position); + examined = default(Position); while (_mode < Mode.Trailer) { @@ -457,17 +459,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } } - private void ParseChunkedPrefix(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + private void ParseChunkedPrefix(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { consumed = buffer.Start; examined = buffer.Start; - var reader = new ReadableBufferReader(buffer); + var reader = BufferReader.Create(buffer); var ch1 = reader.Take(); var ch2 = reader.Take(); if (ch1 == -1 || ch2 == -1) { - examined = reader.Cursor; + examined = reader.Position; return; } @@ -478,8 +480,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { if (ch1 == ';') { - consumed = reader.Cursor; - examined = reader.Cursor; + consumed = reader.Position; + examined = reader.Position; AddAndCheckConsumedBytes(reader.ConsumedBytes); _inputLength = chunkSize; @@ -490,14 +492,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http ch2 = reader.Take(); if (ch2 == -1) { - examined = reader.Cursor; + examined = reader.Position; return; } if (ch1 == '\r' && ch2 == '\n') { - consumed = reader.Cursor; - examined = reader.Cursor; + consumed = reader.Position; + examined = reader.Position; AddAndCheckConsumedBytes(reader.ConsumedBytes); _inputLength = chunkSize; @@ -513,7 +515,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _context.ThrowRequestRejected(RequestRejectionReason.BadChunkSizeData); } - private void ParseExtension(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + private void ParseExtension(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { // Chunk-extensions not currently parsed // Just drain the data @@ -522,8 +524,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http do { - ReadCursor extensionCursor; - if (ReadCursorOperations.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1) + Position extensionCursor; + if (ReadOnlyBuffer.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1) { // End marker not found yet consumed = buffer.End; @@ -565,7 +567,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } while (_mode == Mode.Extension); } - private void ReadChunkedData(ReadableBuffer buffer, WritableBuffer writableBuffer, out ReadCursor consumed, out ReadCursor examined) + private void ReadChunkedData(ReadOnlyBuffer buffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { var actual = Math.Min(buffer.Length, _inputLength); consumed = buffer.Move(buffer.Start, actual); @@ -582,7 +584,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } } - private void ParseChunkedSuffix(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + private void ParseChunkedSuffix(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { consumed = buffer.Start; examined = buffer.Start; @@ -608,7 +610,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } } - private void ParseChunkedTrailer(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + private void ParseChunkedTrailer(ReadOnlyBuffer buffer, out Position consumed, out Position 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 34c74f23d1..466f17f64e 100644 --- a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs +++ b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs @@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return FlushAsyncAwaited(awaitable, bytesWritten, cancellationToken); } - private async Task FlushAsyncAwaited(WritableBufferAwaitable awaitable, long count, CancellationToken cancellationToken) + private async Task FlushAsyncAwaited(ValueAwaiter awaitable, long count, CancellationToken cancellationToken) { // https://github.com/dotnet/corefxlab/issues/1334 // Since the flush awaitable doesn't currently support multiple awaiters diff --git a/src/Kestrel.Core/Internal/Http/HttpParser.cs b/src/Kestrel.Core/Internal/Http/HttpParser.cs index ab66b2337f..13297094f3 100644 --- a/src/Kestrel.Core/Internal/Http/HttpParser.cs +++ b/src/Kestrel.Core/Internal/Http/HttpParser.cs @@ -2,6 +2,8 @@ // 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.Sequences; using System.IO.Pipelines; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -31,7 +33,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, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined) + public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined) { consumed = buffer.Start; examined = buffer.End; @@ -186,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded); } - public unsafe bool ParseHeaders(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) + public unsafe bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes) { consumed = buffer.Start; examined = buffer.End; @@ -194,8 +196,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var bufferEnd = buffer.End; - var reader = new ReadableBufferReader(buffer); - var start = default(ReadableBufferReader); + var reader = BufferReader.Create(buffer); + var start = default(BufferReader); var done = false; try @@ -276,10 +278,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } else { - var current = reader.Cursor; + var current = reader.Position; // Split buffers - if (ReadCursorOperations.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1) + if (ReadOnlyBuffer.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1) { // Not there return false; @@ -312,7 +314,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } finally { - consumed = reader.Cursor; + consumed = reader.Position; consumedBytes = reader.ConsumedBytes; if (done) @@ -412,10 +414,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.NoInlining)] - private static bool TryGetNewLine(ref ReadableBuffer buffer, out ReadCursor found) + private static bool TryGetNewLine(ref ReadOnlyBuffer buffer, out Position found) { var start = buffer.Start; - if (ReadCursorOperations.Seek(start, buffer.End, out found, ByteLF) != -1) + if (ReadOnlyBuffer.Seek(start, buffer.End, out found, ByteLF) != -1) { // Move 1 byte past the \n found = buffer.Move(found, 1); diff --git a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs index fca679dd23..2d722efa3e 100644 --- a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs +++ b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs @@ -380,7 +380,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { } - protected virtual bool BeginRead(out ReadableBufferAwaitable awaitable) + protected virtual bool BeginRead(out ValueAwaiter awaitable) { awaitable = default; return false; @@ -1302,7 +1302,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http ( pool: _context.MemoryPool, readerScheduler: ServiceContext.ThreadPool, - writerScheduler: InlineScheduler.Default, + writerScheduler: Scheduler.Inline, maximumSizeHigh: 1, maximumSizeLow: 1 )); diff --git a/src/Kestrel.Core/Internal/Http/IHttpParser.cs b/src/Kestrel.Core/Internal/Http/IHttpParser.cs index a0a477d0f0..07dff45a84 100644 --- a/src/Kestrel.Core/Internal/Http/IHttpParser.cs +++ b/src/Kestrel.Core/Internal/Http/IHttpParser.cs @@ -1,14 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; +using System.Collections.Sequences; using System.IO.Pipelines; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { public interface IHttpParser where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler { - bool ParseRequestLine(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined); + bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined); - bool ParseHeaders(TRequestHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes); + bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes); } -} \ No newline at end of file +} diff --git a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs index 6989d80aa3..e45d8ef5c5 100644 --- a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs +++ b/src/Kestrel.Core/Internal/Http/PipelineExtensions.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.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private static byte[] _numericBytesScratch; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span ToSpan(this ReadableBuffer buffer) + public static ReadOnlySpan ToSpan(this ReadOnlyBuffer buffer) { if (buffer.IsSingleSpan) { @@ -35,6 +36,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return result; } + public static ArraySegment GetArray(this ReadOnlyMemory memory) + { + if (!MemoryMarshal.TryGetArray(memory, out var result)) + { + throw new InvalidOperationException("Buffer backed by array was expected"); + } + return result; + } + public unsafe static void WriteAsciiNoValidation(ref this WritableBufferWriter buffer, string data) { if (string.IsNullOrEmpty(data)) diff --git a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs index db71ff63c9..c1cb104f50 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs @@ -2,6 +2,8 @@ // 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.Sequences; using System.Collections.Concurrent; using System.IO.Pipelines; using System.Text; @@ -214,7 +216,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } } - private bool ParsePreface(ReadableBuffer readableBuffer, out ReadCursor consumed, out ReadCursor examined) + private bool ParsePreface(ReadOnlyBuffer readableBuffer, out Position consumed, out Position examined) { consumed = readableBuffer.Start; examined = readableBuffer.End; diff --git a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs index 2a45009277..0a2ae72aa0 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs @@ -1,13 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; +using System.Collections.Sequences; using System.IO.Pipelines; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 { public static class Http2FrameReader { - public static bool ReadFrame(ReadableBuffer readableBuffer, Http2Frame frame, out ReadCursor consumed, out ReadCursor examined) + public static bool ReadFrame(ReadOnlyBuffer readableBuffer, Http2Frame frame, out Position consumed, out Position examined) { consumed = readableBuffer.Start; examined = readableBuffer.End; diff --git a/src/Kestrel.Core/Internal/HttpConnection.cs b/src/Kestrel.Core/Internal/HttpConnection.cs index 44f0fcbd1a..1ac4945ae4 100644 --- a/src/Kestrel.Core/Internal/HttpConnection.cs +++ b/src/Kestrel.Core/Internal/HttpConnection.cs @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal ( pool: MemoryPool, readerScheduler: _context.ServiceContext.ThreadPool, - writerScheduler: InlineScheduler.Default, + writerScheduler: Scheduler.Inline, maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 ); @@ -81,8 +81,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions ( pool: MemoryPool, - readerScheduler: InlineScheduler.Default, - writerScheduler: InlineScheduler.Default, + readerScheduler: Scheduler.Inline, + writerScheduler: Scheduler.Inline, maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 ); diff --git a/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs index f762ff976b..26219bf8b0 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure { - public class InlineLoggingThreadPool : IThreadPool + public class InlineLoggingThreadPool : KestrelThreadPool { private readonly IKestrelTrace _log; @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure _log = log; } - public void Run(Action action) + public override void Run(Action action) { try { @@ -28,12 +28,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure } } - public void UnsafeRun(WaitCallback action, object state) + public override void UnsafeRun(WaitCallback action, object state) { action(state); } - public void Schedule(Action action, object state) + public override void Schedule(Action action) + { + Run(action); + } + + public override void Schedule(Action action, object state) { try { diff --git a/src/Kestrel.Core/Internal/Infrastructure/IThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs similarity index 64% rename from src/Kestrel.Core/Internal/Infrastructure/IThreadPool.cs rename to src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs index c78a4db61d..54375c3aaa 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/IThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/KestrelThreadPool.cs @@ -7,9 +7,9 @@ using System.Threading; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure { - public interface IThreadPool : IScheduler + public abstract class KestrelThreadPool: Scheduler { - void Run(Action action); - void UnsafeRun(WaitCallback action, object state); + public abstract void Run(Action action); + public abstract void UnsafeRun(WaitCallback action, object state); } } \ No newline at end of file diff --git a/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs index 184d956b18..1d90a7b681 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure { - public class LoggingThreadPool : IThreadPool + public class LoggingThreadPool : KestrelThreadPool { private readonly IKestrelTrace _log; @@ -40,17 +40,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure }; } - public void Run(Action action) + public override void Run(Action action) { ThreadPool.QueueUserWorkItem(_runAction, action); } - public void UnsafeRun(WaitCallback action, object state) + public override void UnsafeRun(WaitCallback action, object state) { ThreadPool.QueueUserWorkItem(action, state); } - public void Schedule(Action action, object state) + public override void Schedule(Action action) + { + Run(action); + } + + public override void Schedule(Action action, object state) { Run(() => action(state)); } diff --git a/src/Kestrel.Core/Internal/ServiceContext.cs b/src/Kestrel.Core/Internal/ServiceContext.cs index 30f45b1f37..9bad6b576b 100644 --- a/src/Kestrel.Core/Internal/ServiceContext.cs +++ b/src/Kestrel.Core/Internal/ServiceContext.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal { public IKestrelTrace Log { get; set; } - public IThreadPool ThreadPool { get; set; } + public KestrelThreadPool ThreadPool { get; set; } public IHttpParser HttpParser { get; set; } diff --git a/src/Kestrel.Core/KestrelServer.cs b/src/Kestrel.Core/KestrelServer.cs index 43b7ee3981..6d2c1d059c 100644 --- a/src/Kestrel.Core/KestrelServer.cs +++ b/src/Kestrel.Core/KestrelServer.cs @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core // TODO: This logic will eventually move into the IConnectionHandler and off // the service context once we get to https://github.com/aspnet/KestrelHttpServer/issues/1662 - IThreadPool threadPool = null; + KestrelThreadPool threadPool = null; switch (serverOptions.ApplicationSchedulingMode) { case SchedulingMode.Default: diff --git a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs index dc1af6ec56..3889bff14f 100644 --- a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs +++ b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs @@ -23,8 +23,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal public string ConnectionId { get; set; } public virtual MemoryPool MemoryPool { get; } - public virtual IScheduler InputWriterScheduler { get; } - public virtual IScheduler OutputReaderScheduler { get; } + public virtual Scheduler InputWriterScheduler { get; } + public virtual Scheduler OutputReaderScheduler { get; } public IPipeConnection Transport { get; set; } public IPipeConnection Application { get; set; } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs index 60b7849e26..35cbdf0771 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs @@ -6,6 +6,7 @@ using System.Buffers; using System.Diagnostics; using System.IO; using System.IO.Pipelines; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Protocols; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; @@ -183,7 +184,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal _bufferHandle.Dispose(); } - private async Task ApplyBackpressureAsync(WritableBufferAwaitable flushTask) + private async Task ApplyBackpressureAsync(ValueAwaiter flushTask) { Log.ConnectionPause(ConnectionId); _socket.ReadStop(); diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs index dde6aa5f30..be2ca1d255 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 IScheduler InputWriterScheduler => ListenerContext.Thread; - public override IScheduler OutputReaderScheduler => ListenerContext.Thread; + public override Scheduler InputWriterScheduler => ListenerContext.Thread; + public override Scheduler OutputReaderScheduler => ListenerContext.Thread; } } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs index ca9edc7445..ba4396fe32 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 : IScheduler + public class LibuvThread : Scheduler { // 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 @@ -390,7 +390,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal return await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task; } - public void Schedule(Action action, object state) + public override void Schedule(Action action) + { + Post(state => state(), action); + } + + public override void Schedule(Action action, object state) { Post(action, state); } diff --git a/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs b/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs index 9eac9c1a39..c25f2aec28 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, ReadableBuffer buffer) + public LibuvAwaitable WriteAsync(UvStreamHandle handle, ReadOnlyBuffer buffer) { Write(handle, buffer, LibuvAwaitable.Callback, _awaitable); return _awaitable; @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin private unsafe void Write( UvStreamHandle handle, - ReadableBuffer buffer, + ReadOnlyBuffer buffer, Action callback, object state) { diff --git a/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs b/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs index 8edfb997b2..7340736bd8 100644 --- a/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs +++ b/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs @@ -2,15 +2,24 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal { public static class BufferExtensions { - public static ArraySegment GetArray(this Memory buffer) + public static ArraySegment GetArray(this Memory memory) { - ArraySegment result; - if (!buffer.TryGetArray(out result)) + if (!memory.TryGetArray(out var result)) + { + throw new InvalidOperationException("Buffer backed by array was expected"); + } + return result; + } + + public static ArraySegment GetArray(this ReadOnlyMemory memory) + { + if (!MemoryMarshal.TryGetArray(memory, out var result)) { throw new InvalidOperationException("Buffer backed by array was expected"); } diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs index d74159792e..ff7c678cd7 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 IScheduler InputWriterScheduler => InlineScheduler.Default; - public override IScheduler OutputReaderScheduler => TaskRunScheduler.Default; + public override Scheduler InputWriterScheduler => Scheduler.Inline; + public override Scheduler OutputReaderScheduler => Scheduler.TaskRun; public async Task StartAsync(IConnectionHandler connectionHandler) { diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs b/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs index f871dc7021..8f5197f2ad 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs @@ -2,10 +2,12 @@ // 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.Pipelines; using System.Net.Sockets; +using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal { @@ -24,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal _eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError); } - public SocketAwaitable SendAsync(ReadableBuffer buffers) + public SocketAwaitable SendAsync(ReadOnlyBuffer buffers) { if (buffers.IsSingleSpan) { @@ -50,7 +52,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal return _awaitable; } - private SocketAwaitable SendAsync(Memory buffer) + private SocketAwaitable SendAsync(ReadOnlyMemory memory) { // The BufferList getter is much less expensive then the setter. if (_eventArgs.BufferList != null) @@ -59,9 +61,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal } #if NETCOREAPP2_1 - _eventArgs.SetBuffer(buffer); + _eventArgs.SetBuffer(MemoryMarshal.AsMemory(memory)); #else - var segment = buffer.GetArray(); + var segment = memory.GetArray(); _eventArgs.SetBuffer(segment.Array, segment.Offset, segment.Count); #endif @@ -73,7 +75,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal return _awaitable; } - private List> GetBufferList(ReadableBuffer buffer) + private List> GetBufferList(ReadOnlyBuffer buffer) { Debug.Assert(!buffer.IsEmpty); Debug.Assert(!buffer.IsSingleSpan); diff --git a/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs b/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs index 9a090437e8..2d7f3b5746 100644 --- a/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs +++ b/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs @@ -12,8 +12,8 @@ namespace Microsoft.AspNetCore.Protocols.Features IPipeConnection Application { get; set; } - IScheduler InputWriterScheduler { get; } + Scheduler InputWriterScheduler { get; } - IScheduler OutputReaderScheduler { get; } + Scheduler OutputReaderScheduler { get; } } } diff --git a/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs b/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs index 5c7afd17f0..42264410db 100644 --- a/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs +++ b/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs @@ -58,9 +58,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public IPipeConnection Transport { get; set; } public IPipeConnection Application { get; set; } - public IScheduler InputWriterScheduler => TaskRunScheduler.Default; + public Scheduler InputWriterScheduler => Scheduler.TaskRun; - public IScheduler OutputReaderScheduler => TaskRunScheduler.Default; + public Scheduler OutputReaderScheduler => Scheduler.TaskRun; public string ConnectionId { get; set; } } diff --git a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs index 934bd31257..3c1eba171b 100644 --- a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Collections; using System.Collections.Generic; +using System.Collections.Sequences; using System.IO; using System.IO.Pipelines; using System.Linq; @@ -33,8 +34,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private readonly ServiceContext _serviceContext; private readonly Http1ConnectionContext _http1ConnectionContext; private readonly MemoryPool _pipelineFactory; - private ReadCursor _consumed; - private ReadCursor _examined; + private Position _consumed; + private Position _examined; private Mock _timeoutControl; public Http1ConnectionTests() diff --git a/test/Kestrel.Core.Tests/HttpParserTests.cs b/test/Kestrel.Core.Tests/HttpParserTests.cs index 17647743e5..2a1d3dd142 100644 --- a/test/Kestrel.Core.Tests/HttpParserTests.cs +++ b/test/Kestrel.Core.Tests/HttpParserTests.cs @@ -2,8 +2,8 @@ // 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.IO.Pipelines.Testing; using System.Collections.Generic; using System.Linq; using System.Text; @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests string expectedVersion) { var parser = CreateParser(Mock.Of()); - var buffer = ReadableBuffer.Create(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)); @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine) { var parser = CreateParser(Mock.Of()); - var buffer = ReadableBuffer.Create(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,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine) { var parser = CreateParser(Mock.Of()); - var buffer = ReadableBuffer.Create(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)); @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests .Returns(true); var parser = CreateParser(mockTrace.Object); - var buffer = ReadableBuffer.Create(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 = ReadableBuffer.Create(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 = ReadableBuffer.Create(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 = ReadableBuffer.Create(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,7 +204,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { var parser = CreateParser(Mock.Of()); - var buffer = ReadableBuffer.Create(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); @@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var parser = CreateParser(Mock.Of()); const string headerLine = "Header: value\r\n\r"; - var buffer1 = ReadableBuffer.Create(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)); @@ -302,7 +302,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal(buffer1.End, examined); Assert.Equal(headerLine.Length - 1, consumedBytes); - var buffer2 = ReadableBuffer.Create(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); @@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests .Returns(true); var parser = CreateParser(mockTrace.Object); - var buffer = ReadableBuffer.Create(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 = ReadableBuffer.Create(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 = ReadableBuffer.Create(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 = ReadableBuffer.Create(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)); @@ -369,27 +369,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } - [Fact] - public void ParseRequestLineSplitBufferWithoutNewLineDoesNotUpdateConsumed() - { - var parser = CreateParser(Mock.Of()); - var buffer = BufferUtilities.CreateBuffer("GET ", "/"); - - var requestHandler = new RequestHandler(); - var result = parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined); - - Assert.False(result); - Assert.Equal(buffer.Start, consumed); - Assert.Equal(buffer.End, examined); - } - private void VerifyHeader( string headerName, string rawHeaderValue, string expectedHeaderValue) { var parser = CreateParser(Mock.Of()); - var buffer = ReadableBuffer.Create(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); @@ -407,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 = ReadableBuffer.Create(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); diff --git a/test/Kestrel.Core.Tests/OutputProducerTests.cs b/test/Kestrel.Core.Tests/OutputProducerTests.cs index 77e21810f3..71a4b7712b 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 19ac6a1592..397fbdbbc8 100644 --- a/test/Kestrel.Core.Tests/PipeOptionsTests.cs +++ b/test/Kestrel.Core.Tests/PipeOptionsTests.cs @@ -26,7 +26,7 @@ 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); @@ -44,7 +44,7 @@ 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); @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeHigh); Assert.Same(serviceContext.ThreadPool, connectionLifetime.AdaptedInputPipeOptions.ReaderScheduler); - Assert.Same(InlineScheduler.Default, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler); + Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler); } [Theory] @@ -87,8 +87,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeHigh); - Assert.Same(InlineScheduler.Default, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler); - Assert.Same(InlineScheduler.Default, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler); + Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler); + Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler); } } } diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs index f6df1515e3..4c79bddf19 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs @@ -117,11 +117,11 @@ 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>(), It.IsAny())).Callback, object>((a, o) => + mockScheduler.Setup(m => m.Schedule(It.IsAny())).Callback(a => { - backPressure = () => a(o); + backPressure = a; }); mockConnectionHandler.InputOptions = pool => new PipeOptions( diff --git a/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs b/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs index c079e405cc..001b4343e1 100644 --- a/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/MultipleLoopTests.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.Net; using System.Net.Sockets; @@ -68,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests await writeRequest.WriteAsync( serverConnectionPipe, - ReadableBuffer.Create(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 0378022eed..dfe9681a0b 100644 --- a/test/Kestrel.Transport.Libuv.Tests/NetworkingTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/NetworkingTests.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.Net; using System.Net.Sockets; using System.Runtime.InteropServices; @@ -161,7 +162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests { var req = new UvWriteReq(_logger); req.DangerousInit(loop); - var block = ReadableBuffer.Create(new byte[] { 65, 66, 67, 68, 69 }); + var block = new ReadOnlyBuffer(new byte[] { 65, 66, 67, 68, 69 }); await req.WriteAsync( tcp2,