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; }
|
public override string ReadLine() { throw null; }
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
public override System.Threading.Tasks.Task<string> ReadLineAsync() { throw null; }
|
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
|
public partial class HttpResponseStreamWriter : System.IO.TextWriter
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -528,6 +528,20 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
return _charsRead;
|
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
|
private readonly struct ReadLineStepResult
|
||||||
{
|
{
|
||||||
public static readonly ReadLineStepResult Done = new ReadLineStepResult(true, null);
|
public static readonly ReadLineStepResult Done = new ReadLineStepResult(true, null);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -55,6 +56,22 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
Assert.Equal(5000, result.Length);
|
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]
|
[Fact]
|
||||||
public static void TestRead()
|
public static void TestRead()
|
||||||
{
|
{
|
||||||
|
|
@ -477,5 +494,84 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
httpRequestStreamReader.ReadLineAsync()
|
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