Implement HttpRequestStreamReader.ReadToEndAsync (#18232)

This commit is contained in:
Thomas Levesque 2020-04-14 08:40:21 +02:00 committed by GitHub
parent 698ab1518d
commit 5d914d4d2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 1 deletions

View File

@ -152,6 +152,8 @@ namespace Microsoft.AspNetCore.WebUtilities
public override string ReadLine() { throw null; }
[System.Diagnostics.DebuggerStepThroughAttribute]
public override System.Threading.Tasks.Task<string> ReadLineAsync() { throw null; }
[System.Diagnostics.DebuggerStepThroughAttribute]
public override System.Threading.Tasks.Task<string> ReadToEndAsync() { throw null; }
}
public partial class HttpResponseStreamWriter : System.IO.TextWriter
{

View File

@ -333,7 +333,7 @@ namespace Microsoft.AspNetCore.WebUtilities
if (_disposed)
{
throw new ObjectDisposedException(nameof(HttpRequestStreamReader));
}
}
StringBuilder sb = null;
var consumeLineFeed = false;
@ -528,6 +528,20 @@ namespace Microsoft.AspNetCore.WebUtilities
return _charsRead;
}
public async override Task<string> ReadToEndAsync()
{
StringBuilder sb = new StringBuilder(_charsRead - _charBufferIndex);
do
{
int tmpCharPos = _charBufferIndex;
sb.Append(_charBuffer, tmpCharPos, _charsRead - tmpCharPos);
_charBufferIndex = _charsRead; // We consumed these characters
await ReadIntoBufferAsync().ConfigureAwait(false);
} while (_charsRead > 0);
return sb.ToString();
}
private readonly struct ReadLineStepResult
{
public static readonly ReadLineStepResult Done = new ReadLineStepResult(true, null);

View File

@ -7,6 +7,7 @@ using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@ -55,6 +56,22 @@ namespace Microsoft.AspNetCore.WebUtilities
Assert.Equal(5000, result.Length);
}
[Fact]
public static async Task ReadToEndAsync_Reads_Asynchronously()
{
// Arrange
var stream = new AsyncOnlyStreamWrapper(GetLargeStream());
var reader = new HttpRequestStreamReader(stream, Encoding.UTF8);
var streamReader = new StreamReader(GetLargeStream());
string expected = await streamReader.ReadToEndAsync();
// Act
var actual = await reader.ReadToEndAsync();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public static void TestRead()
{
@ -477,5 +494,84 @@ namespace Microsoft.AspNetCore.WebUtilities
httpRequestStreamReader.ReadLineAsync()
)};
}
private class AsyncOnlyStreamWrapper : Stream
{
private readonly Stream _inner;
public AsyncOnlyStreamWrapper(Stream inner)
{
_inner = inner;
}
public override bool CanRead => _inner.CanRead;
public override bool CanSeek => _inner.CanSeek;
public override bool CanWrite => _inner.CanWrite;
public override long Length => _inner.Length;
public override long Position
{
get => _inner.Position;
set => _inner.Position = value;
}
public override void Flush()
{
throw SyncOperationForbiddenException();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return _inner.FlushAsync(cancellationToken);
}
public override int Read(byte[] buffer, int offset, int count)
{
throw SyncOperationForbiddenException();
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _inner.ReadAsync(buffer, offset, count, cancellationToken);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _inner.Seek(offset, origin);
}
public override void SetLength(long value)
{
_inner.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
throw SyncOperationForbiddenException();
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _inner.WriteAsync(buffer, offset, count, cancellationToken);
}
protected override void Dispose(bool disposing)
{
_inner.Dispose();
}
public override ValueTask DisposeAsync()
{
return _inner.DisposeAsync();
}
private Exception SyncOperationForbiddenException()
{
return new InvalidOperationException("The stream cannot be accessed synchronously");
}
}
}
}