aspnetcore/src/Microsoft.AspNetCore.Server.../Adapter/Internal/AdaptedPipeline.cs

94 lines
2.5 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
namespace Microsoft.AspNetCore.Server.Kestrel.Adapter.Internal
{
public class AdaptedPipeline : IDisposable
{
private const int MinAllocBufferSize = 2048;
private readonly Stream _filteredStream;
private readonly StreamSocketOutput _output;
public AdaptedPipeline(
Stream filteredStream,
IPipe inputPipe,
IPipe outputPipe)
{
Input = inputPipe;
_output = new StreamSocketOutput(filteredStream, outputPipe);
_filteredStream = filteredStream;
}
public IPipe Input { get; }
public ISocketOutput Output => _output;
public void Dispose()
{
Input.Writer.Complete();
}
public async Task StartAsync()
{
var inputTask = ReadInputAsync();
var outputTask = _output.WriteOutputAsync();
var result = await Task.WhenAny(inputTask, outputTask);
if (result == inputTask)
{
// Close output
_output.Dispose();
}
else
{
// Close input
Input.Writer.Complete();
}
await Task.WhenAll(inputTask, outputTask);
}
private async Task ReadInputAsync()
{
int bytesRead;
do
{
var block = Input.Writer.Alloc(MinAllocBufferSize);
try
{
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)
{
Input.Writer.Complete(ex);
// Don't rethrow the exception. It should be handled by the Pipeline consumer.
return;
}
} while (bytesRead != 0);
Input.Writer.Complete();
}
}
}