React to pipelines changes (#2275)
This commit is contained in:
parent
8280c1b73f
commit
a84095e5c3
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
private const int InnerLoopCount = 512;
|
private const int InnerLoopCount = 512;
|
||||||
|
|
||||||
public ReadOnlyBuffer _buffer;
|
public ReadOnlyBuffer<byte> _buffer;
|
||||||
public Http1Connection _http1Connection;
|
public Http1Connection _http1Connection;
|
||||||
|
|
||||||
[IterationSetup]
|
[IterationSetup]
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask;
|
private static readonly Func<object, Task> _psuedoAsyncTaskFunc = (obj) => _psuedoAsyncTask;
|
||||||
|
|
||||||
private readonly TestHttp1Connection _http1Connection;
|
private readonly TestHttp1Connection _http1Connection;
|
||||||
private (IPipeConnection Transport, IPipeConnection Application) _pair;
|
private (IDuplexPipe Transport, IDuplexPipe Application) _pair;
|
||||||
|
|
||||||
private readonly byte[] _writeData;
|
private readonly byte[] _writeData;
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
var reader = _pair.Application.Input;
|
var reader = _pair.Application.Input;
|
||||||
if (reader.TryRead(out var readResult))
|
if (reader.TryRead(out var readResult))
|
||||||
{
|
{
|
||||||
reader.Advance(readResult.Buffer.End);
|
reader.AdvanceTo(readResult.Buffer.End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
private readonly HttpParser<Adapter> _parser = new HttpParser<Adapter>();
|
private readonly HttpParser<Adapter> _parser = new HttpParser<Adapter>();
|
||||||
|
|
||||||
private ReadOnlyBuffer _buffer;
|
private ReadOnlyBuffer<byte> _buffer;
|
||||||
|
|
||||||
[Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)]
|
[Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)]
|
||||||
public void PlaintextTechEmpower()
|
public void PlaintextTechEmpower()
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
|
||||||
private void InsertData(byte[] data)
|
private void InsertData(byte[] data)
|
||||||
{
|
{
|
||||||
_buffer = new ReadOnlyBuffer(data);
|
_buffer = new ReadOnlyBuffer<byte>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseData()
|
private void ParseData()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -23,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
|
||||||
public static readonly NullParser<Http1ParsingHandler> Instance = new NullParser<Http1ParsingHandler>();
|
public static readonly NullParser<Http1ParsingHandler> Instance = new NullParser<Http1ParsingHandler>();
|
||||||
|
|
||||||
public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes)
|
public bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
|
||||||
{
|
{
|
||||||
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
|
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
|
||||||
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
|
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
|
||||||
|
|
@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
public bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
handler.OnStartLine(HttpMethod.Get,
|
handler.OnStartLine(HttpMethod.Get,
|
||||||
HttpVersion.Http11,
|
HttpVersion.Http11,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
private const int _writeLenght = 57;
|
private const int _writeLenght = 57;
|
||||||
private const int InnerLoopCount = 512;
|
private const int InnerLoopCount = 512;
|
||||||
|
|
||||||
private IPipe _pipe;
|
private Pipe _pipe;
|
||||||
private MemoryPool _memoryPool;
|
private MemoryPool _memoryPool;
|
||||||
|
|
||||||
[IterationSetup]
|
[IterationSetup]
|
||||||
|
|
@ -30,9 +30,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
for (int i = 0; i < InnerLoopCount; i++)
|
for (int i = 0; i < InnerLoopCount; i++)
|
||||||
{
|
{
|
||||||
var writableBuffer = _pipe.Writer.Alloc(_writeLenght);
|
_pipe.Writer.GetMemory(_writeLenght);
|
||||||
writableBuffer.Advance(_writeLenght);
|
_pipe.Writer.Advance(_writeLenght);
|
||||||
await writableBuffer.FlushAsync();
|
await _pipe.Writer.FlushAsync();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
var result = await _pipe.Reader.ReadAsync();
|
var result = await _pipe.Reader.ReadAsync();
|
||||||
remaining -= result.Buffer.Length;
|
remaining -= result.Buffer.Length;
|
||||||
_pipe.Reader.Advance(result.Buffer.End, result.Buffer.End);
|
_pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -55,11 +55,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
for (int i = 0; i < InnerLoopCount; i++)
|
for (int i = 0; i < InnerLoopCount; i++)
|
||||||
{
|
{
|
||||||
var writableBuffer = _pipe.Writer.Alloc(_writeLenght);
|
_pipe.Writer.GetMemory(_writeLenght);
|
||||||
writableBuffer.Advance(_writeLenght);
|
_pipe.Writer.Advance(_writeLenght);
|
||||||
writableBuffer.FlushAsync().GetAwaiter().GetResult();
|
_pipe.Writer.FlushAsync().GetAwaiter().GetResult();
|
||||||
var result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
var result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||||
_pipe.Reader.Advance(result.Buffer.End, result.Buffer.End);
|
_pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
public class RequestParsingBenchmark
|
public class RequestParsingBenchmark
|
||||||
{
|
{
|
||||||
public IPipe Pipe { get; set; }
|
public Pipe Pipe { get; set; }
|
||||||
|
|
||||||
public Http1Connection Http1Connection { get; set; }
|
public Http1Connection Http1Connection { get; set; }
|
||||||
|
|
||||||
|
|
@ -130,10 +130,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
|
||||||
private void InsertData(byte[] bytes)
|
private void InsertData(byte[] bytes)
|
||||||
{
|
{
|
||||||
var buffer = Pipe.Writer.Alloc(2048);
|
Pipe.Writer.Write(bytes);
|
||||||
buffer.Write(bytes);
|
|
||||||
// There should not be any backpressure and task completes immediately
|
// There should not be any backpressure and task completes immediately
|
||||||
buffer.FlushAsync().GetAwaiter().GetResult();
|
Pipe.Writer.FlushAsync().GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseDataDrainBuffer()
|
private void ParseDataDrainBuffer()
|
||||||
|
|
@ -166,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
}
|
}
|
||||||
while (readableBuffer.Length > 0);
|
while (readableBuffer.Length > 0);
|
||||||
|
|
||||||
Pipe.Reader.Advance(readableBuffer.End);
|
Pipe.Reader.AdvanceTo(readableBuffer.End);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseData()
|
private void ParseData()
|
||||||
|
|
@ -189,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
ErrorUtilities.ThrowInvalidRequestLine();
|
ErrorUtilities.ThrowInvalidRequestLine();
|
||||||
}
|
}
|
||||||
Pipe.Reader.Advance(consumed, examined);
|
Pipe.Reader.AdvanceTo(consumed, examined);
|
||||||
|
|
||||||
result = Pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
result = Pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||||
readableBuffer = result.Buffer;
|
readableBuffer = result.Buffer;
|
||||||
|
|
@ -198,7 +197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
ErrorUtilities.ThrowInvalidRequestHeaders();
|
ErrorUtilities.ThrowInvalidRequestHeaders();
|
||||||
}
|
}
|
||||||
Pipe.Reader.Advance(consumed, examined);
|
Pipe.Reader.AdvanceTo(consumed, examined);
|
||||||
}
|
}
|
||||||
while (true);
|
while (true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,21 +25,21 @@
|
||||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsLoggingTestingPackageVersion>
|
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||||
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsOptionsPackageVersion>
|
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview1-28153</MicrosoftExtensionsOptionsPackageVersion>
|
||||||
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
|
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
|
||||||
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-26115-03</MicrosoftNETCoreApp21PackageVersion>
|
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-26126-02</MicrosoftNETCoreApp21PackageVersion>
|
||||||
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview1-28153</MicrosoftNetHttpHeadersPackageVersion>
|
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview1-28153</MicrosoftNetHttpHeadersPackageVersion>
|
||||||
<MicrosoftNETTestSdkPackageVersion>15.3.0</MicrosoftNETTestSdkPackageVersion>
|
<MicrosoftNETTestSdkPackageVersion>15.3.0</MicrosoftNETTestSdkPackageVersion>
|
||||||
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
||||||
<NewtonsoftJsonPackageVersion>10.0.1</NewtonsoftJsonPackageVersion>
|
<NewtonsoftJsonPackageVersion>10.0.1</NewtonsoftJsonPackageVersion>
|
||||||
<SystemBuffersPackageVersion>4.5.0-preview1-26112-01</SystemBuffersPackageVersion>
|
<SystemBuffersPackageVersion>4.5.0-preview1-26126-05</SystemBuffersPackageVersion>
|
||||||
<SystemBuffersPrimitivesPackageVersion>0.1.0-e180104-2</SystemBuffersPrimitivesPackageVersion>
|
<SystemBuffersPrimitivesPackageVersion>0.1.0-preview1-180129-1</SystemBuffersPrimitivesPackageVersion>
|
||||||
<SystemIOPipelinesPackageVersion>0.1.0-e180104-2</SystemIOPipelinesPackageVersion>
|
<SystemIOPipelinesPackageVersion>0.1.0-preview1-180129-1</SystemIOPipelinesPackageVersion>
|
||||||
<SystemIOPipelinesTestingPackageVersion>0.1.0-e180104-2</SystemIOPipelinesTestingPackageVersion>
|
<SystemIOPipelinesTestingPackageVersion>0.1.0-preview1-180129-1</SystemIOPipelinesTestingPackageVersion>
|
||||||
<SystemMemoryPackageVersion>4.5.0-preview1-26112-01</SystemMemoryPackageVersion>
|
<SystemMemoryPackageVersion>4.5.0-preview1-26126-05</SystemMemoryPackageVersion>
|
||||||
<SystemNumericsVectorsPackageVersion>4.5.0-preview1-26112-01</SystemNumericsVectorsPackageVersion>
|
<SystemNumericsVectorsPackageVersion>4.5.0-preview1-26126-05</SystemNumericsVectorsPackageVersion>
|
||||||
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview1-26112-01</SystemRuntimeCompilerServicesUnsafePackageVersion>
|
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview1-26126-05</SystemRuntimeCompilerServicesUnsafePackageVersion>
|
||||||
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview1-26112-01</SystemSecurityCryptographyCngPackageVersion>
|
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview1-26126-05</SystemSecurityCryptographyCngPackageVersion>
|
||||||
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-e180104-2</SystemTextEncodingsWebUtf8PackageVersion>
|
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-preview1-180129-1</SystemTextEncodingsWebUtf8PackageVersion>
|
||||||
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview1-26112-01</SystemThreadingTasksExtensionsPackageVersion>
|
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview1-26126-05</SystemThreadingTasksExtensionsPackageVersion>
|
||||||
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
|
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
|
||||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
||||||
<XunitRunnerVisualStudioPackageVersion>2.3.1</XunitRunnerVisualStudioPackageVersion>
|
<XunitRunnerVisualStudioPackageVersion>2.3.1</XunitRunnerVisualStudioPackageVersion>
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,17 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
{
|
{
|
||||||
public class AdaptedPipeline : IPipeConnection
|
public class AdaptedPipeline : IDuplexPipe
|
||||||
{
|
{
|
||||||
private const int MinAllocBufferSize = 2048;
|
private const int MinAllocBufferSize = 2048;
|
||||||
|
|
||||||
private readonly IPipeConnection _transport;
|
private readonly IDuplexPipe _transport;
|
||||||
private readonly IPipeConnection _application;
|
private readonly IDuplexPipe _application;
|
||||||
|
|
||||||
public AdaptedPipeline(IPipeConnection transport,
|
public AdaptedPipeline(IDuplexPipe transport,
|
||||||
IPipeConnection application,
|
IDuplexPipe application,
|
||||||
IPipe inputPipe,
|
Pipe inputPipe,
|
||||||
IPipe outputPipe)
|
Pipe outputPipe)
|
||||||
{
|
{
|
||||||
_transport = transport;
|
_transport = transport;
|
||||||
_application = application;
|
_application = application;
|
||||||
|
|
@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
Output = outputPipe;
|
Output = outputPipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPipe Input { get; }
|
public Pipe Input { get; }
|
||||||
|
|
||||||
public IPipe Output { get; }
|
public Pipe Output { get; }
|
||||||
|
|
||||||
IPipeReader IPipeConnection.Input => Input.Reader;
|
PipeReader IDuplexPipe.Input => Input.Reader;
|
||||||
|
|
||||||
IPipeWriter IPipeConnection.Output => Output.Writer;
|
PipeWriter IDuplexPipe.Output => Output.Writer;
|
||||||
|
|
||||||
public async Task RunAsync(Stream stream)
|
public async Task RunAsync(Stream stream)
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
}
|
}
|
||||||
await stream.FlushAsync();
|
await stream.FlushAsync();
|
||||||
}
|
}
|
||||||
else if (buffer.IsSingleSpan)
|
else if (buffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
var array = buffer.First.GetArray();
|
var array = buffer.First.GetArray();
|
||||||
await stream.WriteAsync(array.Array, array.Offset, array.Count);
|
await stream.WriteAsync(array.Array, array.Offset, array.Count);
|
||||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Output.Reader.Advance(buffer.End);
|
Output.Reader.AdvanceTo(buffer.End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -124,13 +124,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
||||||
var outputBuffer = Input.Writer.Alloc(MinAllocBufferSize);
|
var outputBuffer = Input.Writer.GetMemory(MinAllocBufferSize);
|
||||||
|
|
||||||
var array = outputBuffer.Buffer.GetArray();
|
var array = outputBuffer.GetArray();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count);
|
var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count);
|
||||||
outputBuffer.Advance(bytesRead);
|
Input.Writer.Advance(bytesRead);
|
||||||
|
|
||||||
if (bytesRead == 0)
|
if (bytesRead == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -140,10 +140,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
outputBuffer.Commit();
|
Input.Writer.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await outputBuffer.FlushAsync();
|
var result = await Input.Writer.FlushAsync();
|
||||||
|
|
||||||
if (result.IsCompleted)
|
if (result.IsCompleted)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,16 @@ using System.IO.Pipelines;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
{
|
{
|
||||||
public class RawStream : Stream
|
public class RawStream : Stream
|
||||||
{
|
{
|
||||||
private readonly IPipeReader _input;
|
private readonly PipeReader _input;
|
||||||
private readonly IPipeWriter _output;
|
private readonly PipeWriter _output;
|
||||||
|
|
||||||
public RawStream(IPipeReader input, IPipeWriter output)
|
public RawStream(PipeReader input, PipeWriter output)
|
||||||
{
|
{
|
||||||
_input = input;
|
_input = input;
|
||||||
_output = output;
|
_output = output;
|
||||||
|
|
@ -75,14 +76,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
|
|
||||||
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
|
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
|
||||||
{
|
{
|
||||||
var output = _output.Alloc();
|
|
||||||
|
|
||||||
if (buffer != null)
|
if (buffer != null)
|
||||||
{
|
{
|
||||||
output.Write(new ArraySegment<byte>(buffer, offset, count));
|
_output.Write(new ReadOnlySpan<byte>(buffer, offset, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
await output.FlushAsync(token);
|
await _output.FlushAsync(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
|
|
@ -118,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_input.Advance(readableBuffer.End, readableBuffer.End);
|
_input.AdvanceTo(readableBuffer.End, readableBuffer.End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,22 +83,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal for testing
|
// Internal for testing
|
||||||
internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, Scheduler writerScheduler) => new PipeOptions
|
internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler writerScheduler) => new PipeOptions
|
||||||
(
|
(
|
||||||
pool: memoryPool,
|
pool: memoryPool,
|
||||||
readerScheduler: serviceContext.ThreadPool,
|
readerScheduler: serviceContext.ThreadPool,
|
||||||
writerScheduler: writerScheduler,
|
writerScheduler: writerScheduler,
|
||||||
maximumSizeHigh: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
|
pauseWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
|
||||||
maximumSizeLow: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
|
resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, Scheduler readerScheduler) => new PipeOptions
|
internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler readerScheduler) => new PipeOptions
|
||||||
(
|
(
|
||||||
pool: memoryPool,
|
pool: memoryPool,
|
||||||
readerScheduler: readerScheduler,
|
readerScheduler: readerScheduler,
|
||||||
writerScheduler: serviceContext.ThreadPool,
|
writerScheduler: serviceContext.ThreadPool,
|
||||||
maximumSizeHigh: GetOutputResponseBufferSize(serviceContext),
|
pauseWriterThreshold: GetOutputResponseBufferSize(serviceContext),
|
||||||
maximumSizeLow: GetOutputResponseBufferSize(serviceContext)
|
resumeWriterThreshold: GetOutputResponseBufferSize(serviceContext)
|
||||||
);
|
);
|
||||||
|
|
||||||
private static long GetOutputResponseBufferSize(ServiceContext serviceContext)
|
private static long GetOutputResponseBufferSize(ServiceContext serviceContext)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
|
@ -47,16 +48,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return new ArraySegment<byte>(bytes, offset, 10 - offset);
|
return new ArraySegment<byte>(bytes, offset, 10 - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int WriteBeginChunkBytes(ref WritableBufferWriter start, int dataCount)
|
public static int WriteBeginChunkBytes(ref OutputWriter<PipeWriter> start, int dataCount)
|
||||||
{
|
{
|
||||||
var chunkSegment = BeginChunkBytes(dataCount);
|
var chunkSegment = BeginChunkBytes(dataCount);
|
||||||
start.Write(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count);
|
start.Write(new ReadOnlySpan<byte>(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count));
|
||||||
return chunkSegment.Count;
|
return chunkSegment.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteEndChunkBytes(ref WritableBufferWriter start)
|
public static void WriteEndChunkBytes(ref OutputWriter<PipeWriter> start)
|
||||||
{
|
{
|
||||||
start.Write(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count);
|
start.Write(new ReadOnlySpan<byte>(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
|
@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
Output = new Http1OutputProducer(_context.Application.Input, _context.Transport.Output, _context.ConnectionId, _context.ServiceContext.Log, _context.TimeoutControl);
|
Output = new Http1OutputProducer(_context.Application.Input, _context.Transport.Output, _context.ConnectionId, _context.ServiceContext.Log, _context.TimeoutControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPipeReader Input => _context.Transport.Input;
|
public PipeReader Input => _context.Transport.Input;
|
||||||
|
|
||||||
public ITimeoutControl TimeoutControl => _context.TimeoutControl;
|
public ITimeoutControl TimeoutControl => _context.TimeoutControl;
|
||||||
public bool RequestTimedOut => _requestTimedOut;
|
public bool RequestTimedOut => _requestTimedOut;
|
||||||
|
|
@ -69,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
Input.CancelPendingRead();
|
Input.CancelPendingRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParseRequest(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
public void ParseRequest(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = buffer.Start;
|
consumed = buffer.Start;
|
||||||
examined = buffer.End;
|
examined = buffer.End;
|
||||||
|
|
@ -107,7 +108,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TakeStartLine(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
public bool TakeStartLine(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
var overLength = false;
|
var overLength = false;
|
||||||
if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize)
|
if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize)
|
||||||
|
|
@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TakeMessageHeaders(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
public bool TakeMessageHeaders(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
// Make sure the buffer is limited
|
// Make sure the buffer is limited
|
||||||
bool overLength = false;
|
bool overLength = false;
|
||||||
|
|
@ -453,7 +454,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Input.Advance(consumed, examined);
|
Input.AdvanceTo(consumed, examined);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.IsCompleted)
|
if (result.IsCompleted)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
public IPEndPoint RemoteEndPoint { get; set; }
|
public IPEndPoint RemoteEndPoint { get; set; }
|
||||||
public IPEndPoint LocalEndPoint { get; set; }
|
public IPEndPoint LocalEndPoint { get; set; }
|
||||||
public ITimeoutControl TimeoutControl { get; set; }
|
public ITimeoutControl TimeoutControl { get; set; }
|
||||||
public IPipeConnection Transport { get; set; }
|
public IDuplexPipe Transport { get; set; }
|
||||||
public IPipeConnection Application { get; set; }
|
public IDuplexPipe Application { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
|
@ -62,19 +63,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
if (!readableBuffer.IsEmpty)
|
if (!readableBuffer.IsEmpty)
|
||||||
{
|
{
|
||||||
var writableBuffer = _context.RequestBodyPipe.Writer.Alloc(1);
|
|
||||||
bool done;
|
bool done;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
done = Read(readableBuffer, writableBuffer, out consumed, out examined);
|
done = Read(readableBuffer, _context.RequestBodyPipe.Writer, out consumed, out examined);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
writableBuffer.Commit();
|
_context.RequestBodyPipe.Writer.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeAwaitable = writableBuffer.FlushAsync();
|
var writeAwaitable = _context.RequestBodyPipe.Writer.FlushAsync();
|
||||||
var backpressure = false;
|
var backpressure = false;
|
||||||
|
|
||||||
if (!writeAwaitable.IsCompleted)
|
if (!writeAwaitable.IsCompleted)
|
||||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_context.Input.Advance(consumed, examined);
|
_context.Input.AdvanceTo(consumed, examined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
result = await _context.RequestBodyPipe.Reader.ReadAsync();
|
result = await _context.RequestBodyPipe.Reader.ReadAsync();
|
||||||
_context.RequestBodyPipe.Reader.Advance(result.Buffer.End);
|
_context.RequestBodyPipe.Reader.AdvanceTo(result.Buffer.End);
|
||||||
} while (!result.IsCompleted);
|
} while (!result.IsCompleted);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
@ -151,11 +151,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Copy(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer)
|
protected void Copy(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer)
|
||||||
{
|
{
|
||||||
_context.TimeoutControl.BytesRead(readableBuffer.Length);
|
_context.TimeoutControl.BytesRead(readableBuffer.Length);
|
||||||
|
|
||||||
if (readableBuffer.IsSingleSpan)
|
if (readableBuffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
writableBuffer.Write(readableBuffer.First.Span);
|
writableBuffer.Write(readableBuffer.First.Span);
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_pumpTask = PumpAsync();
|
_pumpTask = PumpAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined)
|
protected virtual bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
RequestUpgrade = true;
|
RequestUpgrade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined)
|
protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
Copy(readableBuffer, writableBuffer);
|
Copy(readableBuffer, writableBuffer);
|
||||||
consumed = readableBuffer.End;
|
consumed = readableBuffer.End;
|
||||||
|
|
@ -316,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_inputLength = _contentLength;
|
_inputLength = _contentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined)
|
protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
if (_inputLength == 0)
|
if (_inputLength == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var actual = (int)Math.Min(readableBuffer.Length, _inputLength);
|
var actual = (int)Math.Min(readableBuffer.Length, _inputLength);
|
||||||
_inputLength -= actual;
|
_inputLength -= actual;
|
||||||
|
|
||||||
consumed = readableBuffer.Move(readableBuffer.Start, actual);
|
consumed = readableBuffer.GetPosition(readableBuffer.Start, actual);
|
||||||
examined = consumed;
|
examined = consumed;
|
||||||
|
|
||||||
Copy(readableBuffer.Slice(0, actual), writableBuffer);
|
Copy(readableBuffer.Slice(0, actual), writableBuffer);
|
||||||
|
|
@ -364,10 +364,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
RequestKeepAlive = keepAlive;
|
RequestKeepAlive = keepAlive;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined)
|
protected override bool Read(ReadOnlyBuffer<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = default(Position);
|
consumed = default(SequencePosition);
|
||||||
examined = default(Position);
|
examined = default(SequencePosition);
|
||||||
|
|
||||||
while (_mode < Mode.Trailer)
|
while (_mode < Mode.Trailer)
|
||||||
{
|
{
|
||||||
|
|
@ -455,13 +455,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseChunkedPrefix(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
private void ParseChunkedPrefix(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = buffer.Start;
|
consumed = buffer.Start;
|
||||||
examined = buffer.Start;
|
examined = buffer.Start;
|
||||||
var reader = BufferReader.Create(buffer);
|
var reader = BufferReader.Create(buffer);
|
||||||
var ch1 = reader.Take();
|
var ch1 = reader.Read();
|
||||||
var ch2 = reader.Take();
|
var ch2 = reader.Read();
|
||||||
|
|
||||||
if (ch1 == -1 || ch2 == -1)
|
if (ch1 == -1 || ch2 == -1)
|
||||||
{
|
{
|
||||||
|
|
@ -485,7 +485,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch2 = reader.Take();
|
ch2 = reader.Read();
|
||||||
if (ch2 == -1)
|
if (ch2 == -1)
|
||||||
{
|
{
|
||||||
examined = reader.Position;
|
examined = reader.Position;
|
||||||
|
|
@ -511,7 +511,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_context.ThrowRequestRejected(RequestRejectionReason.BadChunkSizeData);
|
_context.ThrowRequestRejected(RequestRejectionReason.BadChunkSizeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseExtension(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
private void ParseExtension(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
// Chunk-extensions not currently parsed
|
// Chunk-extensions not currently parsed
|
||||||
// Just drain the data
|
// Just drain the data
|
||||||
|
|
@ -520,8 +520,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Position extensionCursor;
|
SequencePosition? extensionCursorPosition = buffer.PositionOf(ByteCR);
|
||||||
if (ReadOnlyBuffer.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1)
|
if (extensionCursorPosition == null)
|
||||||
{
|
{
|
||||||
// End marker not found yet
|
// End marker not found yet
|
||||||
consumed = buffer.End;
|
consumed = buffer.End;
|
||||||
|
|
@ -530,6 +530,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var extensionCursor = extensionCursorPosition.Value;
|
||||||
var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;
|
var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;
|
||||||
|
|
||||||
var sufixBuffer = buffer.Slice(extensionCursor);
|
var sufixBuffer = buffer.Slice(extensionCursor);
|
||||||
|
|
@ -563,10 +564,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
} while (_mode == Mode.Extension);
|
} while (_mode == Mode.Extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadChunkedData(ReadOnlyBuffer buffer, WritableBuffer writableBuffer, out Position consumed, out Position examined)
|
private void ReadChunkedData(ReadOnlyBuffer<byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
var actual = Math.Min(buffer.Length, _inputLength);
|
var actual = Math.Min(buffer.Length, _inputLength);
|
||||||
consumed = buffer.Move(buffer.Start, actual);
|
consumed = buffer.GetPosition(buffer.Start, actual);
|
||||||
examined = consumed;
|
examined = consumed;
|
||||||
|
|
||||||
Copy(buffer.Slice(0, actual), writableBuffer);
|
Copy(buffer.Slice(0, actual), writableBuffer);
|
||||||
|
|
@ -580,7 +581,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseChunkedSuffix(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
private void ParseChunkedSuffix(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = buffer.Start;
|
consumed = buffer.Start;
|
||||||
examined = buffer.Start;
|
examined = buffer.Start;
|
||||||
|
|
@ -606,7 +607,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseChunkedTrailer(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
private void ParseChunkedTrailer(ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = buffer.Start;
|
consumed = buffer.Start;
|
||||||
examined = buffer.Start;
|
examined = buffer.Start;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
@ -28,8 +29,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
private bool _completed = false;
|
private bool _completed = false;
|
||||||
|
|
||||||
private readonly IPipeWriter _pipeWriter;
|
private readonly PipeWriter _pipeWriter;
|
||||||
private readonly IPipeReader _outputPipeReader;
|
private readonly PipeReader _outputPipeReader;
|
||||||
|
|
||||||
// https://github.com/dotnet/corefxlab/issues/1334
|
// https://github.com/dotnet/corefxlab/issues/1334
|
||||||
// Pipelines don't support multiple awaiters on flush
|
// Pipelines don't support multiple awaiters on flush
|
||||||
|
|
@ -39,8 +40,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private Action _flushCompleted;
|
private Action _flushCompleted;
|
||||||
|
|
||||||
public Http1OutputProducer(
|
public Http1OutputProducer(
|
||||||
IPipeReader outputPipeReader,
|
PipeReader outputPipeReader,
|
||||||
IPipeWriter pipeWriter,
|
PipeWriter pipeWriter,
|
||||||
string connectionId,
|
string connectionId,
|
||||||
IKestrelTrace log,
|
IKestrelTrace log,
|
||||||
ITimeoutControl timeoutControl)
|
ITimeoutControl timeoutControl)
|
||||||
|
|
@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return WriteAsync(Constants.EmptyData, cancellationToken);
|
return WriteAsync(Constants.EmptyData, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write<T>(Action<WritableBuffer, T> callback, T state)
|
public void Write<T>(Action<PipeWriter, T> callback, T state)
|
||||||
{
|
{
|
||||||
lock (_contextLock)
|
lock (_contextLock)
|
||||||
{
|
{
|
||||||
|
|
@ -82,13 +83,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = _pipeWriter.Alloc(1);
|
var buffer = _pipeWriter;
|
||||||
callback(buffer, state);
|
callback(buffer, state);
|
||||||
buffer.Commit();
|
buffer.Commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task WriteAsync<T>(Action<WritableBuffer, T> callback, T state)
|
public Task WriteAsync<T>(Action<PipeWriter, T> callback, T state)
|
||||||
{
|
{
|
||||||
lock (_contextLock)
|
lock (_contextLock)
|
||||||
{
|
{
|
||||||
|
|
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = _pipeWriter.Alloc(1);
|
var buffer = _pipeWriter;
|
||||||
callback(buffer, state);
|
callback(buffer, state);
|
||||||
buffer.Commit();
|
buffer.Commit();
|
||||||
}
|
}
|
||||||
|
|
@ -114,8 +115,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = _pipeWriter.Alloc(1);
|
var buffer = _pipeWriter;
|
||||||
var writer = new WritableBufferWriter(buffer);
|
var writer = OutputWriter.Create(buffer);
|
||||||
|
|
||||||
writer.Write(_bytesHttpVersion11);
|
writer.Write(_bytesHttpVersion11);
|
||||||
var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase);
|
var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase);
|
||||||
|
|
@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
ArraySegment<byte> buffer,
|
ArraySegment<byte> buffer,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var writableBuffer = default(WritableBuffer);
|
var writableBuffer = default(PipeWriter);
|
||||||
long bytesWritten = 0;
|
long bytesWritten = 0;
|
||||||
lock (_contextLock)
|
lock (_contextLock)
|
||||||
{
|
{
|
||||||
|
|
@ -176,11 +177,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
writableBuffer = _pipeWriter.Alloc(1);
|
writableBuffer = _pipeWriter;
|
||||||
var writer = new WritableBufferWriter(writableBuffer);
|
var writer = OutputWriter.Create(writableBuffer);
|
||||||
if (buffer.Count > 0)
|
if (buffer.Count > 0)
|
||||||
{
|
{
|
||||||
writer.Write(buffer.Array, buffer.Offset, buffer.Count);
|
writer.Write(new ReadOnlySpan<byte>(buffer.Array, buffer.Offset, buffer.Count));
|
||||||
bytesWritten += buffer.Count;
|
bytesWritten += buffer.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +193,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
// Single caller, at end of method - so inline
|
// Single caller, at end of method - so inline
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private Task FlushAsync(WritableBuffer writableBuffer, long bytesWritten, CancellationToken cancellationToken)
|
private Task FlushAsync(PipeWriter writableBuffer, long bytesWritten, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var awaitable = writableBuffer.FlushAsync(cancellationToken);
|
var awaitable = writableBuffer.FlushAsync(cancellationToken);
|
||||||
if (awaitable.IsCompleted)
|
if (awaitable.IsCompleted)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
@ -7753,7 +7754,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void CopyToFast(ref WritableBufferWriter output)
|
protected void CopyToFast(ref OutputWriter<PipeWriter> output)
|
||||||
{
|
{
|
||||||
var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0);
|
var tempBits = _bits | (_contentLength.HasValue ? -9223372036854775808L : 0);
|
||||||
|
|
||||||
|
|
@ -7771,7 +7772,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Connection[i];
|
var value = _headers._Connection[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 17, 14);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 17, 14));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7797,7 +7798,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Date[i];
|
var value = _headers._Date[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 31, 8);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 31, 8));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7818,7 +7819,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ContentType[i];
|
var value = _headers._ContentType[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 133, 16);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 133, 16));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7844,7 +7845,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Server[i];
|
var value = _headers._Server[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 350, 10);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 350, 10));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7858,7 +7859,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
if ((tempBits & -9223372036854775808L) != 0)
|
if ((tempBits & -9223372036854775808L) != 0)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 592, 18);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 592, 18));
|
||||||
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
|
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
|
||||||
|
|
||||||
if((tempBits & ~-9223372036854775808L) == 0)
|
if((tempBits & ~-9223372036854775808L) == 0)
|
||||||
|
|
@ -7876,7 +7877,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._CacheControl[i];
|
var value = _headers._CacheControl[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 0, 17);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 0, 17));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7897,7 +7898,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._KeepAlive[i];
|
var value = _headers._KeepAlive[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 39, 14);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 39, 14));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7918,7 +7919,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Pragma[i];
|
var value = _headers._Pragma[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 53, 10);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 53, 10));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7939,7 +7940,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Trailer[i];
|
var value = _headers._Trailer[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 63, 11);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 63, 11));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7965,7 +7966,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._TransferEncoding[i];
|
var value = _headers._TransferEncoding[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 74, 21);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 74, 21));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7986,7 +7987,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Upgrade[i];
|
var value = _headers._Upgrade[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 95, 11);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 95, 11));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8007,7 +8008,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Via[i];
|
var value = _headers._Via[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 106, 7);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 106, 7));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8028,7 +8029,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Warning[i];
|
var value = _headers._Warning[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 113, 11);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 113, 11));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8049,7 +8050,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Allow[i];
|
var value = _headers._Allow[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 124, 9);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 124, 9));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8070,7 +8071,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ContentEncoding[i];
|
var value = _headers._ContentEncoding[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 149, 20);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 149, 20));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8091,7 +8092,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ContentLanguage[i];
|
var value = _headers._ContentLanguage[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 169, 20);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 169, 20));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8112,7 +8113,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ContentLocation[i];
|
var value = _headers._ContentLocation[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 189, 20);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 189, 20));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8133,7 +8134,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ContentMD5[i];
|
var value = _headers._ContentMD5[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 209, 15);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 209, 15));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8154,7 +8155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ContentRange[i];
|
var value = _headers._ContentRange[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 224, 17);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 224, 17));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8175,7 +8176,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Expires[i];
|
var value = _headers._Expires[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 241, 11);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 241, 11));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8196,7 +8197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._LastModified[i];
|
var value = _headers._LastModified[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 252, 17);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 252, 17));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8217,7 +8218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AcceptRanges[i];
|
var value = _headers._AcceptRanges[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 269, 17);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 269, 17));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8238,7 +8239,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Age[i];
|
var value = _headers._Age[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 286, 7);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 286, 7));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8259,7 +8260,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ETag[i];
|
var value = _headers._ETag[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 293, 8);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 293, 8));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8280,7 +8281,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Location[i];
|
var value = _headers._Location[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 301, 12);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 301, 12));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8301,7 +8302,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._ProxyAuthenticate[i];
|
var value = _headers._ProxyAuthenticate[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 313, 22);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 313, 22));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8322,7 +8323,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._RetryAfter[i];
|
var value = _headers._RetryAfter[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 335, 15);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 335, 15));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8343,7 +8344,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._SetCookie[i];
|
var value = _headers._SetCookie[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 360, 14);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 360, 14));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8364,7 +8365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._Vary[i];
|
var value = _headers._Vary[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 374, 8);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 374, 8));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8385,7 +8386,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._WWWAuthenticate[i];
|
var value = _headers._WWWAuthenticate[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 382, 20);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 382, 20));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8406,7 +8407,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AccessControlAllowCredentials[i];
|
var value = _headers._AccessControlAllowCredentials[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 402, 36);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 402, 36));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8427,7 +8428,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AccessControlAllowHeaders[i];
|
var value = _headers._AccessControlAllowHeaders[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 438, 32);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 438, 32));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8448,7 +8449,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AccessControlAllowMethods[i];
|
var value = _headers._AccessControlAllowMethods[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 470, 32);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 470, 32));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8469,7 +8470,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AccessControlAllowOrigin[i];
|
var value = _headers._AccessControlAllowOrigin[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 502, 31);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 502, 31));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8490,7 +8491,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AccessControlExposeHeaders[i];
|
var value = _headers._AccessControlExposeHeaders[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 533, 33);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 533, 33));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8511,7 +8512,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._AccessControlMaxAge[i];
|
var value = _headers._AccessControlMaxAge[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
output.Write(_headerBytes, 566, 26);
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, 566, 26));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private const byte ByteQuestionMark = (byte)'?';
|
private const byte ByteQuestionMark = (byte)'?';
|
||||||
private const byte BytePercentage = (byte)'%';
|
private const byte BytePercentage = (byte)'%';
|
||||||
|
|
||||||
public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined)
|
public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = buffer.Start;
|
consumed = buffer.Start;
|
||||||
examined = buffer.End;
|
examined = buffer.End;
|
||||||
|
|
@ -43,10 +44,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var lineIndex = span.IndexOf(ByteLF);
|
var lineIndex = span.IndexOf(ByteLF);
|
||||||
if (lineIndex >= 0)
|
if (lineIndex >= 0)
|
||||||
{
|
{
|
||||||
consumed = buffer.Move(consumed, lineIndex + 1);
|
consumed = buffer.GetPosition(consumed, lineIndex + 1);
|
||||||
span = span.Slice(0, lineIndex + 1);
|
span = span.Slice(0, lineIndex + 1);
|
||||||
}
|
}
|
||||||
else if (buffer.IsSingleSpan)
|
else if (buffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
// No request line end
|
// No request line end
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -188,7 +189,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded);
|
handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes)
|
public unsafe bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
|
||||||
{
|
{
|
||||||
consumed = buffer.Start;
|
consumed = buffer.Start;
|
||||||
examined = buffer.End;
|
examined = buffer.End;
|
||||||
|
|
@ -197,21 +198,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var bufferEnd = buffer.End;
|
var bufferEnd = buffer.End;
|
||||||
|
|
||||||
var reader = BufferReader.Create(buffer);
|
var reader = BufferReader.Create(buffer);
|
||||||
var start = default(BufferReader<ReadOnlyBuffer>);
|
var start = default(BufferReader<ReadOnlyBuffer<byte>>);
|
||||||
var done = false;
|
var done = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!reader.End)
|
while (!reader.End)
|
||||||
{
|
{
|
||||||
var span = reader.Span;
|
var span = reader.CurrentSegment;
|
||||||
var remaining = span.Length - reader.Index;
|
var remaining = span.Length - reader.CurrentSegmentIndex;
|
||||||
|
|
||||||
fixed (byte* pBuffer = &MemoryMarshal.GetReference(span))
|
fixed (byte* pBuffer = &MemoryMarshal.GetReference(span))
|
||||||
{
|
{
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
var index = reader.Index;
|
var index = reader.CurrentSegmentIndex;
|
||||||
int ch1;
|
int ch1;
|
||||||
int ch2;
|
int ch2;
|
||||||
|
|
||||||
|
|
@ -228,8 +229,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
start = reader;
|
start = reader;
|
||||||
|
|
||||||
// Possibly split across spans
|
// Possibly split across spans
|
||||||
ch1 = reader.Take();
|
ch1 = reader.Read();
|
||||||
ch2 = reader.Take();
|
ch2 = reader.Read();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch1 == ByteCR)
|
if (ch1 == ByteCR)
|
||||||
|
|
@ -245,9 +246,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
// If we got 2 bytes from the span directly so skip ahead 2 so that
|
// If we got 2 bytes from the span directly so skip ahead 2 so that
|
||||||
// the reader's state matches what we expect
|
// the reader's state matches what we expect
|
||||||
if (index == reader.Index)
|
if (index == reader.CurrentSegmentIndex)
|
||||||
{
|
{
|
||||||
reader.Skip(2);
|
reader.Advance(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
done = true;
|
done = true;
|
||||||
|
|
@ -260,10 +261,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
// We moved the reader so look ahead 2 bytes so reset both the reader
|
// We moved the reader so look ahead 2 bytes so reset both the reader
|
||||||
// and the index
|
// and the index
|
||||||
if (index != reader.Index)
|
if (index != reader.CurrentSegmentIndex)
|
||||||
{
|
{
|
||||||
reader = start;
|
reader = start;
|
||||||
index = reader.Index;
|
index = reader.CurrentSegmentIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
var endIndex = new Span<byte>(pBuffer + index, remaining).IndexOf(ByteLF);
|
var endIndex = new Span<byte>(pBuffer + index, remaining).IndexOf(ByteLF);
|
||||||
|
|
@ -279,16 +280,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var current = reader.Position;
|
var current = reader.Position;
|
||||||
|
var currentSlice = buffer.Slice(current, bufferEnd);
|
||||||
|
|
||||||
|
var lineEndPosition = currentSlice.PositionOf(ByteLF);
|
||||||
// Split buffers
|
// Split buffers
|
||||||
if (ReadOnlyBuffer.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1)
|
if (lineEndPosition == null)
|
||||||
{
|
{
|
||||||
// Not there
|
// Not there
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lineEnd = lineEndPosition.Value;
|
||||||
|
|
||||||
// Make sure LF is included in lineEnd
|
// Make sure LF is included in lineEnd
|
||||||
lineEnd = buffer.Move(lineEnd, 1);
|
lineEnd = buffer.GetPosition(lineEnd, 1);
|
||||||
var headerSpan = buffer.Slice(current, lineEnd).ToSpan();
|
var headerSpan = buffer.Slice(current, lineEnd).ToSpan();
|
||||||
length = headerSpan.Length;
|
length = headerSpan.Length;
|
||||||
|
|
||||||
|
|
@ -304,7 +309,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the reader forward past the header line
|
// Skip the reader forward past the header line
|
||||||
reader.Skip(length);
|
reader.Advance(length);
|
||||||
remaining -= length;
|
remaining -= length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -414,15 +419,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private static bool TryGetNewLine(ref ReadOnlyBuffer buffer, out Position found)
|
private static bool TryGetNewLine(ref ReadOnlyBuffer<byte> buffer, out SequencePosition found)
|
||||||
{
|
{
|
||||||
var start = buffer.Start;
|
var byteLfPosition = buffer.PositionOf(ByteLF);
|
||||||
if (ReadOnlyBuffer.Seek(start, buffer.End, out found, ByteLF) != -1)
|
if (byteLfPosition != null)
|
||||||
{
|
{
|
||||||
// Move 1 byte past the \n
|
// Move 1 byte past the \n
|
||||||
found = buffer.Move(found, 1);
|
found = buffer.GetPosition(byteLfPosition.Value, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
found = default;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,35 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
public partial class HttpProtocol
|
public partial class HttpProtocol
|
||||||
{
|
{
|
||||||
private static readonly Type IHttpRequestFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature);
|
private static readonly Type IHttpRequestFeatureType = typeof(IHttpRequestFeature);
|
||||||
private static readonly Type IHttpResponseFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature);
|
private static readonly Type IHttpResponseFeatureType = typeof(IHttpResponseFeature);
|
||||||
private static readonly Type IHttpRequestIdentifierFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature);
|
private static readonly Type IHttpRequestIdentifierFeatureType = typeof(IHttpRequestIdentifierFeature);
|
||||||
private static readonly Type IServiceProvidersFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature);
|
private static readonly Type IServiceProvidersFeatureType = typeof(IServiceProvidersFeature);
|
||||||
private static readonly Type IHttpRequestLifetimeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature);
|
private static readonly Type IHttpRequestLifetimeFeatureType = typeof(IHttpRequestLifetimeFeature);
|
||||||
private static readonly Type IHttpConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature);
|
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
|
||||||
private static readonly Type IHttpAuthenticationFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature);
|
private static readonly Type IHttpAuthenticationFeatureType = typeof(IHttpAuthenticationFeature);
|
||||||
private static readonly Type IQueryFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IQueryFeature);
|
private static readonly Type IQueryFeatureType = typeof(IQueryFeature);
|
||||||
private static readonly Type IFormFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IFormFeature);
|
private static readonly Type IFormFeatureType = typeof(IFormFeature);
|
||||||
private static readonly Type IHttpUpgradeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature);
|
private static readonly Type IHttpUpgradeFeatureType = typeof(IHttpUpgradeFeature);
|
||||||
private static readonly Type IHttp2StreamIdFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature);
|
private static readonly Type IHttp2StreamIdFeatureType = typeof(IHttp2StreamIdFeature);
|
||||||
private static readonly Type IResponseCookiesFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature);
|
private static readonly Type IResponseCookiesFeatureType = typeof(IResponseCookiesFeature);
|
||||||
private static readonly Type IItemsFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IItemsFeature);
|
private static readonly Type IItemsFeatureType = typeof(IItemsFeature);
|
||||||
private static readonly Type ITlsConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature);
|
private static readonly Type ITlsConnectionFeatureType = typeof(ITlsConnectionFeature);
|
||||||
private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature);
|
private static readonly Type IHttpWebSocketFeatureType = typeof(IHttpWebSocketFeature);
|
||||||
private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ISessionFeature);
|
private static readonly Type ISessionFeatureType = typeof(ISessionFeature);
|
||||||
private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature);
|
private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(IHttpMaxRequestBodySizeFeature);
|
||||||
private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature);
|
private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(IHttpMinRequestBodyDataRateFeature);
|
||||||
private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature);
|
private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(IHttpMinResponseDataRateFeature);
|
||||||
private static readonly Type IHttpBodyControlFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature);
|
private static readonly Type IHttpBodyControlFeatureType = typeof(IHttpBodyControlFeature);
|
||||||
private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
|
private static readonly Type IHttpSendFileFeatureType = typeof(IHttpSendFileFeature);
|
||||||
|
|
||||||
private object _currentIHttpRequestFeature;
|
private object _currentIHttpRequestFeature;
|
||||||
private object _currentIHttpResponseFeature;
|
private object _currentIHttpResponseFeature;
|
||||||
|
|
@ -283,87 +287,87 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
if (_currentIHttpRequestFeature != null)
|
if (_currentIHttpRequestFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestFeature);
|
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as IHttpRequestFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpResponseFeature != null)
|
if (_currentIHttpResponseFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as global::Microsoft.AspNetCore.Http.Features.IHttpResponseFeature);
|
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as IHttpResponseFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpRequestIdentifierFeature != null)
|
if (_currentIHttpRequestIdentifierFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestIdentifierFeature);
|
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature as IHttpRequestIdentifierFeature);
|
||||||
}
|
}
|
||||||
if (_currentIServiceProvidersFeature != null)
|
if (_currentIServiceProvidersFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as global::Microsoft.AspNetCore.Http.Features.IServiceProvidersFeature);
|
yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature as IServiceProvidersFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpRequestLifetimeFeature != null)
|
if (_currentIHttpRequestLifetimeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpRequestLifetimeFeature);
|
yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature as IHttpRequestLifetimeFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpConnectionFeature != null)
|
if (_currentIHttpConnectionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as global::Microsoft.AspNetCore.Http.Features.IHttpConnectionFeature);
|
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature as IHttpConnectionFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpAuthenticationFeature != null)
|
if (_currentIHttpAuthenticationFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as global::Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature);
|
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature as IHttpAuthenticationFeature);
|
||||||
}
|
}
|
||||||
if (_currentIQueryFeature != null)
|
if (_currentIQueryFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as global::Microsoft.AspNetCore.Http.Features.IQueryFeature);
|
yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature as IQueryFeature);
|
||||||
}
|
}
|
||||||
if (_currentIFormFeature != null)
|
if (_currentIFormFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as global::Microsoft.AspNetCore.Http.Features.IFormFeature);
|
yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature as IFormFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpUpgradeFeature != null)
|
if (_currentIHttpUpgradeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpUpgradeFeature);
|
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as IHttpUpgradeFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttp2StreamIdFeature != null)
|
if (_currentIHttp2StreamIdFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttp2StreamIdFeature);
|
yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature as IHttp2StreamIdFeature);
|
||||||
}
|
}
|
||||||
if (_currentIResponseCookiesFeature != null)
|
if (_currentIResponseCookiesFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature);
|
yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature as IResponseCookiesFeature);
|
||||||
}
|
}
|
||||||
if (_currentIItemsFeature != null)
|
if (_currentIItemsFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as global::Microsoft.AspNetCore.Http.Features.IItemsFeature);
|
yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature as IItemsFeature);
|
||||||
}
|
}
|
||||||
if (_currentITlsConnectionFeature != null)
|
if (_currentITlsConnectionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature);
|
yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature as ITlsConnectionFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpWebSocketFeature != null)
|
if (_currentIHttpWebSocketFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature);
|
yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature as IHttpWebSocketFeature);
|
||||||
}
|
}
|
||||||
if (_currentISessionFeature != null)
|
if (_currentISessionFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as global::Microsoft.AspNetCore.Http.Features.ISessionFeature);
|
yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature as ISessionFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpMaxRequestBodySizeFeature != null)
|
if (_currentIHttpMaxRequestBodySizeFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature);
|
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as IHttpMaxRequestBodySizeFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpMinRequestBodyDataRateFeature != null)
|
if (_currentIHttpMinRequestBodyDataRateFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature);
|
yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as IHttpMinRequestBodyDataRateFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpMinResponseDataRateFeature != null)
|
if (_currentIHttpMinResponseDataRateFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinResponseDataRateFeature);
|
yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature as IHttpMinResponseDataRateFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpBodyControlFeature != null)
|
if (_currentIHttpBodyControlFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature);
|
yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature as IHttpBodyControlFeature);
|
||||||
}
|
}
|
||||||
if (_currentIHttpSendFileFeature != null)
|
if (_currentIHttpSendFileFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
|
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as IHttpSendFileFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MaybeExtra != null)
|
if (MaybeExtra != null)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive");
|
private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive");
|
||||||
private static readonly byte[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked");
|
private static readonly byte[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked");
|
||||||
private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName);
|
private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName);
|
||||||
private static readonly Action<WritableBuffer, ArraySegment<byte>> _writeChunk = WriteChunk;
|
private static readonly Action<PipeWriter, ArraySegment<byte>> _writeChunk = WriteChunk;
|
||||||
|
|
||||||
private readonly object _onStartingSync = new Object();
|
private readonly object _onStartingSync = new Object();
|
||||||
private readonly object _onCompletedSync = new Object();
|
private readonly object _onCompletedSync = new Object();
|
||||||
|
|
@ -895,13 +896,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return Output.WriteAsync(_writeChunk, data);
|
return Output.WriteAsync(_writeChunk, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteChunk(WritableBuffer writableBuffer, ArraySegment<byte> buffer)
|
private static void WriteChunk(PipeWriter writableBuffer, ArraySegment<byte> buffer)
|
||||||
{
|
{
|
||||||
var writer = new WritableBufferWriter(writableBuffer);
|
var writer = OutputWriter.Create(writableBuffer);
|
||||||
if (buffer.Count > 0)
|
if (buffer.Count > 0)
|
||||||
{
|
{
|
||||||
ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Count);
|
ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Count);
|
||||||
writer.Write(buffer.Array, buffer.Offset, buffer.Count);
|
writer.Write(new ReadOnlySpan<byte>(buffer.Array, buffer.Offset, buffer.Count));
|
||||||
ChunkWriter.WriteEndChunkBytes(ref writer);
|
ChunkWriter.WriteEndChunkBytes(ref writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1297,9 +1298,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
(
|
(
|
||||||
pool: _context.MemoryPool,
|
pool: _context.MemoryPool,
|
||||||
readerScheduler: ServiceContext.ThreadPool,
|
readerScheduler: ServiceContext.ThreadPool,
|
||||||
writerScheduler: Scheduler.Inline,
|
writerScheduler: PipeScheduler.Inline,
|
||||||
maximumSizeHigh: 1,
|
pauseWriterThreshold: 1,
|
||||||
maximumSizeLow: 1
|
resumeWriterThreshold: 1
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(ref WritableBufferWriter output)
|
public void CopyTo(ref OutputWriter<PipeWriter> output)
|
||||||
{
|
{
|
||||||
CopyToFast(ref output);
|
CopyToFast(ref output);
|
||||||
if (MaybeUnknown != null)
|
if (MaybeUnknown != null)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
public interface IHttpOutputProducer : IDisposable
|
public interface IHttpOutputProducer : IDisposable
|
||||||
{
|
{
|
||||||
void Abort(Exception error);
|
void Abort(Exception error);
|
||||||
Task WriteAsync<T>(Action<WritableBuffer, T> callback, T state);
|
Task WriteAsync<T>(Action<PipeWriter, T> callback, T state);
|
||||||
Task FlushAsync(CancellationToken cancellationToken);
|
Task FlushAsync(CancellationToken cancellationToken);
|
||||||
Task Write100ContinueAsync(CancellationToken cancellationToken);
|
Task Write100ContinueAsync(CancellationToken cancellationToken);
|
||||||
void WriteResponseHeaders(int statusCode, string ReasonPhrase, HttpResponseHeaders responseHeaders);
|
void WriteResponseHeaders(int statusCode, string ReasonPhrase, HttpResponseHeaders responseHeaders);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
|
||||||
|
|
@ -9,8 +10,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
public interface IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
|
public interface IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
|
||||||
{
|
{
|
||||||
bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined);
|
bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined);
|
||||||
|
|
||||||
bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position examined, out int consumedBytes);
|
bool ParseHeaders(TRequestHandler handler, ReadOnlyBuffer<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
// buffer.Count is int
|
// buffer.Count is int
|
||||||
var actual = (int) Math.Min(readableBuffer.Length, buffer.Count);
|
var actual = (int) Math.Min(readableBuffer.Length, buffer.Count);
|
||||||
var slice = readableBuffer.Slice(0, actual);
|
var slice = readableBuffer.Slice(0, actual);
|
||||||
consumed = readableBuffer.Move(readableBuffer.Start, actual);
|
consumed = readableBuffer.GetPosition(readableBuffer.Start, actual);
|
||||||
slice.CopyTo(buffer);
|
slice.CopyTo(buffer);
|
||||||
return actual;
|
return actual;
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_context.RequestBodyPipe.Reader.Advance(consumed);
|
_context.RequestBodyPipe.Reader.AdvanceTo(consumed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_context.RequestBodyPipe.Reader.Advance(consumed);
|
_context.RequestBodyPipe.Reader.AdvanceTo(consumed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private static byte[] _numericBytesScratch;
|
private static byte[] _numericBytesScratch;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ReadOnlySpan<byte> ToSpan(this ReadOnlyBuffer buffer)
|
public static ReadOnlySpan<byte> ToSpan(this ReadOnlyBuffer<byte> buffer)
|
||||||
{
|
{
|
||||||
if (buffer.IsSingleSpan)
|
if (buffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
return buffer.First.Span;
|
return buffer.First.Span;
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static void WriteAsciiNoValidation(ref this WritableBufferWriter buffer, string data)
|
public unsafe static void WriteAsciiNoValidation(ref this OutputWriter<PipeWriter> buffer, string data)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(data))
|
if (string.IsNullOrEmpty(data))
|
||||||
{
|
{
|
||||||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public unsafe static void WriteNumeric(ref this WritableBufferWriter buffer, ulong number)
|
public unsafe static void WriteNumeric(ref this OutputWriter<PipeWriter> buffer, ulong number)
|
||||||
{
|
{
|
||||||
const byte AsciiDigitStart = (byte)'0';
|
const byte AsciiDigitStart = (byte)'0';
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private static void WriteNumericMultiWrite(ref this WritableBufferWriter buffer, ulong number)
|
private static void WriteNumericMultiWrite(ref this OutputWriter<PipeWriter> buffer, ulong number)
|
||||||
{
|
{
|
||||||
const byte AsciiDigitStart = (byte)'0';
|
const byte AsciiDigitStart = (byte)'0';
|
||||||
|
|
||||||
|
|
@ -141,11 +141,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
while (value != 0);
|
while (value != 0);
|
||||||
|
|
||||||
var length = _maxULongByteLength - position;
|
var length = _maxULongByteLength - position;
|
||||||
buffer.Write(byteBuffer, position, length);
|
buffer.Write(new ReadOnlySpan<byte>(byteBuffer, position, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private unsafe static void WriteAsciiMultiWrite(ref this WritableBufferWriter buffer, string data)
|
private unsafe static void WriteAsciiMultiWrite(ref this OutputWriter<PipeWriter> buffer, string data)
|
||||||
{
|
{
|
||||||
var remaining = data.Length;
|
var remaining = data.Length;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
|
@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
|
|
||||||
public string ConnectionId => _context.ConnectionId;
|
public string ConnectionId => _context.ConnectionId;
|
||||||
|
|
||||||
public IPipeReader Input => _context.Transport.Input;
|
public PipeReader Input => _context.Transport.Input;
|
||||||
|
|
||||||
public IKestrelTrace Log => _context.ServiceContext.Log;
|
public IKestrelTrace Log => _context.ServiceContext.Log;
|
||||||
|
|
||||||
|
|
@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Input.Advance(consumed, examined);
|
Input.AdvanceTo(consumed, examined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Input.Advance(consumed, examined);
|
Input.AdvanceTo(consumed, examined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ParsePreface(ReadOnlyBuffer readableBuffer, out Position consumed, out Position examined)
|
private bool ParsePreface(ReadOnlyBuffer<byte> readableBuffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = readableBuffer.Start;
|
consumed = readableBuffer.Start;
|
||||||
examined = readableBuffer.End;
|
examined = readableBuffer.End;
|
||||||
|
|
@ -226,7 +227,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var span = readableBuffer.IsSingleSpan
|
var span = readableBuffer.IsSingleSegment
|
||||||
? readableBuffer.First.Span
|
? readableBuffer.First.Span
|
||||||
: readableBuffer.ToSpan();
|
: readableBuffer.ToSpan();
|
||||||
|
|
||||||
|
|
@ -238,7 +239,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
consumed = examined = readableBuffer.Move(readableBuffer.Start, ClientPreface.Length);
|
consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, ClientPreface.Length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
public IPEndPoint LocalEndPoint { get; set; }
|
public IPEndPoint LocalEndPoint { get; set; }
|
||||||
public IPEndPoint RemoteEndPoint { get; set; }
|
public IPEndPoint RemoteEndPoint { get; set; }
|
||||||
|
|
||||||
public IPipeConnection Transport { get; set; }
|
public IDuplexPipe Transport { get; set; }
|
||||||
public IPipeConnection Application { get; set; }
|
public IDuplexPipe Application { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Sequences;
|
using System.Collections.Sequences;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
|
||||||
|
|
@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
{
|
{
|
||||||
public static class Http2FrameReader
|
public static class Http2FrameReader
|
||||||
{
|
{
|
||||||
public static bool ReadFrame(ReadOnlyBuffer readableBuffer, Http2Frame frame, out Position consumed, out Position examined)
|
public static bool ReadFrame(ReadOnlyBuffer<byte> readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined)
|
||||||
{
|
{
|
||||||
consumed = readableBuffer.Start;
|
consumed = readableBuffer.Start;
|
||||||
examined = readableBuffer.End;
|
examined = readableBuffer.End;
|
||||||
|
|
@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
}
|
}
|
||||||
|
|
||||||
readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload);
|
readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload);
|
||||||
consumed = examined = readableBuffer.Move(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length);
|
consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -20,12 +21,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
private readonly Http2Frame _outgoingFrame = new Http2Frame();
|
private readonly Http2Frame _outgoingFrame = new Http2Frame();
|
||||||
private readonly object _writeLock = new object();
|
private readonly object _writeLock = new object();
|
||||||
private readonly HPackEncoder _hpackEncoder = new HPackEncoder();
|
private readonly HPackEncoder _hpackEncoder = new HPackEncoder();
|
||||||
private readonly IPipeWriter _outputWriter;
|
private readonly PipeWriter _outputWriter;
|
||||||
private readonly IPipeReader _outputReader;
|
private readonly PipeReader _outputReader;
|
||||||
|
|
||||||
private bool _completed;
|
private bool _completed;
|
||||||
|
|
||||||
public Http2FrameWriter(IPipeWriter outputPipeWriter, IPipeReader outputPipeReader)
|
public Http2FrameWriter(PipeWriter outputPipeWriter, PipeReader outputPipeReader)
|
||||||
{
|
{
|
||||||
_outputWriter = outputPipeWriter;
|
_outputWriter = outputPipeWriter;
|
||||||
_outputReader = outputPipeReader;
|
_outputReader = outputPipeReader;
|
||||||
|
|
@ -48,7 +49,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
|
|
||||||
public Task FlushAsync(CancellationToken cancellationToken)
|
public Task FlushAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return WriteAsync(Constants.EmptyData);
|
lock (_writeLock)
|
||||||
|
{
|
||||||
|
return WriteAsync(Constants.EmptyData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Write100ContinueAsync(int streamId)
|
public Task Write100ContinueAsync(int streamId)
|
||||||
|
|
@ -185,9 +189,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeableBuffer = _outputWriter.Alloc(1);
|
_outputWriter.Write(data);
|
||||||
writeableBuffer.Write(data);
|
_outputWriter.Commit();
|
||||||
writeableBuffer.Commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be called with _writeLock
|
// Must be called with _writeLock
|
||||||
|
|
@ -198,9 +201,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeableBuffer = _outputWriter.Alloc(1);
|
_outputWriter.Write(data);
|
||||||
writeableBuffer.Write(data);
|
await _outputWriter.FlushAsync(cancellationToken);
|
||||||
await writeableBuffer.FlushAsync(cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<KeyValuePair<string, string>> EnumerateHeaders(IHeaderDictionary headers)
|
private static IEnumerable<KeyValuePair<string, string>> EnumerateHeaders(IHeaderDictionary headers)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
// TODO: RST_STREAM?
|
// TODO: RST_STREAM?
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task WriteAsync<T>(Action<WritableBuffer, T> callback, T state)
|
public Task WriteAsync<T>(Action<PipeWriter, T> callback, T state)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
|
|
@ -78,19 +79,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
|
||||||
{
|
{
|
||||||
if (data.Count > 0)
|
if (data.Count > 0)
|
||||||
{
|
{
|
||||||
var writableBuffer = RequestBodyPipe.Writer.Alloc(1);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
writableBuffer.Write(data);
|
RequestBodyPipe.Writer.Write(data);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
writableBuffer.Commit();
|
RequestBodyPipe.Writer.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestBodyStarted = true;
|
RequestBodyStarted = true;
|
||||||
await writableBuffer.FlushAsync();
|
await RequestBodyPipe.Writer.FlushAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endStream)
|
if (endStream)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
private IList<IAdaptedConnection> _adaptedConnections;
|
private IList<IAdaptedConnection> _adaptedConnections;
|
||||||
private IPipeConnection _adaptedTransport;
|
private IDuplexPipe _adaptedTransport;
|
||||||
|
|
||||||
private readonly object _protocolSelectionLock = new object();
|
private readonly object _protocolSelectionLock = new object();
|
||||||
private ProtocolSelectionState _protocolSelectionState = ProtocolSelectionState.Initializing;
|
private ProtocolSelectionState _protocolSelectionState = ProtocolSelectionState.Initializing;
|
||||||
|
|
@ -75,18 +75,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
(
|
(
|
||||||
pool: MemoryPool,
|
pool: MemoryPool,
|
||||||
readerScheduler: _context.ServiceContext.ThreadPool,
|
readerScheduler: _context.ServiceContext.ThreadPool,
|
||||||
writerScheduler: Scheduler.Inline,
|
writerScheduler: PipeScheduler.Inline,
|
||||||
maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
|
pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
|
||||||
maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
|
resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions
|
internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions
|
||||||
(
|
(
|
||||||
pool: MemoryPool,
|
pool: MemoryPool,
|
||||||
readerScheduler: Scheduler.Inline,
|
readerScheduler: PipeScheduler.Inline,
|
||||||
writerScheduler: Scheduler.Inline,
|
writerScheduler: PipeScheduler.Inline,
|
||||||
maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0,
|
pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0,
|
||||||
maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0
|
resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
private IKestrelTrace Log => _context.ServiceContext.Log;
|
private IKestrelTrace Log => _context.ServiceContext.Log;
|
||||||
|
|
@ -196,13 +196,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing only
|
// For testing only
|
||||||
internal void Initialize(IPipeConnection transport, IPipeConnection application)
|
internal void Initialize(IDuplexPipe transport, IDuplexPipe application)
|
||||||
{
|
{
|
||||||
_requestProcessor = _http1Connection = CreateHttp1Connection(transport, application);
|
_requestProcessor = _http1Connection = CreateHttp1Connection(transport, application);
|
||||||
_protocolSelectionState = ProtocolSelectionState.Selected;
|
_protocolSelectionState = ProtocolSelectionState.Selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Http1Connection CreateHttp1Connection(IPipeConnection transport, IPipeConnection application)
|
private Http1Connection CreateHttp1Connection(IDuplexPipe transport, IDuplexPipe application)
|
||||||
{
|
{
|
||||||
return new Http1Connection(new Http1ConnectionContext
|
return new Http1Connection(new Http1ConnectionContext
|
||||||
{
|
{
|
||||||
|
|
@ -218,7 +218,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Http2Connection CreateHttp2Connection(IPipeConnection transport, IPipeConnection application)
|
private Http2Connection CreateHttp2Connection(IDuplexPipe transport, IDuplexPipe application)
|
||||||
{
|
{
|
||||||
return new Http2Connection(new Http2ConnectionContext
|
return new Http2Connection(new Http2ConnectionContext
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
public MemoryPool MemoryPool { get; set; }
|
public MemoryPool MemoryPool { get; set; }
|
||||||
public IPEndPoint LocalEndPoint { get; set; }
|
public IPEndPoint LocalEndPoint { get; set; }
|
||||||
public IPEndPoint RemoteEndPoint { get; set; }
|
public IPEndPoint RemoteEndPoint { get; set; }
|
||||||
public IPipeConnection Transport { get; set; }
|
public IDuplexPipe Transport { get; set; }
|
||||||
public IPipeConnection Application { get; set; }
|
public IDuplexPipe Application { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO.Pipelines;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
{
|
{
|
||||||
public abstract class KestrelThreadPool: Scheduler
|
public abstract class KestrelThreadPool : PipeScheduler
|
||||||
{
|
{
|
||||||
public abstract void Run(Action action);
|
public abstract void Run(Action action);
|
||||||
public abstract void UnsafeRun(WaitCallback action, object state);
|
public abstract void UnsafeRun(WaitCallback action, object state);
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
|
|
||||||
public override void Run(Action action)
|
public override void Run(Action action)
|
||||||
{
|
{
|
||||||
ThreadPool.QueueUserWorkItem(_runAction, action);
|
System.Threading.ThreadPool.QueueUserWorkItem(_runAction, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UnsafeRun(WaitCallback action, object state)
|
public override void UnsafeRun(WaitCallback action, object state)
|
||||||
{
|
{
|
||||||
ThreadPool.QueueUserWorkItem(action, state);
|
System.Threading.ThreadPool.QueueUserWorkItem(action, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Schedule(Action action)
|
public override void Schedule(Action action)
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
|
|
||||||
MemoryPool IConnectionTransportFeature.MemoryPool => MemoryPool;
|
MemoryPool IConnectionTransportFeature.MemoryPool => MemoryPool;
|
||||||
|
|
||||||
IPipeConnection IConnectionTransportFeature.Transport
|
IDuplexPipe IConnectionTransportFeature.Transport
|
||||||
{
|
{
|
||||||
get => Transport;
|
get => Transport;
|
||||||
set => Transport = value;
|
set => Transport = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPipeConnection IConnectionTransportFeature.Application
|
IDuplexPipe IConnectionTransportFeature.Application
|
||||||
{
|
{
|
||||||
get => Application;
|
get => Application;
|
||||||
set => Application = value;
|
set => Application = value;
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal
|
||||||
public string ConnectionId { get; set; }
|
public string ConnectionId { get; set; }
|
||||||
|
|
||||||
public virtual MemoryPool MemoryPool { get; }
|
public virtual MemoryPool MemoryPool { get; }
|
||||||
public virtual Scheduler InputWriterScheduler { get; }
|
public virtual PipeScheduler InputWriterScheduler { get; }
|
||||||
public virtual Scheduler OutputReaderScheduler { get; }
|
public virtual PipeScheduler OutputReaderScheduler { get; }
|
||||||
|
|
||||||
public IPipeConnection Transport { get; set; }
|
public IDuplexPipe Transport { get; set; }
|
||||||
public IPipeConnection Application { get; set; }
|
public IDuplexPipe Application { get; set; }
|
||||||
|
|
||||||
public IPipeWriter Input => Application.Output;
|
public PipeWriter Input => Application.Output;
|
||||||
public IPipeReader Output => Application.Input;
|
public PipeReader Output => Application.Input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
private readonly UvStreamHandle _socket;
|
private readonly UvStreamHandle _socket;
|
||||||
|
|
||||||
private WritableBuffer? _currentWritableBuffer;
|
|
||||||
private MemoryHandle _bufferHandle;
|
private MemoryHandle _bufferHandle;
|
||||||
|
|
||||||
public LibuvConnection(ListenerContext context, UvStreamHandle socket) : base(context)
|
public LibuvConnection(ListenerContext context, UvStreamHandle socket) : base(context)
|
||||||
|
|
@ -107,13 +106,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
|
|
||||||
private unsafe LibuvFunctions.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
|
private unsafe LibuvFunctions.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
|
||||||
{
|
{
|
||||||
Debug.Assert(_currentWritableBuffer == null);
|
var currentWritableBuffer = Input.GetMemory(MinAllocBufferSize);
|
||||||
var currentWritableBuffer = Input.Alloc(MinAllocBufferSize);
|
_bufferHandle = currentWritableBuffer.Retain(true);
|
||||||
_currentWritableBuffer = currentWritableBuffer;
|
|
||||||
|
|
||||||
_bufferHandle = currentWritableBuffer.Buffer.Retain(true);
|
return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Length);
|
||||||
|
|
||||||
return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Buffer.Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReadCallback(UvStreamHandle handle, int status, object state)
|
private static void ReadCallback(UvStreamHandle handle, int status, object state)
|
||||||
|
|
@ -127,17 +123,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
{
|
{
|
||||||
// EAGAIN/EWOULDBLOCK so just return the buffer.
|
// EAGAIN/EWOULDBLOCK so just return the buffer.
|
||||||
// http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb
|
// http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb
|
||||||
Debug.Assert(_currentWritableBuffer != null);
|
Input.Commit();
|
||||||
_currentWritableBuffer.Value.Commit();
|
|
||||||
}
|
}
|
||||||
else if (status > 0)
|
else if (status > 0)
|
||||||
{
|
{
|
||||||
Log.ConnectionRead(ConnectionId, status);
|
Log.ConnectionRead(ConnectionId, status);
|
||||||
|
|
||||||
Debug.Assert(_currentWritableBuffer != null);
|
Input.Advance(status);
|
||||||
var currentWritableBuffer = _currentWritableBuffer.Value;
|
var flushTask = Input.FlushAsync();
|
||||||
currentWritableBuffer.Advance(status);
|
|
||||||
var flushTask = currentWritableBuffer.FlushAsync();
|
|
||||||
|
|
||||||
if (!flushTask.IsCompleted)
|
if (!flushTask.IsCompleted)
|
||||||
{
|
{
|
||||||
|
|
@ -149,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Given a negative status, it's possible that OnAlloc wasn't called.
|
// Given a negative status, it's possible that OnAlloc wasn't called.
|
||||||
_currentWritableBuffer?.Commit();
|
Input.Commit();
|
||||||
_socket.ReadStop();
|
_socket.ReadStop();
|
||||||
|
|
||||||
IOException error = null;
|
IOException error = null;
|
||||||
|
|
@ -180,7 +173,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup state from last OnAlloc. This is safe even if OnAlloc wasn't called.
|
// Cleanup state from last OnAlloc. This is safe even if OnAlloc wasn't called.
|
||||||
_currentWritableBuffer = null;
|
|
||||||
_bufferHandle.Dispose();
|
_bufferHandle.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
public ListenerContext ListenerContext { get; set; }
|
public ListenerContext ListenerContext { get; set; }
|
||||||
|
|
||||||
public override MemoryPool MemoryPool => ListenerContext.Thread.MemoryPool;
|
public override MemoryPool MemoryPool => ListenerContext.Thread.MemoryPool;
|
||||||
public override Scheduler InputWriterScheduler => ListenerContext.Thread;
|
public override PipeScheduler InputWriterScheduler => ListenerContext.Thread;
|
||||||
public override Scheduler OutputReaderScheduler => ListenerContext.Thread;
|
public override PipeScheduler OutputReaderScheduler => ListenerContext.Thread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
private readonly UvStreamHandle _socket;
|
private readonly UvStreamHandle _socket;
|
||||||
private readonly string _connectionId;
|
private readonly string _connectionId;
|
||||||
private readonly ILibuvTrace _log;
|
private readonly ILibuvTrace _log;
|
||||||
private readonly IPipeReader _pipe;
|
private readonly PipeReader _pipe;
|
||||||
|
|
||||||
public LibuvOutputConsumer(
|
public LibuvOutputConsumer(
|
||||||
IPipeReader pipe,
|
PipeReader pipe,
|
||||||
LibuvThread thread,
|
LibuvThread thread,
|
||||||
UvStreamHandle socket,
|
UvStreamHandle socket,
|
||||||
string connectionId,
|
string connectionId,
|
||||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_pipe.Advance(consumed);
|
_pipe.AdvanceTo(consumed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
|
||||||
{
|
{
|
||||||
public class LibuvThread : Scheduler
|
public class LibuvThread : PipeScheduler
|
||||||
{
|
{
|
||||||
// maximum times the work queues swapped and are processed in a single pass
|
// maximum times the work queues swapped and are processed in a single pass
|
||||||
// as completing a task may immediately have write data to put on the network
|
// as completing a task may immediately have write data to put on the network
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
||||||
_bufs = handle + requestSize;
|
_bufs = handle + requestSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlyBuffer buffer)
|
public LibuvAwaitable<UvWriteReq> WriteAsync(UvStreamHandle handle, ReadOnlyBuffer<byte> buffer)
|
||||||
{
|
{
|
||||||
Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable);
|
Write(handle, buffer, LibuvAwaitable<UvWriteReq>.Callback, _awaitable);
|
||||||
return _awaitable;
|
return _awaitable;
|
||||||
|
|
@ -63,14 +63,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin
|
||||||
|
|
||||||
private unsafe void Write(
|
private unsafe void Write(
|
||||||
UvStreamHandle handle,
|
UvStreamHandle handle,
|
||||||
ReadOnlyBuffer buffer,
|
ReadOnlyBuffer<byte> buffer,
|
||||||
Action<UvWriteReq, int, UvException, object> callback,
|
Action<UvWriteReq, int, UvException, object> callback,
|
||||||
object state)
|
object state)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var nBuffers = 0;
|
var nBuffers = 0;
|
||||||
if (buffer.IsSingleSpan)
|
if (buffer.IsSingleSegment)
|
||||||
{
|
{
|
||||||
nBuffers = 1;
|
nBuffers = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
public override MemoryPool MemoryPool { get; }
|
public override MemoryPool MemoryPool { get; }
|
||||||
public override Scheduler InputWriterScheduler => Scheduler.Inline;
|
public override PipeScheduler InputWriterScheduler => PipeScheduler.Inline;
|
||||||
public override Scheduler OutputReaderScheduler => Scheduler.TaskRun;
|
public override PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool;
|
||||||
|
|
||||||
public async Task StartAsync(IConnectionHandler connectionHandler)
|
public async Task StartAsync(IConnectionHandler connectionHandler)
|
||||||
{
|
{
|
||||||
|
|
@ -96,11 +96,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Ensure we have some reasonable amount of buffer space
|
// Ensure we have some reasonable amount of buffer space
|
||||||
var buffer = Input.Alloc(MinAllocBufferSize);
|
var buffer = Input.GetMemory(MinAllocBufferSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var bytesReceived = await _receiver.ReceiveAsync(buffer.Buffer);
|
var bytesReceived = await _receiver.ReceiveAsync(buffer);
|
||||||
|
|
||||||
if (bytesReceived == 0)
|
if (bytesReceived == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -109,14 +109,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.Advance(bytesReceived);
|
Input.Advance(bytesReceived);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
buffer.Commit();
|
Input.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
var flushTask = buffer.FlushAsync();
|
var flushTask = Input.FlushAsync();
|
||||||
|
|
||||||
if (!flushTask.IsCompleted)
|
if (!flushTask.IsCompleted)
|
||||||
{
|
{
|
||||||
|
|
@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Output.Advance(buffer.End);
|
Output.AdvanceTo(buffer.End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
_eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError);
|
_eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketAwaitable SendAsync(ReadOnlyBuffer buffers)
|
public SocketAwaitable SendAsync(ReadOnlyBuffer<byte> buffers)
|
||||||
{
|
{
|
||||||
if (buffers.IsSingleSpan)
|
if (buffers.IsSingleSegment)
|
||||||
{
|
{
|
||||||
return SendAsync(buffers.First);
|
return SendAsync(buffers.First);
|
||||||
}
|
}
|
||||||
|
|
@ -75,10 +75,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
return _awaitable;
|
return _awaitable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer buffer)
|
private List<ArraySegment<byte>> GetBufferList(ReadOnlyBuffer<byte> buffer)
|
||||||
{
|
{
|
||||||
Debug.Assert(!buffer.IsEmpty);
|
Debug.Assert(!buffer.IsEmpty);
|
||||||
Debug.Assert(!buffer.IsSingleSpan);
|
Debug.Assert(!buffer.IsSingleSegment);
|
||||||
|
|
||||||
if (_bufferList == null)
|
if (_bufferList == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Protocols
|
||||||
|
|
||||||
public abstract IFeatureCollection Features { get; }
|
public abstract IFeatureCollection Features { get; }
|
||||||
|
|
||||||
public abstract IPipeConnection Transport { get; set; }
|
public abstract IDuplexPipe Transport { get; set; }
|
||||||
|
|
||||||
public abstract MemoryPool MemoryPool { get; }
|
public abstract MemoryPool MemoryPool { get; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Protocols
|
||||||
|
|
||||||
public override MemoryPool MemoryPool => ConnectionTransportFeature.MemoryPool;
|
public override MemoryPool MemoryPool => ConnectionTransportFeature.MemoryPool;
|
||||||
|
|
||||||
public override IPipeConnection Transport
|
public override IDuplexPipe Transport
|
||||||
{
|
{
|
||||||
get => ConnectionTransportFeature.Transport;
|
get => ConnectionTransportFeature.Transport;
|
||||||
set => ConnectionTransportFeature.Transport = value;
|
set => ConnectionTransportFeature.Transport = value;
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ namespace Microsoft.AspNetCore.Protocols.Features
|
||||||
{
|
{
|
||||||
MemoryPool MemoryPool { get; }
|
MemoryPool MemoryPool { get; }
|
||||||
|
|
||||||
IPipeConnection Transport { get; set; }
|
IDuplexPipe Transport { get; set; }
|
||||||
|
|
||||||
IPipeConnection Application { get; set; }
|
IDuplexPipe Application { get; set; }
|
||||||
|
|
||||||
Scheduler InputWriterScheduler { get; }
|
PipeScheduler InputWriterScheduler { get; }
|
||||||
|
|
||||||
Scheduler OutputReaderScheduler { get; }
|
PipeScheduler OutputReaderScheduler { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ using System.Text;
|
||||||
|
|
||||||
namespace System.IO.Pipelines
|
namespace System.IO.Pipelines
|
||||||
{
|
{
|
||||||
public class PipeConnection : IPipeConnection
|
public class PipeConnection : IDuplexPipe
|
||||||
{
|
{
|
||||||
public PipeConnection(IPipeReader reader, IPipeWriter writer)
|
public PipeConnection(PipeReader reader, PipeWriter writer)
|
||||||
{
|
{
|
||||||
Input = reader;
|
Input = reader;
|
||||||
Output = writer;
|
Output = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPipeReader Input { get; }
|
public PipeReader Input { get; }
|
||||||
|
|
||||||
public IPipeWriter Output { get; }
|
public PipeWriter Output { get; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ namespace System.IO.Pipelines
|
||||||
{
|
{
|
||||||
public static class PipeFactory
|
public static class PipeFactory
|
||||||
{
|
{
|
||||||
public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(MemoryPool memoryPool)
|
public static (IDuplexPipe Transport, IDuplexPipe Application) CreateConnectionPair(MemoryPool memoryPool)
|
||||||
{
|
{
|
||||||
return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool));
|
return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions)
|
public static (IDuplexPipe Transport, IDuplexPipe Application) CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions)
|
||||||
{
|
{
|
||||||
var input = new Pipe(inputOptions);
|
var input = new Pipe(inputOptions);
|
||||||
var output = new Pipe(outputOptions);
|
var output = new Pipe(outputOptions);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
using System;
|
using System.Buffers;
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
@ -55,12 +53,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
public MemoryPool MemoryPool { get; } = new MemoryPool();
|
public MemoryPool MemoryPool { get; } = new MemoryPool();
|
||||||
|
|
||||||
public IPipeConnection Transport { get; set; }
|
public IDuplexPipe Transport { get; set; }
|
||||||
public IPipeConnection Application { get; set; }
|
public IDuplexPipe Application { get; set; }
|
||||||
|
|
||||||
public Scheduler InputWriterScheduler => Scheduler.TaskRun;
|
public PipeScheduler InputWriterScheduler => PipeScheduler.ThreadPool;
|
||||||
|
|
||||||
public Scheduler OutputReaderScheduler => Scheduler.TaskRun;
|
public PipeScheduler OutputReaderScheduler => PipeScheduler.ThreadPool;
|
||||||
|
|
||||||
public string ConnectionId { get; set; }
|
public string ConnectionId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
{
|
{
|
||||||
public class Http1ConnectionTests : IDisposable
|
public class Http1ConnectionTests : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IPipeConnection _transport;
|
private readonly IDuplexPipe _transport;
|
||||||
private readonly IPipeConnection _application;
|
private readonly IDuplexPipe _application;
|
||||||
private readonly TestHttp1Connection _http1Connection;
|
private readonly TestHttp1Connection _http1Connection;
|
||||||
private readonly ServiceContext _serviceContext;
|
private readonly ServiceContext _serviceContext;
|
||||||
private readonly Http1ConnectionContext _http1ConnectionContext;
|
private readonly Http1ConnectionContext _http1ConnectionContext;
|
||||||
private readonly MemoryPool _pipelineFactory;
|
private readonly MemoryPool _pipelineFactory;
|
||||||
private Position _consumed;
|
private SequencePosition _consumed;
|
||||||
private Position _examined;
|
private SequencePosition _examined;
|
||||||
private Mock<ITimeoutControl> _timeoutControl;
|
private Mock<ITimeoutControl> _timeoutControl;
|
||||||
|
|
||||||
public Http1ConnectionTests()
|
public Http1ConnectionTests()
|
||||||
|
|
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
|
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, exception.Message);
|
Assert.Equal(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, exception.Message);
|
||||||
Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode);
|
Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode);
|
||||||
|
|
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
|
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.BadRequest_TooManyHeaders, exception.Message);
|
Assert.Equal(CoreStrings.BadRequest_TooManyHeaders, exception.Message);
|
||||||
Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode);
|
Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode);
|
||||||
|
|
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
|
|
||||||
var takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined);
|
var takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined);
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.True(takeMessageHeaders);
|
Assert.True(takeMessageHeaders);
|
||||||
Assert.Equal(1, _http1Connection.RequestHeaders.Count);
|
Assert.Equal(1, _http1Connection.RequestHeaders.Count);
|
||||||
|
|
@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
|
|
||||||
takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined);
|
takeMessageHeaders = _http1Connection.TakeMessageHeaders(readableBuffer, out _consumed, out _examined);
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.True(takeMessageHeaders);
|
Assert.True(takeMessageHeaders);
|
||||||
Assert.Equal(1, _http1Connection.RequestHeaders.Count);
|
Assert.Equal(1, _http1Connection.RequestHeaders.Count);
|
||||||
|
|
@ -342,7 +342,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
|
|
||||||
var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined);
|
var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined);
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.True(returnValue);
|
Assert.True(returnValue);
|
||||||
Assert.Equal(expectedMethod, _http1Connection.Method);
|
Assert.Equal(expectedMethod, _http1Connection.Method);
|
||||||
|
|
@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
|
|
||||||
var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined);
|
var returnValue = _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined);
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.True(returnValue);
|
Assert.True(returnValue);
|
||||||
Assert.Equal(expectedRawTarget, _http1Connection.RawTarget);
|
Assert.Equal(expectedRawTarget, _http1Connection.RawTarget);
|
||||||
|
|
@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("G"));
|
await _application.Output.WriteAsync(Encoding.ASCII.GetBytes("G"));
|
||||||
|
|
||||||
_http1Connection.ParseRequest((await _transport.Input.ReadAsync()).Buffer, out _consumed, out _examined);
|
_http1Connection.ParseRequest((await _transport.Input.ReadAsync()).Buffer, out _consumed, out _examined);
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
var expectedRequestHeadersTimeout = _serviceContext.ServerOptions.Limits.RequestHeadersTimeout.Ticks;
|
var expectedRequestHeadersTimeout = _serviceContext.ServerOptions.Limits.RequestHeadersTimeout.Ticks;
|
||||||
_timeoutControl.Verify(cc => cc.ResetTimeout(expectedRequestHeadersTimeout, TimeoutAction.SendTimeoutResponse));
|
_timeoutControl.Verify(cc => cc.ResetTimeout(expectedRequestHeadersTimeout, TimeoutAction.SendTimeoutResponse));
|
||||||
|
|
@ -395,7 +395,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
var readableBuffer = (await _transport.Input.ReadAsync()).Buffer;
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
var exception = Assert.Throws<BadHttpRequestException>(() => _http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.BadRequest_RequestLineTooLong, exception.Message);
|
Assert.Equal(CoreStrings.BadRequest_RequestLineTooLong, exception.Message);
|
||||||
Assert.Equal(StatusCodes.Status414UriTooLong, exception.StatusCode);
|
Assert.Equal(StatusCodes.Status414UriTooLong, exception.StatusCode);
|
||||||
|
|
@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target), exception.Message);
|
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target), exception.Message);
|
||||||
}
|
}
|
||||||
|
|
@ -424,7 +424,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
|
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
|
||||||
}
|
}
|
||||||
|
|
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(requestLine.EscapeNonPrintable()), exception.Message);
|
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(requestLine.EscapeNonPrintable()), exception.Message);
|
||||||
}
|
}
|
||||||
|
|
@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
|
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
|
||||||
}
|
}
|
||||||
|
|
@ -472,7 +472,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
|
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(target.EscapeNonPrintable()), exception.Message);
|
||||||
}
|
}
|
||||||
|
|
@ -486,7 +486,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(405, exception.StatusCode);
|
Assert.Equal(405, exception.StatusCode);
|
||||||
Assert.Equal(CoreStrings.BadRequest_MethodNotAllowed, exception.Message);
|
Assert.Equal(CoreStrings.BadRequest_MethodNotAllowed, exception.Message);
|
||||||
|
|
@ -685,7 +685,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
_http1Connection.TakeStartLine(readableBuffer, out _consumed, out _examined));
|
||||||
_transport.Input.Advance(_consumed, _examined);
|
_transport.Input.AdvanceTo(_consumed, _examined);
|
||||||
|
|
||||||
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(string.Empty), exception.Message);
|
Assert.Equal(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(string.Empty), exception.Message);
|
||||||
Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);
|
Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize));
|
private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize));
|
||||||
|
|
||||||
private readonly MemoryPool _memoryPool = new MemoryPool();
|
private readonly MemoryPool _memoryPool = new MemoryPool();
|
||||||
private readonly (IPipeConnection Transport, IPipeConnection Application) _pair;
|
private readonly (IDuplexPipe Transport, IDuplexPipe Application) _pair;
|
||||||
private readonly TestApplicationErrorLogger _logger;
|
private readonly TestApplicationErrorLogger _logger;
|
||||||
private readonly Http2ConnectionContext _connectionContext;
|
private readonly Http2ConnectionContext _connectionContext;
|
||||||
private readonly Http2Connection _connection;
|
private readonly Http2Connection _connection;
|
||||||
|
|
@ -2138,7 +2138,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
private async Task SendAsync(ArraySegment<byte> span)
|
private async Task SendAsync(ArraySegment<byte> span)
|
||||||
{
|
{
|
||||||
var writableBuffer = _pair.Application.Output.Alloc(1);
|
var writableBuffer = _pair.Application.Output;
|
||||||
writableBuffer.Write(span);
|
writableBuffer.Write(span);
|
||||||
await writableBuffer.FlushAsync();
|
await writableBuffer.FlushAsync();
|
||||||
}
|
}
|
||||||
|
|
@ -2466,7 +2466,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_pair.Application.Input.Advance(consumed, examined);
|
_pair.Application.Input.AdvanceTo(consumed, examined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
string expectedVersion)
|
string expectedVersion)
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
Assert.True(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
Assert.True(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
||||||
|
|
@ -45,8 +45,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.Equal(requestHandler.RawTarget, expectedRawTarget);
|
Assert.Equal(requestHandler.RawTarget, expectedRawTarget);
|
||||||
Assert.Equal(requestHandler.RawPath, expectedRawPath);
|
Assert.Equal(requestHandler.RawPath, expectedRawPath);
|
||||||
Assert.Equal(requestHandler.Version, expectedVersion);
|
Assert.Equal(requestHandler.Version, expectedVersion);
|
||||||
Assert.Equal(buffer.End, consumed);
|
Assert.True(buffer.Slice(consumed).IsEmpty);
|
||||||
Assert.Equal(buffer.End, examined);
|
Assert.True(buffer.Slice(examined).IsEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine)
|
public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine)
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
||||||
|
|
@ -65,13 +65,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine)
|
public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine)
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
||||||
|
|
||||||
Assert.Equal(buffer.Start, consumed);
|
Assert.Equal(buffer.Start, consumed);
|
||||||
Assert.Equal(buffer.End, examined);
|
Assert.True(buffer.Slice(examined).IsEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var parser = CreateParser(mockTrace.Object);
|
var parser = CreateParser(mockTrace.Object);
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var parser = CreateParser(mockTrace.Object);
|
var parser = CreateParser(mockTrace.Object);
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var parser = CreateParser(mockTrace.Object);
|
var parser = CreateParser(mockTrace.Object);
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(requestLine));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(requestLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
|
|
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
|
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
Assert.False(parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
|
Assert.False(parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
|
||||||
}
|
}
|
||||||
|
|
@ -204,12 +204,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
|
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
|
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
|
||||||
|
|
||||||
Assert.Equal(buffer.Start, consumed);
|
Assert.Equal(buffer.Length, buffer.Slice(consumed).Length);
|
||||||
Assert.Equal(buffer.End, examined);
|
Assert.True(buffer.Slice(examined).IsEmpty);
|
||||||
Assert.Equal(0, consumedBytes);
|
Assert.Equal(0, consumedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,19 +294,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
|
|
||||||
const string headerLine = "Header: value\r\n\r";
|
const string headerLine = "Header: value\r\n\r";
|
||||||
var buffer1 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(headerLine));
|
var buffer1 = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(headerLine));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes));
|
Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes));
|
||||||
|
|
||||||
Assert.Equal(buffer1.Move(buffer1.Start, headerLine.Length - 1), consumed);
|
Assert.Equal(buffer1.GetPosition(buffer1.Start, headerLine.Length - 1), consumed);
|
||||||
Assert.Equal(buffer1.End, examined);
|
Assert.Equal(buffer1.End, examined);
|
||||||
Assert.Equal(headerLine.Length - 1, consumedBytes);
|
Assert.Equal(headerLine.Length - 1, consumedBytes);
|
||||||
|
|
||||||
var buffer2 = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("\r\n"));
|
var buffer2 = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("\r\n"));
|
||||||
Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes));
|
Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes));
|
||||||
|
|
||||||
Assert.Equal(buffer2.End, consumed);
|
Assert.True(buffer2.Slice(consumed).IsEmpty);
|
||||||
Assert.Equal(buffer2.End, examined);
|
Assert.True(buffer2.Slice(examined).IsEmpty);
|
||||||
Assert.Equal(2, consumedBytes);
|
Assert.Equal(2, consumedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
var parser = CreateParser(mockTrace.Object);
|
var parser = CreateParser(mockTrace.Object);
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
|
|
@ -341,7 +341,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var parser = CreateParser(mockTrace.Object);
|
var parser = CreateParser(mockTrace.Object);
|
||||||
|
|
||||||
// Invalid request line
|
// Invalid request line
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n"));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n"));
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
|
|
@ -351,7 +351,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode);
|
Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode);
|
||||||
|
|
||||||
// Unrecognized HTTP version
|
// Unrecognized HTTP version
|
||||||
buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n"));
|
buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n"));
|
||||||
|
|
||||||
exception = Assert.Throws<BadHttpRequestException>(() =>
|
exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));
|
||||||
|
|
@ -360,7 +360,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, (exception as BadHttpRequestException).StatusCode);
|
Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, (exception as BadHttpRequestException).StatusCode);
|
||||||
|
|
||||||
// Invalid request header
|
// Invalid request header
|
||||||
buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes("Header: value\n\r\n"));
|
buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes("Header: value\n\r\n"));
|
||||||
|
|
||||||
exception = Assert.Throws<BadHttpRequestException>(() =>
|
exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
|
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));
|
||||||
|
|
@ -375,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
string expectedHeaderValue)
|
string expectedHeaderValue)
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n"));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n"));
|
||||||
|
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
|
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
|
||||||
|
|
@ -384,8 +384,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.Single(pairs);
|
Assert.Single(pairs);
|
||||||
Assert.Equal(headerName, pairs[0].Key);
|
Assert.Equal(headerName, pairs[0].Key);
|
||||||
Assert.Equal(expectedHeaderValue, pairs[0].Value);
|
Assert.Equal(expectedHeaderValue, pairs[0].Value);
|
||||||
Assert.Equal(buffer.End, consumed);
|
Assert.True(buffer.Slice(consumed).IsEmpty);
|
||||||
Assert.Equal(buffer.End, examined);
|
Assert.True(buffer.Slice(examined).IsEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VerifyRawHeaders(string rawHeaders, IEnumerable<string> expectedHeaderNames, IEnumerable<string> expectedHeaderValues)
|
private void VerifyRawHeaders(string rawHeaders, IEnumerable<string> expectedHeaderNames, IEnumerable<string> expectedHeaderValues)
|
||||||
|
|
@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match");
|
Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match");
|
||||||
|
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
||||||
var buffer = new ReadOnlyBuffer(Encoding.ASCII.GetBytes(rawHeaders));
|
var buffer = new ReadOnlyBuffer<byte>(Encoding.ASCII.GetBytes(rawHeaders));
|
||||||
|
|
||||||
var requestHandler = new RequestHandler();
|
var requestHandler = new RequestHandler();
|
||||||
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
|
parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);
|
||||||
|
|
@ -403,8 +403,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length);
|
Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length);
|
||||||
Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key));
|
Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key));
|
||||||
Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value));
|
Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value));
|
||||||
Assert.Equal(buffer.End, consumed);
|
Assert.True(buffer.Slice(consumed).IsEmpty);
|
||||||
Assert.Equal(buffer.End, examined);
|
Assert.True(buffer.Slice(examined).IsEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IHttpParser<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log.IsEnabled(LogLevel.Information));
|
private IHttpParser<RequestHandler> CreateParser(IKestrelTrace log) => new HttpParser<RequestHandler>(log.IsEnabled(LogLevel.Information));
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -445,23 +446,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
// The block returned by IncomingStart always has at least 2048 available bytes,
|
// The block returned by IncomingStart always has at least 2048 available bytes,
|
||||||
// so no need to bounds check in this test.
|
// so no need to bounds check in this test.
|
||||||
var bytes = Encoding.ASCII.GetBytes(data[0]);
|
var bytes = Encoding.ASCII.GetBytes(data[0]);
|
||||||
var buffer = input.Application.Output.Alloc(2048);
|
var buffer = input.Application.Output.GetMemory(2028);
|
||||||
ArraySegment<byte> block;
|
ArraySegment<byte> block;
|
||||||
Assert.True(buffer.Buffer.TryGetArray(out block));
|
Assert.True(MemoryMarshal.TryGetArray(buffer, out block));
|
||||||
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
|
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
|
||||||
buffer.Advance(bytes.Length);
|
input.Application.Output.Advance(bytes.Length);
|
||||||
await buffer.FlushAsync();
|
await input.Application.Output.FlushAsync();
|
||||||
|
|
||||||
// Verify the block passed to WriteAsync is the same one incoming data was written into.
|
// Verify the block passed to WriteAsync is the same one incoming data was written into.
|
||||||
Assert.Same(block.Array, await writeTcs.Task);
|
Assert.Same(block.Array, await writeTcs.Task);
|
||||||
|
|
||||||
writeTcs = new TaskCompletionSource<byte[]>();
|
writeTcs = new TaskCompletionSource<byte[]>();
|
||||||
bytes = Encoding.ASCII.GetBytes(data[1]);
|
bytes = Encoding.ASCII.GetBytes(data[1]);
|
||||||
buffer = input.Application.Output.Alloc(2048);
|
buffer = input.Application.Output.GetMemory(2048);
|
||||||
Assert.True(buffer.Buffer.TryGetArray(out block));
|
Assert.True(MemoryMarshal.TryGetArray(buffer, out block));
|
||||||
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
|
Buffer.BlockCopy(bytes, 0, block.Array, block.Offset, bytes.Length);
|
||||||
buffer.Advance(bytes.Length);
|
input.Application.Output.Advance(bytes.Length);
|
||||||
await buffer.FlushAsync();
|
await input.Application.Output.FlushAsync();
|
||||||
|
|
||||||
Assert.Same(block.Array, await writeTcs.Task);
|
Assert.Same(block.Array, await writeTcs.Task);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var pipeOptions = new PipeOptions
|
var pipeOptions = new PipeOptions
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: Mock.Of<Scheduler>()
|
readerScheduler: Mock.Of<PipeScheduler>()
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var socketOutput = CreateOutputProducer(pipeOptions))
|
using (var socketOutput = CreateOutputProducer(pipeOptions))
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
serviceContext.ServerOptions.Limits.MaxResponseBufferSize = maxResponseBufferSize;
|
serviceContext.ServerOptions.Limits.MaxResponseBufferSize = maxResponseBufferSize;
|
||||||
serviceContext.ThreadPool = new LoggingThreadPool(null);
|
serviceContext.ThreadPool = new LoggingThreadPool(null);
|
||||||
|
|
||||||
var mockScheduler = Mock.Of<Scheduler>();
|
var mockScheduler = Mock.Of<PipeScheduler>();
|
||||||
var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler);
|
var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler);
|
||||||
|
|
||||||
Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.MaximumSizeLow);
|
Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.ResumeWriterThreshold);
|
||||||
Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.MaximumSizeHigh);
|
Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.PauseWriterThreshold);
|
||||||
Assert.Same(mockScheduler, outputPipeOptions.ReaderScheduler);
|
Assert.Same(mockScheduler, outputPipeOptions.ReaderScheduler);
|
||||||
Assert.Same(serviceContext.ThreadPool, outputPipeOptions.WriterScheduler);
|
Assert.Same(serviceContext.ThreadPool, outputPipeOptions.WriterScheduler);
|
||||||
}
|
}
|
||||||
|
|
@ -44,11 +44,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize;
|
serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize;
|
||||||
serviceContext.ThreadPool = new LoggingThreadPool(null);
|
serviceContext.ThreadPool = new LoggingThreadPool(null);
|
||||||
|
|
||||||
var mockScheduler = Mock.Of<Scheduler>();
|
var mockScheduler = Mock.Of<PipeScheduler>();
|
||||||
var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler);
|
var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler);
|
||||||
|
|
||||||
Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.MaximumSizeLow);
|
Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.ResumeWriterThreshold);
|
||||||
Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.MaximumSizeHigh);
|
Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.PauseWriterThreshold);
|
||||||
Assert.Same(serviceContext.ThreadPool, inputPipeOptions.ReaderScheduler);
|
Assert.Same(serviceContext.ThreadPool, inputPipeOptions.ReaderScheduler);
|
||||||
Assert.Same(mockScheduler, inputPipeOptions.WriterScheduler);
|
Assert.Same(mockScheduler, inputPipeOptions.WriterScheduler);
|
||||||
}
|
}
|
||||||
|
|
@ -66,10 +66,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
ServiceContext = serviceContext
|
ServiceContext = serviceContext
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeLow);
|
Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedInputPipeOptions.ResumeWriterThreshold);
|
||||||
Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.MaximumSizeHigh);
|
Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedInputPipeOptions.PauseWriterThreshold);
|
||||||
Assert.Same(serviceContext.ThreadPool, connectionLifetime.AdaptedInputPipeOptions.ReaderScheduler);
|
Assert.Same(serviceContext.ThreadPool, connectionLifetime.AdaptedInputPipeOptions.ReaderScheduler);
|
||||||
Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler);
|
Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedInputPipeOptions.WriterScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -85,10 +85,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
ServiceContext = serviceContext
|
ServiceContext = serviceContext
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeLow);
|
Assert.Equal(expectedMaximumSizeLow, connectionLifetime.AdaptedOutputPipeOptions.ResumeWriterThreshold);
|
||||||
Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.MaximumSizeHigh);
|
Assert.Equal(expectedMaximumSizeHigh, connectionLifetime.AdaptedOutputPipeOptions.PauseWriterThreshold);
|
||||||
Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler);
|
Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.ReaderScheduler);
|
||||||
Assert.Same(Scheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler);
|
Assert.Same(PipeScheduler.Inline, connectionLifetime.AdaptedOutputPipeOptions.WriterScheduler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
// ulong.MaxValue.ToString().Length
|
// ulong.MaxValue.ToString().Length
|
||||||
private const int _ulongMaxValueLength = 20;
|
private const int _ulongMaxValueLength = 20;
|
||||||
|
|
||||||
private readonly IPipe _pipe;
|
private readonly Pipe _pipe;
|
||||||
private readonly MemoryPool _memoryPool = new MemoryPool();
|
private readonly MemoryPool _memoryPool = new MemoryPool();
|
||||||
|
|
||||||
public PipelineExtensionTests()
|
public PipelineExtensionTests()
|
||||||
|
|
@ -34,8 +34,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
[InlineData(4_8_15_16_23_42)]
|
[InlineData(4_8_15_16_23_42)]
|
||||||
public void WritesNumericToAscii(ulong number)
|
public void WritesNumericToAscii(ulong number)
|
||||||
{
|
{
|
||||||
var writerBuffer = _pipe.Writer.Alloc();
|
var writerBuffer = _pipe.Writer;
|
||||||
var writer = new WritableBufferWriter(writerBuffer);
|
var writer = OutputWriter.Create(writerBuffer);
|
||||||
writer.WriteNumeric(number);
|
writer.WriteNumeric(number);
|
||||||
writerBuffer.FlushAsync().GetAwaiter().GetResult();
|
writerBuffer.FlushAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
|
@ -51,8 +51,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
[InlineData(_ulongMaxValueLength - 1)]
|
[InlineData(_ulongMaxValueLength - 1)]
|
||||||
public void WritesNumericAcrossSpanBoundaries(int gapSize)
|
public void WritesNumericAcrossSpanBoundaries(int gapSize)
|
||||||
{
|
{
|
||||||
var writerBuffer = _pipe.Writer.Alloc(100);
|
var writerBuffer = _pipe.Writer;
|
||||||
var writer = new WritableBufferWriter(writerBuffer);
|
var writer = OutputWriter.Create(writerBuffer);
|
||||||
// almost fill up the first block
|
// almost fill up the first block
|
||||||
var spacer = new byte[writer.Span.Length - gapSize];
|
var spacer = new byte[writer.Span.Length - gapSize];
|
||||||
writer.Write(spacer);
|
writer.Write(spacer);
|
||||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||||
var numAsString = ulong.MaxValue.ToString();
|
var numAsString = ulong.MaxValue.ToString();
|
||||||
var written = reader.Buffer.Slice(spacer.Length, numAsString.Length);
|
var written = reader.Buffer.Slice(spacer.Length, numAsString.Length);
|
||||||
Assert.False(written.IsSingleSpan, "The buffer should cross spans");
|
Assert.False(written.IsSingleSegment, "The buffer should cross spans");
|
||||||
AssertExtensions.Equal(Encoding.ASCII.GetBytes(numAsString), written.ToArray());
|
AssertExtensions.Equal(Encoding.ASCII.GetBytes(numAsString), written.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,8 +82,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
[InlineData(null, new byte[0])]
|
[InlineData(null, new byte[0])]
|
||||||
public void EncodesAsAscii(string input, byte[] expected)
|
public void EncodesAsAscii(string input, byte[] expected)
|
||||||
{
|
{
|
||||||
var writerBuffer = _pipe.Writer.Alloc();
|
var writerBuffer = _pipe.Writer;
|
||||||
var writer = new WritableBufferWriter(writerBuffer);
|
var writer = OutputWriter.Create(writerBuffer);
|
||||||
writer.WriteAsciiNoValidation(input);
|
writer.WriteAsciiNoValidation(input);
|
||||||
writerBuffer.FlushAsync().GetAwaiter().GetResult();
|
writerBuffer.FlushAsync().GetAwaiter().GetResult();
|
||||||
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||||
|
|
@ -109,8 +109,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
{
|
{
|
||||||
// WriteAscii doesn't validate if characters are in the ASCII range
|
// WriteAscii doesn't validate if characters are in the ASCII range
|
||||||
// but it shouldn't produce more than one byte per character
|
// but it shouldn't produce more than one byte per character
|
||||||
var writerBuffer = _pipe.Writer.Alloc();
|
var writerBuffer = _pipe.Writer;
|
||||||
var writer = new WritableBufferWriter(writerBuffer);
|
var writer = OutputWriter.Create(writerBuffer);
|
||||||
writer.WriteAsciiNoValidation(input);
|
writer.WriteAsciiNoValidation(input);
|
||||||
writerBuffer.FlushAsync().GetAwaiter().GetResult();
|
writerBuffer.FlushAsync().GetAwaiter().GetResult();
|
||||||
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||||
|
|
@ -122,8 +122,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
public void WriteAsciiNoValidation()
|
public void WriteAsciiNoValidation()
|
||||||
{
|
{
|
||||||
const byte maxAscii = 0x7f;
|
const byte maxAscii = 0x7f;
|
||||||
var writerBuffer = _pipe.Writer.Alloc();
|
var writerBuffer = _pipe.Writer;
|
||||||
var writer = new WritableBufferWriter(writerBuffer);
|
var writer = OutputWriter.Create(writerBuffer);
|
||||||
for (var i = 0; i < maxAscii; i++)
|
for (var i = 0; i < maxAscii; i++)
|
||||||
{
|
{
|
||||||
writer.WriteAsciiNoValidation(new string((char)i, 1));
|
writer.WriteAsciiNoValidation(new string((char)i, 1));
|
||||||
|
|
@ -151,8 +151,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
public void WritesAsciiAcrossBlockBoundaries(int stringLength, int gapSize)
|
public void WritesAsciiAcrossBlockBoundaries(int stringLength, int gapSize)
|
||||||
{
|
{
|
||||||
var testString = new string(' ', stringLength);
|
var testString = new string(' ', stringLength);
|
||||||
var writerBuffer = _pipe.Writer.Alloc(100);
|
var writerBuffer = _pipe.Writer;
|
||||||
var writer = new WritableBufferWriter(writerBuffer);
|
var writer = OutputWriter.Create(writerBuffer);
|
||||||
// almost fill up the first block
|
// almost fill up the first block
|
||||||
var spacer = new byte[writer.Span.Length - gapSize];
|
var spacer = new byte[writer.Span.Length - gapSize];
|
||||||
writer.Write(spacer);
|
writer.Write(spacer);
|
||||||
|
|
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
|
||||||
var written = reader.Buffer.Slice(spacer.Length, stringLength);
|
var written = reader.Buffer.Slice(spacer.Length, stringLength);
|
||||||
Assert.False(written.IsSingleSpan, "The buffer should cross spans");
|
Assert.False(written.IsSingleSegment, "The buffer should cross spans");
|
||||||
AssertExtensions.Equal(Encoding.ASCII.GetBytes(testString), written.ToArray());
|
AssertExtensions.Equal(Encoding.ASCII.GetBytes(testString), written.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
Http1Connection.HttpResponseControl = Mock.Of<IHttpResponseControl>();
|
Http1Connection.HttpResponseControl = Mock.Of<IHttpResponseControl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPipeConnection Transport { get; }
|
public IDuplexPipe Transport { get; }
|
||||||
|
|
||||||
public IPipeConnection Application { get; }
|
public IDuplexPipe Application { get; }
|
||||||
|
|
||||||
public Http1ConnectionContext Http1ConnectionContext { get; }
|
public Http1ConnectionContext Http1ConnectionContext { get; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
mockConnectionHandler.InputOptions = pool =>
|
mockConnectionHandler.InputOptions = pool =>
|
||||||
new PipeOptions(
|
new PipeOptions(
|
||||||
pool: pool,
|
pool: pool,
|
||||||
maximumSizeHigh: 3);
|
pauseWriterThreshold: 3);
|
||||||
|
|
||||||
// We don't set the output writer scheduler here since we want to run the callback inline
|
// We don't set the output writer scheduler here since we want to run the callback inline
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler };
|
var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler };
|
||||||
var transport = new LibuvTransport(mockLibuv, transportContext, null);
|
var transport = new LibuvTransport(mockLibuv, transportContext, null);
|
||||||
var thread = new LibuvThread(transport);
|
var thread = new LibuvThread(transport);
|
||||||
var mockScheduler = new Mock<Scheduler>();
|
var mockScheduler = new Mock<PipeScheduler>();
|
||||||
Action backPressure = null;
|
Action backPressure = null;
|
||||||
mockScheduler.Setup(m => m.Schedule(It.IsAny<Action>())).Callback<Action>(a =>
|
mockScheduler.Setup(m => m.Schedule(It.IsAny<Action>())).Callback<Action>(a =>
|
||||||
{
|
{
|
||||||
|
|
@ -126,8 +126,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
mockConnectionHandler.InputOptions = pool =>
|
mockConnectionHandler.InputOptions = pool =>
|
||||||
new PipeOptions(
|
new PipeOptions(
|
||||||
pool: pool,
|
pool: pool,
|
||||||
maximumSizeHigh: 3,
|
pauseWriterThreshold: 3,
|
||||||
maximumSizeLow: 3,
|
resumeWriterThreshold: 3,
|
||||||
writerScheduler: mockScheduler.Object);
|
writerScheduler: mockScheduler.Object);
|
||||||
|
|
||||||
mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler:thread );
|
mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler:thread );
|
||||||
|
|
@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
var result = await mockConnectionHandler.Input.Reader.ReadAsync();
|
var result = await mockConnectionHandler.Input.Reader.ReadAsync();
|
||||||
// Calling advance will call into our custom scheduler that captures the back pressure
|
// Calling advance will call into our custom scheduler that captures the back pressure
|
||||||
// callback
|
// callback
|
||||||
mockConnectionHandler.Input.Reader.Advance(result.Buffer.End);
|
mockConnectionHandler.Input.Reader.AdvanceTo(result.Buffer.End);
|
||||||
|
|
||||||
// Cancel the current pending flush
|
// Cancel the current pending flush
|
||||||
mockConnectionHandler.Input.Writer.CancelPendingFlush();
|
mockConnectionHandler.Input.Writer.CancelPendingFlush();
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
// SocketOutput, the write callback would never be invoked for writes larger than
|
// SocketOutput, the write callback would never be invoked for writes larger than
|
||||||
// maxResponseBufferSize even after the write actually completed.
|
// maxResponseBufferSize even after the write actually completed.
|
||||||
|
|
||||||
// ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null.
|
// ConnectionHandler will set Pause/ResumeWriterThreshold to zero when MaxResponseBufferSize is null.
|
||||||
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
||||||
var pipeOptions = new PipeOptions
|
var pipeOptions = new PipeOptions
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize ?? 0,
|
pauseWriterThreshold: maxResponseBufferSize ?? 0,
|
||||||
maximumSizeLow: maxResponseBufferSize ?? 0
|
resumeWriterThreshold: maxResponseBufferSize ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -96,14 +96,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null.
|
// ConnectionHandler will set Pause/ResumeWriterThreshold to zero when MaxResponseBufferSize is null.
|
||||||
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
||||||
var pipeOptions = new PipeOptions
|
var pipeOptions = new PipeOptions
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: 0,
|
pauseWriterThreshold: 0,
|
||||||
maximumSizeLow: 0
|
resumeWriterThreshold: 0
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -144,14 +144,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ConnectionHandler will set MaximumSizeHigh/Low to 1 when MaxResponseBufferSize is zero.
|
// ConnectionHandler will set Pause/ResumeWriterThreshold to 1 when MaxResponseBufferSize is zero.
|
||||||
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
||||||
var pipeOptions = new PipeOptions
|
var pipeOptions = new PipeOptions
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: 1,
|
pauseWriterThreshold: 1,
|
||||||
maximumSizeLow: 1
|
resumeWriterThreshold: 1
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -206,8 +206,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize,
|
pauseWriterThreshold: maxResponseBufferSize,
|
||||||
maximumSizeLow: maxResponseBufferSize
|
resumeWriterThreshold: maxResponseBufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -270,8 +270,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize,
|
pauseWriterThreshold: maxResponseBufferSize,
|
||||||
maximumSizeLow: maxResponseBufferSize
|
resumeWriterThreshold: maxResponseBufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -340,8 +340,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize,
|
pauseWriterThreshold: maxResponseBufferSize,
|
||||||
maximumSizeLow: maxResponseBufferSize
|
resumeWriterThreshold: maxResponseBufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource))
|
using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource))
|
||||||
|
|
@ -433,8 +433,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize,
|
pauseWriterThreshold: maxResponseBufferSize,
|
||||||
maximumSizeLow: maxResponseBufferSize
|
resumeWriterThreshold: maxResponseBufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -517,8 +517,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize,
|
pauseWriterThreshold: maxResponseBufferSize,
|
||||||
maximumSizeLow: maxResponseBufferSize
|
resumeWriterThreshold: maxResponseBufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -599,8 +599,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize,
|
pauseWriterThreshold: maxResponseBufferSize,
|
||||||
maximumSizeLow: maxResponseBufferSize
|
resumeWriterThreshold: maxResponseBufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -654,14 +654,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null.
|
// ConnectionHandler will set Pause/ResumeWriterThreshold to zero when MaxResponseBufferSize is null.
|
||||||
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
// This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly.
|
||||||
var pipeOptions = new PipeOptions
|
var pipeOptions = new PipeOptions
|
||||||
(
|
(
|
||||||
pool: _memoryPool,
|
pool: _memoryPool,
|
||||||
readerScheduler: _libuvThread,
|
readerScheduler: _libuvThread,
|
||||||
maximumSizeHigh: maxResponseBufferSize ?? 0,
|
pauseWriterThreshold: maxResponseBufferSize ?? 0,
|
||||||
maximumSizeLow: maxResponseBufferSize ?? 0
|
resumeWriterThreshold: maxResponseBufferSize ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
using (var outputProducer = CreateOutputProducer(pipeOptions))
|
||||||
|
|
@ -728,7 +728,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
return (Http1OutputProducer)http1Connection.Output;
|
return (Http1OutputProducer)http1Connection.Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WriteOutputAsync(LibuvOutputConsumer consumer, IPipeReader outputReader, Http1Connection http1Connection)
|
private async Task WriteOutputAsync(LibuvOutputConsumer consumer, PipeReader outputReader, Http1Connection http1Connection)
|
||||||
{
|
{
|
||||||
// This WriteOutputAsync() calling code is equivalent to that in LibuvConnection.
|
// This WriteOutputAsync() calling code is equivalent to that in LibuvConnection.
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
|
|
||||||
await writeRequest.WriteAsync(
|
await writeRequest.WriteAsync(
|
||||||
serverConnectionPipe,
|
serverConnectionPipe,
|
||||||
new ReadOnlyBuffer(new byte[] { 1, 2, 3, 4 }));
|
new ReadOnlyBuffer<byte>(new byte[] { 1, 2, 3, 4 }));
|
||||||
|
|
||||||
writeRequest.Dispose();
|
writeRequest.Dispose();
|
||||||
serverConnectionPipe.Dispose();
|
serverConnectionPipe.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
{
|
{
|
||||||
var req = new UvWriteReq(_logger);
|
var req = new UvWriteReq(_logger);
|
||||||
req.DangerousInit(loop);
|
req.DangerousInit(loop);
|
||||||
var block = new ReadOnlyBuffer(new byte[] { 65, 66, 67, 68, 69 });
|
var block = new ReadOnlyBuffer<byte>(new byte[] { 65, 66, 67, 68, 69 });
|
||||||
|
|
||||||
await req.WriteAsync(
|
await req.WriteAsync(
|
||||||
tcp2,
|
tcp2,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
|
||||||
feature.Application = new PipeConnection(Output.Reader, Input.Writer);
|
feature.Application = new PipeConnection(Output.Reader, Input.Writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPipe Input { get; private set; }
|
public Pipe Input { get; private set; }
|
||||||
public IPipe Output { get; private set; }
|
public Pipe Output { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,6 @@
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\src\Kestrel.Core\Kestrel.Core.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
//using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
|
|
||||||
namespace CodeGenerator
|
namespace CodeGenerator
|
||||||
{
|
{
|
||||||
|
|
@ -23,39 +23,39 @@ namespace CodeGenerator
|
||||||
{
|
{
|
||||||
var alwaysFeatures = new[]
|
var alwaysFeatures = new[]
|
||||||
{
|
{
|
||||||
typeof(IHttpRequestFeature),
|
"IHttpRequestFeature",
|
||||||
typeof(IHttpResponseFeature),
|
"IHttpResponseFeature",
|
||||||
typeof(IHttpRequestIdentifierFeature),
|
"IHttpRequestIdentifierFeature",
|
||||||
typeof(IServiceProvidersFeature),
|
"IServiceProvidersFeature",
|
||||||
typeof(IHttpRequestLifetimeFeature),
|
"IHttpRequestLifetimeFeature",
|
||||||
typeof(IHttpConnectionFeature),
|
"IHttpConnectionFeature",
|
||||||
};
|
};
|
||||||
|
|
||||||
var commonFeatures = new[]
|
var commonFeatures = new[]
|
||||||
{
|
{
|
||||||
typeof(IHttpAuthenticationFeature),
|
"IHttpAuthenticationFeature",
|
||||||
typeof(IQueryFeature),
|
"IQueryFeature",
|
||||||
typeof(IFormFeature),
|
"IFormFeature",
|
||||||
};
|
};
|
||||||
|
|
||||||
var sometimesFeatures = new[]
|
var sometimesFeatures = new[]
|
||||||
{
|
{
|
||||||
typeof(IHttpUpgradeFeature),
|
"IHttpUpgradeFeature",
|
||||||
typeof(IHttp2StreamIdFeature),
|
"IHttp2StreamIdFeature",
|
||||||
typeof(IResponseCookiesFeature),
|
"IResponseCookiesFeature",
|
||||||
typeof(IItemsFeature),
|
"IItemsFeature",
|
||||||
typeof(ITlsConnectionFeature),
|
"ITlsConnectionFeature",
|
||||||
typeof(IHttpWebSocketFeature),
|
"IHttpWebSocketFeature",
|
||||||
typeof(ISessionFeature),
|
"ISessionFeature",
|
||||||
typeof(IHttpMaxRequestBodySizeFeature),
|
"IHttpMaxRequestBodySizeFeature",
|
||||||
typeof(IHttpMinRequestBodyDataRateFeature),
|
"IHttpMinRequestBodyDataRateFeature",
|
||||||
typeof(IHttpMinResponseDataRateFeature),
|
"IHttpMinResponseDataRateFeature",
|
||||||
typeof(IHttpBodyControlFeature),
|
"IHttpBodyControlFeature",
|
||||||
};
|
};
|
||||||
|
|
||||||
var rareFeatures = new[]
|
var rareFeatures = new[]
|
||||||
{
|
{
|
||||||
typeof(IHttpSendFileFeature),
|
"IHttpSendFileFeature",
|
||||||
};
|
};
|
||||||
|
|
||||||
var allFeatures = alwaysFeatures.Concat(commonFeatures).Concat(sometimesFeatures).Concat(rareFeatures);
|
var allFeatures = alwaysFeatures.Concat(commonFeatures).Concat(sometimesFeatures).Concat(rareFeatures);
|
||||||
|
|
@ -64,15 +64,15 @@ namespace CodeGenerator
|
||||||
// See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs
|
// See also: src/Kestrel/Http/HttpProtocol.FeatureCollection.cs
|
||||||
var implementedFeatures = new[]
|
var implementedFeatures = new[]
|
||||||
{
|
{
|
||||||
typeof(IHttpRequestFeature),
|
"IHttpRequestFeature",
|
||||||
typeof(IHttpResponseFeature),
|
"IHttpResponseFeature",
|
||||||
typeof(IHttpRequestIdentifierFeature),
|
"IHttpRequestIdentifierFeature",
|
||||||
typeof(IHttpRequestLifetimeFeature),
|
"IHttpRequestLifetimeFeature",
|
||||||
typeof(IHttpConnectionFeature),
|
"IHttpConnectionFeature",
|
||||||
typeof(IHttpMaxRequestBodySizeFeature),
|
"IHttpMaxRequestBodySizeFeature",
|
||||||
typeof(IHttpMinRequestBodyDataRateFeature),
|
"IHttpMinRequestBodyDataRateFeature",
|
||||||
typeof(IHttpMinResponseDataRateFeature),
|
"IHttpMinResponseDataRateFeature",
|
||||||
typeof(IHttpBodyControlFeature),
|
"IHttpBodyControlFeature",
|
||||||
};
|
};
|
||||||
|
|
||||||
return $@"// Copyright (c) .NET Foundation. All rights reserved.
|
return $@"// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
|
@ -81,26 +81,30 @@ namespace CodeGenerator
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{{
|
{{
|
||||||
public partial class {className}
|
public partial class {className}
|
||||||
{{{Each(allFeatures, feature => $@"
|
{{{Each(allFeatures, feature => $@"
|
||||||
private static readonly Type {feature.Name}Type = typeof(global::{feature.FullName});")}
|
private static readonly Type {feature}Type = typeof({feature});")}
|
||||||
{Each(allFeatures, feature => $@"
|
{Each(allFeatures, feature => $@"
|
||||||
private object _current{feature.Name};")}
|
private object _current{feature};")}
|
||||||
|
|
||||||
private void FastReset()
|
private void FastReset()
|
||||||
{{{Each(implementedFeatures, feature => $@"
|
{{{Each(implementedFeatures, feature => $@"
|
||||||
_current{feature.Name} = this;")}
|
_current{feature} = this;")}
|
||||||
{Each(allFeatures.Where(f => !implementedFeatures.Contains(f)), feature => $@"
|
{Each(allFeatures.Where(f => !implementedFeatures.Contains(f)), feature => $@"
|
||||||
_current{feature.Name} = null;")}
|
_current{feature} = null;")}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
internal object FastFeatureGet(Type key)
|
internal object FastFeatureGet(Type key)
|
||||||
{{{Each(allFeatures, feature => $@"
|
{{{Each(allFeatures, feature => $@"
|
||||||
if (key == {feature.Name}Type)
|
if (key == {feature}Type)
|
||||||
{{
|
{{
|
||||||
return _current{feature.Name};
|
return _current{feature};
|
||||||
}}")}
|
}}")}
|
||||||
return ExtraFeatureGet(key);
|
return ExtraFeatureGet(key);
|
||||||
}}
|
}}
|
||||||
|
|
@ -109,9 +113,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{{
|
{{
|
||||||
_featureRevision++;
|
_featureRevision++;
|
||||||
{Each(allFeatures, feature => $@"
|
{Each(allFeatures, feature => $@"
|
||||||
if (key == {feature.Name}Type)
|
if (key == {feature}Type)
|
||||||
{{
|
{{
|
||||||
_current{feature.Name} = feature;
|
_current{feature} = feature;
|
||||||
return;
|
return;
|
||||||
}}")};
|
}}")};
|
||||||
ExtraFeatureSet(key, feature);
|
ExtraFeatureSet(key, feature);
|
||||||
|
|
@ -119,9 +123,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
|
||||||
{{{Each(allFeatures, feature => $@"
|
{{{Each(allFeatures, feature => $@"
|
||||||
if (_current{feature.Name} != null)
|
if (_current{feature} != null)
|
||||||
{{
|
{{
|
||||||
yield return new KeyValuePair<Type, object>({feature.Name}Type, _current{feature.Name} as global::{feature.FullName});
|
yield return new KeyValuePair<Type, object>({feature}Type, _current{feature} as {feature});
|
||||||
}}")}
|
}}")}
|
||||||
|
|
||||||
if (MaybeExtra != null)
|
if (MaybeExtra != null)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
|
||||||
|
|
||||||
namespace CodeGenerator.HttpUtilities
|
namespace CodeGenerator.HttpUtilities
|
||||||
{
|
{
|
||||||
|
|
@ -17,27 +16,27 @@ namespace CodeGenerator.HttpUtilities
|
||||||
{
|
{
|
||||||
var httpMethods = new []
|
var httpMethods = new []
|
||||||
{
|
{
|
||||||
new Tuple<string, HttpMethod>("CONNECT ", HttpMethod.Connect),
|
new Tuple<string, String>("CONNECT ", "Connect"),
|
||||||
new Tuple<string, HttpMethod>("DELETE ", HttpMethod.Delete),
|
new Tuple<string, String>("DELETE ", "Delete"),
|
||||||
new Tuple<string, HttpMethod>("HEAD ", HttpMethod.Head),
|
new Tuple<string, String>("HEAD ", "Head"),
|
||||||
new Tuple<string, HttpMethod>("PATCH ", HttpMethod.Patch),
|
new Tuple<string, String>("PATCH ", "Patch"),
|
||||||
new Tuple<string, HttpMethod>("POST ", HttpMethod.Post),
|
new Tuple<string, String>("POST ", "Post"),
|
||||||
new Tuple<string, HttpMethod>("PUT ", HttpMethod.Put),
|
new Tuple<string, String>("PUT ", "Put"),
|
||||||
new Tuple<string, HttpMethod>("OPTIONS ", HttpMethod.Options),
|
new Tuple<string, String>("OPTIONS ", "Options"),
|
||||||
new Tuple<string, HttpMethod>("TRACE ", HttpMethod.Trace),
|
new Tuple<string, String>("TRACE ", "Trace"),
|
||||||
new Tuple<string, HttpMethod>("GET ", HttpMethod.Get)
|
new Tuple<string, String>("GET ", "Get")
|
||||||
};
|
};
|
||||||
|
|
||||||
return GenerateFile(httpMethods);
|
return GenerateFile(httpMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateFile(Tuple<string, HttpMethod>[] httpMethods)
|
private static string GenerateFile(Tuple<string, String>[] httpMethods)
|
||||||
{
|
{
|
||||||
var maskLength = (byte)Math.Ceiling(Math.Log(httpMethods.Length, 2));
|
var maskLength = (byte)Math.Ceiling(Math.Log(httpMethods.Length, 2));
|
||||||
|
|
||||||
var methodsInfo = httpMethods.Select(GetMethodStringAndUlongAndMaskLength).ToList();
|
var methodsInfo = httpMethods.Select(GetMethodStringAndUlongAndMaskLength).ToList();
|
||||||
|
|
||||||
var methodsInfoWithoutGet = methodsInfo.Where(m => m.HttpMethod != HttpMethod.Get.ToString()).ToList();
|
var methodsInfoWithoutGet = methodsInfo.Where(m => m.HttpMethod != "Get".ToString()).ToList();
|
||||||
|
|
||||||
var methodsAsciiStringAsLong = methodsInfo.Select(m => m.AsciiStringAsLong).ToArray();
|
var methodsAsciiStringAsLong = methodsInfo.Select(m => m.AsciiStringAsLong).ToArray();
|
||||||
|
|
||||||
|
|
@ -158,7 +157,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
var maskFieldName = GetMaskFieldName(methodInfo.MaskLength);
|
var maskFieldName = GetMaskFieldName(methodInfo.MaskLength);
|
||||||
var httpMethodFieldName = GetHttpMethodFieldName(methodInfo);
|
var httpMethodFieldName = GetHttpMethodFieldName(methodInfo);
|
||||||
|
|
||||||
result.AppendFormat(" SetKnownMethod({0}, {1}, {2}.{3}, {4});", maskFieldName, httpMethodFieldName, typeof(HttpMethod).Name, methodInfo.HttpMethod, methodInfo.MaskLength - 1);
|
result.AppendFormat(" SetKnownMethod({0}, {1}, HttpMethod.{3}, {4});", maskFieldName, httpMethodFieldName, typeof(String).Name, methodInfo.HttpMethod, methodInfo.MaskLength - 1);
|
||||||
|
|
||||||
if (index < methodsInfo.Count - 1)
|
if (index < methodsInfo.Count - 1)
|
||||||
{
|
{
|
||||||
|
|
@ -181,7 +180,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
{
|
{
|
||||||
var methodInfo = methodsInfo[index];
|
var methodInfo = methodsInfo[index];
|
||||||
|
|
||||||
result.AppendFormat(" _methodNames[(byte){0}.{1}] = {2}.{3};", typeof(HttpMethod).Name, methodInfo.HttpMethod, typeof(HttpMethods).Name, methodInfo.HttpMethod);
|
result.AppendFormat(" _methodNames[(byte)HttpMethod.{1}] = {2}.{3};", typeof(String).Name, methodInfo.HttpMethod, typeof(HttpMethods).Name, methodInfo.HttpMethod);
|
||||||
|
|
||||||
if (index < methodsInfo.Count - 1)
|
if (index < methodsInfo.Count - 1)
|
||||||
{
|
{
|
||||||
|
|
@ -281,7 +280,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
public int MaskLength;
|
public int MaskLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple<string, HttpMethod> method)
|
private static MethodInfo GetMethodStringAndUlongAndMaskLength(Tuple<string, string> method)
|
||||||
{
|
{
|
||||||
var methodString = GetMethodString(method.Item1);
|
var methodString = GetMethodString(method.Item1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
|
||||||
|
|
||||||
namespace CodeGenerator
|
namespace CodeGenerator
|
||||||
{
|
{
|
||||||
|
|
@ -266,14 +265,14 @@ namespace CodeGenerator
|
||||||
{
|
{
|
||||||
Headers = requestHeaders,
|
Headers = requestHeaders,
|
||||||
HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length),
|
HeadersByLength = requestHeaders.GroupBy(x => x.Name.Length),
|
||||||
ClassName = nameof(HttpRequestHeaders),
|
ClassName = "HttpRequestHeaders",
|
||||||
Bytes = default(byte[])
|
Bytes = default(byte[])
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Headers = responseHeaders,
|
Headers = responseHeaders,
|
||||||
HeadersByLength = responseHeaders.GroupBy(x => x.Name.Length),
|
HeadersByLength = responseHeaders.GroupBy(x => x.Name.Length),
|
||||||
ClassName = nameof(HttpResponseHeaders),
|
ClassName = "HttpResponseHeaders",
|
||||||
Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray()
|
Bytes = responseHeaders.SelectMany(header => header.Bytes).ToArray()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -293,6 +292,7 @@ namespace CodeGenerator
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
@ -384,7 +384,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}}
|
}}
|
||||||
|
|
||||||
protected override void SetValueFast(string key, StringValues value)
|
protected override void SetValueFast(string key, StringValues value)
|
||||||
{{{(loop.ClassName == nameof(HttpResponseHeaders) ? @"
|
{{{(loop.ClassName == "HttpResponseHeaders" ? @"
|
||||||
ValidateHeaderCharacters(value);" : "")}
|
ValidateHeaderCharacters(value);" : "")}
|
||||||
switch (key.Length)
|
switch (key.Length)
|
||||||
{{{Each(loop.HeadersByLength, byLength => $@"
|
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||||
|
|
@ -406,7 +406,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}}
|
}}
|
||||||
|
|
||||||
protected override bool AddValueFast(string key, StringValues value)
|
protected override bool AddValueFast(string key, StringValues value)
|
||||||
{{{(loop.ClassName == nameof(HttpResponseHeaders) ? @"
|
{{{(loop.ClassName == "HttpResponseHeaders" ? @"
|
||||||
ValidateHeaderCharacters(value);" : "")}
|
ValidateHeaderCharacters(value);" : "")}
|
||||||
switch (key.Length)
|
switch (key.Length)
|
||||||
{{{Each(loop.HeadersByLength, byLength => $@"
|
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||||
|
|
@ -432,7 +432,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}}
|
}}
|
||||||
break;")}
|
break;")}
|
||||||
}}
|
}}
|
||||||
{(loop.ClassName == nameof(HttpResponseHeaders) ? @"
|
{(loop.ClassName == "HttpResponseHeaders" ? @"
|
||||||
ValidateHeaderCharacters(key);" : "")}
|
ValidateHeaderCharacters(key);" : "")}
|
||||||
Unknown.Add(key, value);
|
Unknown.Add(key, value);
|
||||||
// Return true, above will throw and exit for false
|
// Return true, above will throw and exit for false
|
||||||
|
|
@ -522,8 +522,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}}
|
}}
|
||||||
{(loop.ClassName == nameof(HttpResponseHeaders) ? $@"
|
{(loop.ClassName == "HttpResponseHeaders" ? $@"
|
||||||
protected void CopyToFast(ref WritableBufferWriter output)
|
protected void CopyToFast(ref OutputWriter<PipeWriter> output)
|
||||||
{{
|
{{
|
||||||
var tempBits = _bits | (_contentLength.HasValue ? {1L << 63}L : 0);
|
var tempBits = _bits | (_contentLength.HasValue ? {1L << 63}L : 0);
|
||||||
{Each(loop.Headers.Where(header => header.Identifier != "ContentLength").OrderBy(h => !h.PrimaryHeader), header => $@"
|
{Each(loop.Headers.Where(header => header.Identifier != "ContentLength").OrderBy(h => !h.PrimaryHeader), header => $@"
|
||||||
|
|
@ -541,7 +541,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
var value = _headers._{header.Identifier}[i];
|
var value = _headers._{header.Identifier}[i];
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{{
|
{{
|
||||||
output.Write(_headerBytes, {header.BytesOffset}, {header.BytesCount});
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, {header.BytesOffset}, {header.BytesCount}));
|
||||||
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
PipelineExtensions.WriteAsciiNoValidation(ref output, value);
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
@ -555,7 +555,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}}{(header.Identifier == "Server" ? $@"
|
}}{(header.Identifier == "Server" ? $@"
|
||||||
if ((tempBits & {1L << 63}L) != 0)
|
if ((tempBits & {1L << 63}L) != 0)
|
||||||
{{
|
{{
|
||||||
output.Write(_headerBytes, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesOffset}, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesCount});
|
output.Write(new ReadOnlySpan<byte>(_headerBytes, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesOffset}, {loop.Headers.First(x => x.Identifier == "ContentLength").BytesCount}));
|
||||||
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
|
PipelineExtensions.WriteNumeric(ref output, (ulong)ContentLength.Value);
|
||||||
|
|
||||||
if((tempBits & ~{1L << 63}L) == 0)
|
if((tempBits & ~{1L << 63}L) == 0)
|
||||||
|
|
@ -565,7 +565,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
tempBits &= ~{1L << 63}L;
|
tempBits &= ~{1L << 63}L;
|
||||||
}}" : "")}")}
|
}}" : "")}")}
|
||||||
}}" : "")}
|
}}" : "")}
|
||||||
{(loop.ClassName == nameof(HttpRequestHeaders) ? $@"
|
{(loop.ClassName == "HttpRequestHeaders" ? $@"
|
||||||
public unsafe void Append(byte* pKeyBytes, int keyLength, string value)
|
public unsafe void Append(byte* pKeyBytes, int keyLength, string value)
|
||||||
{{
|
{{
|
||||||
var pUB = pKeyBytes;
|
var pUB = pKeyBytes;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
|
||||||
|
|
||||||
namespace CodeGenerator
|
namespace CodeGenerator
|
||||||
{
|
{
|
||||||
|
|
@ -36,7 +34,7 @@ namespace CodeGenerator
|
||||||
public static void Run(string knownHeadersPath, string httpProtocolFeatureCollectionPath, string httpUtilitiesPath)
|
public static void Run(string knownHeadersPath, string httpProtocolFeatureCollectionPath, string httpUtilitiesPath)
|
||||||
{
|
{
|
||||||
var knownHeadersContent = KnownHeaders.GeneratedFile();
|
var knownHeadersContent = KnownHeaders.GeneratedFile();
|
||||||
var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile(nameof(HttpProtocol));
|
var httpProtocolFeatureCollectionContent = HttpProtocolFeatureCollection.GeneratedFile("HttpProtocol");
|
||||||
var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile();
|
var httpUtilitiesContent = HttpUtilities.HttpUtilities.GeneratedFile();
|
||||||
|
|
||||||
var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";
|
var existingKnownHeaders = File.Exists(knownHeadersPath) ? File.ReadAllText(knownHeadersPath) : "";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue