diff --git a/NuGet.config b/NuGet.config
index 69bab2da..ce00c056 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,6 +4,8 @@
+
+
diff --git a/ToProjectReferences.ps1 b/ToProjectReferences.ps1
new file mode 100644
index 00000000..4273aff9
--- /dev/null
+++ b/ToProjectReferences.ps1
@@ -0,0 +1,45 @@
+param($references)
+$ErrorActionPreference = "Stop";
+
+function ToProjectName($file)
+{
+ return $file.Directory.Name;
+}
+
+$projectreferences = ls (Join-Path $references *.csproj) -rec;
+
+$localprojects = ls -rec *.csproj;
+
+foreach ($project in $localprojects)
+{
+ Write-Host "Processing $project";
+
+ [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null;
+
+ $changed = $false
+ $xDoc = [System.Xml.Linq.XDocument]::Load($project, [System.Xml.Linq.LoadOptions]::PreserveWhitespace);
+ $endpoints = $xDoc.Descendants("PackageReference") | %{
+ $packageName = $_.Attribute("Include").Value;
+ $replacementProject = $projectreferences | ? {
+ return (ToProjectName($_)) -eq $packageName
+ };
+
+ if ($replacementProject)
+ {
+ $changed = $true
+ Write-Host " Replacing $packageName with $($project.FullName)";
+ $_.Name = "ProjectReference";
+ $_.Attribute("Include").Value = $replacementProject.FullName;
+ }
+ };
+ if ($changed)
+ {
+ $settings = New-Object System.Xml.XmlWriterSettings
+ $settings.OmitXmlDeclaration = $true;
+ $writer = [System.Xml.XmlWriter]::Create($project, $settings)
+
+ $xDoc.Save($writer);
+ $writer.Dispose();
+ }
+
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/AdaptedPipeline.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/AdaptedPipeline.cs
index 28c8fd66..f3ca1812 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/AdaptedPipeline.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/AdaptedPipeline.cs
@@ -3,37 +3,40 @@
using System;
using System.IO;
+using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
+using MemoryPool = Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure.MemoryPool;
namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
{
public class AdaptedPipeline : IDisposable
{
+ private const int MinAllocBufferSize = 2048;
+
private readonly Stream _filteredStream;
public AdaptedPipeline(
string connectionId,
Stream filteredStream,
+ IPipe pipe,
MemoryPool memory,
- IKestrelTrace logger,
- IThreadPool threadPool,
- IBufferSizeControl bufferSizeControl)
+ IKestrelTrace logger)
{
- SocketInput = new SocketInput(memory, threadPool, bufferSizeControl);
- SocketOutput = new StreamSocketOutput(connectionId, filteredStream, memory, logger);
+ Input = pipe;
+ Output = new StreamSocketOutput(connectionId, filteredStream, memory, logger);
_filteredStream = filteredStream;
}
- public SocketInput SocketInput { get; }
+ public IPipe Input { get; }
- public ISocketOutput SocketOutput { get; }
+ public ISocketOutput Output { get; }
public void Dispose()
{
- SocketInput.Dispose();
+ Input.Writer.Complete();
}
public async Task ReadInputAsync()
@@ -42,21 +45,29 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
do
{
- var block = SocketInput.IncomingStart();
+ var block = Input.Writer.Alloc(MinAllocBufferSize);
try
{
- var count = block.Data.Offset + block.Data.Count - block.End;
- bytesRead = await _filteredStream.ReadAsync(block.Array, block.End, count);
+ var array = block.Memory.GetArray();
+ try
+ {
+ bytesRead = await _filteredStream.ReadAsync(array.Array, array.Offset, array.Count);
+ block.Advance(bytesRead);
+ }
+ finally
+ {
+ await block.FlushAsync();
+ }
}
catch (Exception ex)
{
- SocketInput.IncomingComplete(0, ex);
+ Input.Writer.Complete(ex);
throw;
}
-
- SocketInput.IncomingComplete(bytesRead, error: null);
} while (bytesRead != 0);
+
+ Input.Writer.Complete();
}
}
}
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/RawStream.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/RawStream.cs
index 0824eeb5..3ec258b1 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/RawStream.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Adapter/Internal/RawStream.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
@@ -12,12 +13,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
{
public class RawStream : Stream
{
- private readonly SocketInput _input;
+ private readonly IPipeReader _input;
private readonly ISocketOutput _output;
- private Task _cachedTask = TaskCache.DefaultCompletedTask;
-
- public RawStream(SocketInput input, ISocketOutput output)
+ public RawStream(IPipeReader input, ISocketOutput output)
{
_input = input;
_output = output;
@@ -68,23 +67,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
- var task = ReadAsync(new ArraySegment(buffer, offset, count));
-
- if (task.IsCompletedSuccessfully)
- {
- if (_cachedTask.Result != task.Result)
- {
- // Needs .AsTask to match Stream's Async method return types
- _cachedTask = task.AsTask();
- }
- }
- else
- {
- // Needs .AsTask to match Stream's Async method return types
- _cachedTask = task.AsTask();
- }
-
- return _cachedTask;
+ return ReadAsync(new ArraySegment(buffer, offset, count));
}
public override void Write(byte[] buffer, int offset, int count)
@@ -125,10 +108,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
return _output.FlushAsync(cancellationToken);
}
-
- private ValueTask ReadAsync(ArraySegment buffer)
+ private async Task ReadAsync(ArraySegment buffer)
{
- return _input.ReadAsync(buffer.Array, buffer.Offset, buffer.Count);
+ while (true)
+ {
+ var result = await _input.ReadAsync();
+ var readableBuffer = result.Buffer;
+ try
+ {
+ if (!readableBuffer.IsEmpty)
+ {
+ var count = Math.Min(readableBuffer.Length, buffer.Count);
+ readableBuffer = readableBuffer.Slice(0, count);
+ readableBuffer.CopyTo(buffer);
+ return count;
+ }
+ else if (result.IsCompleted || result.IsCancelled)
+ {
+ return 0;
+ }
+ }
+ finally
+ {
+ _input.Advance(readableBuffer.End, readableBuffer.End);
+ }
+ }
}
#if NET451
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/BufferSizeControl.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/BufferSizeControl.cs
deleted file mode 100644
index 364a1a2c..00000000
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/BufferSizeControl.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System.Diagnostics;
-
-namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
-{
- public class BufferSizeControl : IBufferSizeControl
- {
- private readonly long _maxSize;
- private readonly IConnectionControl _connectionControl;
-
- private readonly object _lock = new object();
-
- private long _size;
- private bool _connectionPaused;
-
- public BufferSizeControl(long maxSize, IConnectionControl connectionControl)
- {
- _maxSize = maxSize;
- _connectionControl = connectionControl;
- }
-
- private long Size
- {
- get
- {
- return _size;
- }
- set
- {
- // Caller should ensure that bytes are never consumed before the producer has called Add()
- Debug.Assert(value >= 0);
- _size = value;
- }
- }
-
- public void Add(int count)
- {
- Debug.Assert(count >= 0);
-
- if (count == 0)
- {
- // No-op and avoid taking lock to reduce contention
- return;
- }
-
- lock (_lock)
- {
- Size += count;
- if (!_connectionPaused && Size >= _maxSize)
- {
- _connectionPaused = true;
- _connectionControl.Pause();
- }
- }
- }
-
- public void Subtract(int count)
- {
- Debug.Assert(count >= 0);
-
- if (count == 0)
- {
- // No-op and avoid taking lock to reduce contention
- return;
- }
-
- lock (_lock)
- {
- Size -= count;
- if (_connectionPaused && Size < _maxSize)
- {
- _connectionPaused = false;
- _connectionControl.Resume();
- }
- }
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Connection.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Connection.cs
index 12b97868..f2211cdc 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Connection.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Connection.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Adapter;
@@ -18,6 +19,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
{
public class Connection : ConnectionContext, IConnectionControl
{
+ private const int MinAllocBufferSize = 2048;
+
// Base32 encoding - in ascii sort order for easy text based sorting
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
@@ -40,11 +43,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
private Task _readInputTask;
private TaskCompletionSource