Implement HttpRequestStreamReader.ReadToEndAsync (#18232)
This commit is contained in:
parent
698ab1518d
commit
5d914d4d2d
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue