Merge release/2.1

This commit is contained in:
Pavel Krymets 2018-01-30 09:39:33 -08:00
commit 261b5836c1
67 changed files with 551 additions and 542 deletions

View File

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

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
private static readonly Func<object, Task> _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);
}
}

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
private readonly HttpParser<Adapter> _parser = new HttpParser<Adapter>();
private ReadOnlyBuffer _buffer;
private ReadOnlyBuffer<byte> _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<byte>(data);
}
private void ParseData()

View File

@ -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<Http1ParsingHandler> Instance = new NullParser<Http1ParsingHandler>();
public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes)
public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
{
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_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<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{
handler.OnStartLine(HttpMethod.Get,
HttpVersion.Http11,

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -1,4 +1,4 @@
<Project>
<Project>
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
@ -25,24 +25,24 @@
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview1-27965</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview1-27965</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-26102-01</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26124-07</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview1-27965</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.3.0</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>
<NewtonsoftJsonPackageVersion>10.0.1</NewtonsoftJsonPackageVersion>
<SystemBuffersPackageVersion>4.5.0-preview1-26102-01</SystemBuffersPackageVersion>
<SystemBuffersPrimitivesPackageVersion>0.1.0-e180104-2</SystemBuffersPrimitivesPackageVersion>
<SystemIOPipelinesPackageVersion>0.1.0-e180104-2</SystemIOPipelinesPackageVersion>
<SystemIOPipelinesTestingPackageVersion>0.1.0-e180104-2</SystemIOPipelinesTestingPackageVersion>
<SystemMemoryPackageVersion>4.5.0-preview1-26102-01</SystemMemoryPackageVersion>
<SystemNumericsVectorsPackageVersion>4.5.0-preview1-26102-01</SystemNumericsVectorsPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview1-26102-01</SystemRuntimeCompilerServicesUnsafePackageVersion>
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview1-26102-01</SystemSecurityCryptographyCngPackageVersion>
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-e180104-2</SystemTextEncodingsWebUtf8PackageVersion>
<SystemBuffersPackageVersion>4.5.0-preview2-26125-06</SystemBuffersPackageVersion>
<SystemBuffersPrimitivesPackageVersion>0.1.0-preview2-180130-1</SystemBuffersPrimitivesPackageVersion>
<SystemIOPipelinesPackageVersion>0.1.0-preview2-180130-1</SystemIOPipelinesPackageVersion>
<SystemIOPipelinesTestingPackageVersion>0.1.0-preview2-180130-1</SystemIOPipelinesTestingPackageVersion>
<SystemMemoryPackageVersion>4.5.0-preview2-26125-06</SystemMemoryPackageVersion>
<SystemNumericsVectorsPackageVersion>4.5.0-preview2-26125-06</SystemNumericsVectorsPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview2-26125-06</SystemRuntimeCompilerServicesUnsafePackageVersion>
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview2-26125-06</SystemSecurityCryptographyCngPackageVersion>
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-preview2-180130-1</SystemTextEncodingsWebUtf8PackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview2-25707-02</SystemThreadingTasksExtensionsPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.3.1</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup>
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
</Project>
</Project>

View File

@ -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)
{

View File

@ -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<byte>(buffer, offset, count));
_output.Write(new ReadOnlySpan<byte>(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);
}
}
}

View File

@ -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)

View File

@ -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<byte>(bytes, offset, 10 - offset);
}
public static int WriteBeginChunkBytes(ref WritableBufferWriter start, int dataCount)
public static int WriteBeginChunkBytes(ref OutputWriter<PipeWriter> start, int dataCount)
{
var chunkSegment = BeginChunkBytes(dataCount);
start.Write(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count);
start.Write(new ReadOnlySpan<byte>(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count));
return chunkSegment.Count;
}
public static void WriteEndChunkBytes(ref WritableBufferWriter start)
public static void WriteEndChunkBytes(ref OutputWriter<PipeWriter> start)
{
start.Write(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count);
start.Write(new ReadOnlySpan<byte>(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count));
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.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<byte> 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<byte> 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<byte> 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)

View File

@ -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; }
}
}

View File

@ -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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
{
consumed = buffer.Start;
examined = buffer.Start;

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
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<T>(Action<WritableBuffer, T> callback, T state)
public void Write<T>(Action<PipeWriter, T> 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<T>(Action<WritableBuffer, T> callback, T state)
public Task WriteAsync<T>(Action<PipeWriter, T> 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<byte> 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<byte>(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)

View File

@ -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<PipeWriter> 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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_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<byte>(_headerBytes, 566, 26));
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
}
}

View File

@ -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<byte> 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<byte> 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<ReadOnlyBuffer>);
var start = default(BufferReader<ReadOnlyBuffer<byte>>);
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<byte>(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<byte> 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;
}

View File

@ -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<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature);
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as IHttpRequestFeature);
}
if (_currentIHttpResponseFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature);
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as IHttpResponseFeature);
}
if (_currentIHttpRequestIdentifierFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature);
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as IHttpRequestIdentifierFeature);
}
if (_currentIServiceProvidersFeature != null)
{
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature);
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as IServiceProvidersFeature);
}
if (_currentIHttpRequestLifetimeFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature);
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as IHttpRequestLifetimeFeature);
}
if (_currentIHttpConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature);
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as IHttpConnectionFeature);
}
if (_currentIHttpAuthenticationFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature);
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as IHttpAuthenticationFeature);
}
if (_currentIQueryFeature != null)
{
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as global::Microsoft.AspNetCore.Http.Features.IQueryFeature);
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as IQueryFeature);
}
if (_currentIFormFeature != null)
{
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as global::Microsoft.AspNetCore.Http.Features.IFormFeature);
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as IFormFeature);
}
if (_currentIHttpUpgradeFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature);
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as IHttpUpgradeFeature);
}
if (_currentIHttp2StreamIdFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature);
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as IHttp2StreamIdFeature);
}
if (_currentIResponseCookiesFeature != null)
{
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature);
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as IResponseCookiesFeature);
}
if (_currentIItemsFeature != null)
{
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as global::Microsoft.AspNetCore.Http.Features.IItemsFeature);
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as IItemsFeature);
}
if (_currentITlsConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature);
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as ITlsConnectionFeature);
}
if (_currentIHttpWebSocketFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature);
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as IHttpWebSocketFeature);
}
if (_currentISessionFeature != null)
{
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as global::Microsoft.AspNetCore.Http.Features.ISessionFeature);
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as ISessionFeature);
}
if (_currentIHttpMaxRequestBodySizeFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature);
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as IHttpMaxRequestBodySizeFeature);
}
if (_currentIHttpMinRequestBodyDataRateFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature);
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as IHttpMinRequestBodyDataRateFeature);
}
if (_currentIHttpMinResponseDataRateFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature);
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as IHttpMinResponseDataRateFeature);
}
if (_currentIHttpBodyControlFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature);
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as IHttpBodyControlFeature);
}
if (_currentIHttpSendFileFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as IHttpSendFileFeature);
}
if (MaybeExtra != null)

View File

@ -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<WritableBuffer, ArraySegment<byte>> _writeChunk = WriteChunk;
private static readonly Action<PipeWriter, ArraySegment<byte>> _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<byte> buffer)
private static void WriteChunk(PipeWriter writableBuffer, ArraySegment<byte> buffer)
{
var writer = new WritableBufferWriter(writableBuffer);
var writer = OutputWriter.Create(writableBuffer);
if (buffer.Count > 0)
{
ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Count);
writer.Write(buffer.Array, buffer.Offset, buffer.Count);
writer.Write(new ReadOnlySpan<byte>(buffer.Array, buffer.Offset, buffer.Count));
ChunkWriter.WriteEndChunkBytes(ref writer);
}
}
@ -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
));
}
}

View File

@ -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<PipeWriter> output)
{
CopyToFast(ref output);
if (MaybeUnknown != null)

View File

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

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
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<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
{
bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined);
bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined);
bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes);
bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes);
}
}

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// buffer.Count is int
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);
}
}
}

View File

@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private static byte[] _numericBytesScratch;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<byte> ToSpan(this ReadOnlyBuffer buffer)
public static ReadOnlySpan<byte> ToSpan(this ReadOnlyBuffer<byte> buffer)
{
if (buffer.IsSingleSpan)
if (buffer.IsSingleSegment)
{
return buffer.First.Span;
}
@ -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<PipeWriter> 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<PipeWriter> 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<PipeWriter> 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<byte>(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<PipeWriter> buffer, string data)
{
var remaining = data.Length;

View File

@ -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<byte> 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;
}

View File

@ -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; }
}
}

View File

@ -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<byte> 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;
}

View File

@ -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<KeyValuePair<string, string>> EnumerateHeaders(IHeaderDictionary headers)

View File

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

View File

@ -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)

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
private IList<IAdaptedConnection> _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
{

View File

@ -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; }
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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

View File

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

View File

@ -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)
{
@ -102,11 +102,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)
{
@ -115,14 +115,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)
{
@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
}
finally
{
Output.Advance(buffer.End);
Output.AdvanceTo(buffer.End);
}
}
}

View File

@ -26,9 +26,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
_eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError);
}
public SocketAwaitable SendAsync(ReadOnlyBuffer buffers)
public SocketAwaitable SendAsync(ReadOnlyBuffer<byte> 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<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer buffer)
private List<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer<byte> buffer)
{
Debug.Assert(!buffer.IsEmpty);
Debug.Assert(!buffer.IsSingleSpan);
Debug.Assert(!buffer.IsSingleSegment);
if (_bufferList == null)
{

View File

@ -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; }
}

View File

@ -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;

View File

@ -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; }
}
}

View File

@ -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()
{

View File

@ -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);

View File

@ -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; }
}

View File

@ -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<ITimeoutControl> _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<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, exception.Message);
Assert.Equal(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<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.BadRequest_TooManyHeaders, exception.Message);
Assert.Equal(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<BadHttpRequestException>(() => _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.BadRequest_RequestLineTooLong, exception.Message);
Assert.Equal(StatusCodes.Status414UriTooLong, exception.StatusCode);
@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target), exception.Message);
}
@ -424,7 +424,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
}
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(requestLine.EscapeNonPrintable()), exception.Message);
}
@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
}
@ -472,7 +472,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() =>
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
_transport.Input.Advance(_consumed, _examined);
_transport.Input.AdvanceTo(_consumed, _examined);
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
}
@ -486,7 +486,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var exception = Assert.Throws<BadHttpRequestException>(() =>
_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<BadHttpRequestException>(() =>
_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);

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize));
private 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<byte> 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);
}
}
}

View File

@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
string expectedVersion)
{
var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler();
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<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
var buffer = new ReadOnlyBuffer<byte>(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<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
var buffer = new ReadOnlyBuffer<byte>(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<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -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<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -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<byte>(Encoding.ASCII.GetBytes(requestLine));
var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler();
Assert.False(parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
}
@ -204,12 +204,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
var buffer = new ReadOnlyBuffer<byte>(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<IKestrelTrace>());
const string headerLine = "Header: value\r\n\r";
var buffer1 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(headerLine));
var buffer1 = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(headerLine));
var requestHandler = new RequestHandler();
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<byte>(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<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -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<byte>(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n"));
var requestHandler = new RequestHandler();
var exception = Assert.Throws<BadHttpRequestException>(() =>
@ -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<byte>(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n"));
exception = Assert.Throws<BadHttpRequestException>(() =>
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<byte>(Encoding.ASCII.GetBytes("Header: value\n\r\n"));
exception = Assert.Throws<BadHttpRequestException>(() =>
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<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n"));
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n"));
var requestHandler = new RequestHandler();
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<string> expectedHeaderNames, IEnumerable<string> expectedHeaderValues)
@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match");
var parser = CreateParser(Mock.Of<IKestrelTrace>());
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
var requestHandler = new RequestHandler();
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<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log.IsEnabled(LogLevel.Information));

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.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<byte> block;
Assert.True(buffer.Buffer.TryGetArray(out block));
Assert.True(MemoryMarshal.TryGetArray(buffer, out block));
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
buffer.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<byte[]>();
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);

View File

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

View File

@ -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<Scheduler>();
var mockScheduler = Mock.Of<PipeScheduler>();
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<Scheduler>();
var mockScheduler = Mock.Of<PipeScheduler>();
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);
}
}
}

View File

@ -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());
}
}

View File

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

View File

@ -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<Scheduler>();
var mockScheduler = new Mock<PipeScheduler>();
Action backPressure = null;
mockScheduler.Setup(m => m.Schedule(It.IsAny<Action>())).Callback<Action>(a =>
{
@ -126,8 +126,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
mockConnectionHandler.InputOptions = pool =>
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();

View File

@ -60,14 +60,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
// SocketOutput, the write callback would never be invoked for writes larger than
// 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

View File

@ -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<byte>(new byte[] { 1, 2, 3, 4 }));
writeRequest.Dispose();
serverConnectionPipe.Dispose();

View File

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

View File

@ -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; }
}
}

View File

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

View File

@ -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<KeyValuePair<Type, object>> FastEnumerable()
{{{Each(allFeatures, feature => $@"
if (_current{feature.Name} != null)
if (_current{feature} != null)
{{
yield return new KeyValuePair<Type, object>({feature.Name}Type, _current{feature.Name} as global::{feature.FullName});
yield return new KeyValuePair<Type, object>({feature}Type, _current{feature} as {feature});
}}")}
if (MaybeExtra != null)

View File

@ -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<string, HttpMethod>("CONNECT ", HttpMethod.Connect),
new Tuple<string, HttpMethod>("DELETE ", HttpMethod.Delete),
new Tuple<string, HttpMethod>("HEAD ", HttpMethod.Head),
new Tuple<string, HttpMethod>("PATCH ", HttpMethod.Patch),
new Tuple<string, HttpMethod>("POST ", HttpMethod.Post),
new Tuple<string, HttpMethod>("PUT ", HttpMethod.Put),
new Tuple<string, HttpMethod>("OPTIONS ", HttpMethod.Options),
new Tuple<string, HttpMethod>("TRACE ", HttpMethod.Trace),
new Tuple<string, HttpMethod>("GET ", HttpMethod.Get)
new Tuple<string, String>("CONNECT ", "Connect"),
new Tuple<string, String>("DELETE ", "Delete"),
new Tuple<string, String>("HEAD ", "Head"),
new Tuple<string, String>("PATCH ", "Patch"),
new Tuple<string, String>("POST ", "Post"),
new Tuple<string, String>("PUT ", "Put"),
new Tuple<string, String>("OPTIONS ", "Options"),
new Tuple<string, String>("TRACE ", "Trace"),
new Tuple<string, String>("GET ", "Get")
};
return GenerateFile(httpMethods);
}
private static string GenerateFile(Tuple<string, HttpMethod>[] httpMethods)
private static string GenerateFile(Tuple<string, String>[] httpMethods)
{
var maskLength = (byte)Math.Ceiling(Math.Log(httpMethods.Length, 2));
var 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<string, HttpMethod> method)
private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple<string, string> method)
{
var methodString = GetMethodString(method.Item1);

View File

@ -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<PipeWriter> 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<byte>(_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<byte>(_headerBytes, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesOffset}, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesCount}));
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
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;

View File

@ -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) : "";