From 78e71792215efe5ed8f058edcfd2099e9a436c86 Mon Sep 17 00:00:00 2001 From: ryanbrandenburg Date: Fri, 15 Jan 2016 14:17:48 -0800 Subject: [PATCH] * Remove HttpRespomseStreamWriter --- .../HttpResponseStreamWriter.cs | 396 --------------- .../Infrastructure/HttpRequestStreamReader.cs | 438 ----------------- ...emoryPoolHttpRequestStreamReaderFactory.cs | 2 +- ...moryPoolHttpResponseStreamWriterFactory.cs | 1 + .../Resources.resx | 6 - .../ViewComponentResult.cs | 1 + .../HttpResponseStreamWriterTest.cs | 462 ------------------ .../HttpResponseStreamReaderTest.cs | 226 --------- .../TestHttpRequestStreamReaderFactory.cs | 2 +- .../TestHttpResponseStreamWriterFactory.cs | 1 + .../ViewFeatures/ViewExecutorTest.cs | 3 +- .../TestHttpResponseStreamWriterFactory.cs | 2 +- 12 files changed, 8 insertions(+), 1532 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Mvc.Core/HttpResponseStreamWriter.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/HttpRequestStreamReader.cs delete mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/HttpResponseStreamWriterTest.cs delete mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/HttpResponseStreamReaderTest.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Core/HttpResponseStreamWriter.cs b/src/Microsoft.AspNetCore.Mvc.Core/HttpResponseStreamWriter.cs deleted file mode 100644 index cb3e998256..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Core/HttpResponseStreamWriter.cs +++ /dev/null @@ -1,396 +0,0 @@ -// 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.Buffers; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.Core; - -namespace Microsoft.AspNetCore.Mvc -{ - /// - /// Writes to the using the supplied . - /// It does not write the BOM and also does not close the stream. - /// - public class HttpResponseStreamWriter : TextWriter - { - private const int MinBufferSize = 128; - - /// - /// Default buffer size. - /// - public const int DefaultBufferSize = 1024; - - private Stream _stream; - private readonly Encoder _encoder; - private readonly ArrayPool _bytePool; - private readonly ArrayPool _charPool; - private readonly int _charBufferSize; - - private byte[] _byteBuffer; - private char[] _charBuffer; - - private int _charBufferCount; - - public HttpResponseStreamWriter(Stream stream, Encoding encoding) - : this(stream, encoding, DefaultBufferSize) - { - } - - public HttpResponseStreamWriter(Stream stream, Encoding encoding, int bufferSize) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (!stream.CanWrite) - { - throw new ArgumentException(Resources.HttpResponseStreamWriter_StreamNotWritable, nameof(stream)); - } - - if (encoding == null) - { - throw new ArgumentNullException(nameof(encoding)); - } - - _stream = stream; - Encoding = encoding; - _charBufferSize = bufferSize; - - if (bufferSize < MinBufferSize) - { - bufferSize = MinBufferSize; - } - - _encoder = encoding.GetEncoder(); - _byteBuffer = new byte[encoding.GetMaxByteCount(bufferSize)]; - _charBuffer = new char[bufferSize]; - } - - public HttpResponseStreamWriter( - Stream stream, - Encoding encoding, - int bufferSize, - ArrayPool bytePool, - ArrayPool charPool) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (!stream.CanWrite) - { - throw new ArgumentException(Resources.HttpResponseStreamWriter_StreamNotWritable, nameof(stream)); - } - - if (encoding == null) - { - throw new ArgumentNullException(nameof(encoding)); - } - - if (bytePool == null) - { - throw new ArgumentNullException(nameof(bytePool)); - } - - if (charPool == null) - { - throw new ArgumentNullException(nameof(charPool)); - } - - _stream = stream; - Encoding = encoding; - _charBufferSize = bufferSize; - - _encoder = encoding.GetEncoder(); - _bytePool = bytePool; - _charPool = charPool; - - _charBuffer = charPool.Rent(bufferSize); - - try - { - var requiredLength = encoding.GetMaxByteCount(bufferSize); - _byteBuffer = bytePool.Rent(requiredLength); - } - catch - { - charPool.Return(_charBuffer); - _charBuffer = null; - - if (_byteBuffer != null) - { - bytePool.Return(_byteBuffer); - _byteBuffer = null; - } - - throw; - } - } - - public override Encoding Encoding { get; } - - public override void Write(char value) - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (_charBufferCount == _charBufferSize) - { - FlushInternal(flushEncoder: false); - } - - _charBuffer[_charBufferCount] = value; - _charBufferCount++; - } - - public override void Write(char[] values, int index, int count) - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (values == null) - { - return; - } - - while (count > 0) - { - if (_charBufferCount == _charBufferSize) - { - FlushInternal(flushEncoder: false); - } - - CopyToCharBuffer(values, ref index, ref count); - } - } - - public override void Write(string value) - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (value == null) - { - return; - } - - var count = value.Length; - var index = 0; - while (count > 0) - { - if (_charBufferCount == _charBufferSize) - { - FlushInternal(flushEncoder: false); - } - - CopyToCharBuffer(value, ref index, ref count); - } - } - - public override async Task WriteAsync(char value) - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (_charBufferCount == _charBufferSize) - { - await FlushInternalAsync(flushEncoder: false); - } - - _charBuffer[_charBufferCount] = value; - _charBufferCount++; - } - - public override async Task WriteAsync(char[] values, int index, int count) - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (values == null) - { - return; - } - - while (count > 0) - { - if (_charBufferCount == _charBufferSize) - { - await FlushInternalAsync(flushEncoder: false); - } - - CopyToCharBuffer(values, ref index, ref count); - } - } - - public override async Task WriteAsync(string value) - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (value == null) - { - return; - } - - var count = value.Length; - var index = 0; - while (count > 0) - { - if (_charBufferCount == _charBufferSize) - { - await FlushInternalAsync(flushEncoder: false); - } - - CopyToCharBuffer(value, ref index, ref count); - } - } - - // We want to flush the stream when Flush/FlushAsync is explicitly - // called by the user (example: from a Razor view). - - public override void Flush() - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - FlushInternal(flushEncoder: true); - } - - public override Task FlushAsync() - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - return FlushInternalAsync(flushEncoder: true); - } - - protected override void Dispose(bool disposing) - { - if (disposing && _stream != null) - { - try - { - FlushInternal(flushEncoder: true); - } - finally - { - _stream = null; - - if (_bytePool != null) - { - _bytePool.Return(_byteBuffer); - _byteBuffer = null; - } - - if (_charPool != null) - { - _charPool.Return(_charBuffer); - _charBuffer = null; - } - } - } - } - - // Note: our FlushInternal method does NOT flush the underlying stream. This would result in - // chunking. - private void FlushInternal(bool flushEncoder) - { - if (_charBufferCount == 0) - { - return; - } - - var count = _encoder.GetBytes( - _charBuffer, - 0, - _charBufferCount, - _byteBuffer, - 0, - flush: flushEncoder); - - if (count > 0) - { - _stream.Write(_byteBuffer, 0, count); - } - - _charBufferCount = 0; - } - - // Note: our FlushInternalAsync method does NOT flush the underlying stream. This would result in - // chunking. - private async Task FlushInternalAsync(bool flushEncoder) - { - if (_charBufferCount == 0) - { - return; - } - - var count = _encoder.GetBytes( - _charBuffer, - 0, - _charBufferCount, - _byteBuffer, - 0, - flush: flushEncoder); - - if (count > 0) - { - await _stream.WriteAsync(_byteBuffer, 0, count); - } - - _charBufferCount = 0; - } - - private void CopyToCharBuffer(string value, ref int index, ref int count) - { - var remaining = Math.Min(_charBufferSize - _charBufferCount, count); - - value.CopyTo( - sourceIndex: index, - destination: _charBuffer, - destinationIndex: _charBufferCount, - count: remaining); - - _charBufferCount += remaining; - index += remaining; - count -= remaining; - } - - private void CopyToCharBuffer(char[] values, ref int index, ref int count) - { - var remaining = Math.Min(_charBufferSize - _charBufferCount, count); - - Buffer.BlockCopy( - src: values, - srcOffset: index * sizeof(char), - dst: _charBuffer, - dstOffset: _charBufferCount * sizeof(char), - count: remaining * sizeof(char)); - - _charBufferCount += remaining; - index += remaining; - count -= remaining; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/HttpRequestStreamReader.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/HttpRequestStreamReader.cs deleted file mode 100644 index 66b7773344..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/HttpRequestStreamReader.cs +++ /dev/null @@ -1,438 +0,0 @@ -// 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.Buffers; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.Core; - -namespace Microsoft.AspNetCore.Mvc.Infrastructure -{ - public class HttpRequestStreamReader : TextReader - { - private const int DefaultBufferSize = 1024; - private const int MinBufferSize = 128; - private const int MaxSharedBuilderCapacity = 360; // also the max capacity used in StringBuilderCache - - private Stream _stream; - private readonly Encoding _encoding; - private readonly Decoder _decoder; - - private readonly ArrayPool _bytePool; - private readonly ArrayPool _charPool; - - private readonly int _byteBufferSize; - private byte[] _byteBuffer; - private char[] _charBuffer; - - private int _charBufferIndex; - private int _charsRead; - private int _bytesRead; - - private bool _isBlocked; - - public HttpRequestStreamReader(Stream stream, Encoding encoding) - : this(stream, encoding, DefaultBufferSize) - { - } - - public HttpRequestStreamReader(Stream stream, Encoding encoding, int bufferSize) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (!stream.CanRead) - { - throw new ArgumentException(Resources.HttpRequestStreamReader_StreamNotReadable, nameof(stream)); - } - - if (encoding == null) - { - throw new ArgumentNullException(nameof(encoding)); - } - - _stream = stream; - _encoding = encoding; - _decoder = encoding.GetDecoder(); - - if (bufferSize < MinBufferSize) - { - bufferSize = MinBufferSize; - } - - _byteBufferSize = bufferSize; - _byteBuffer = new byte[bufferSize]; - var maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize); - _charBuffer = new char[maxCharsPerBuffer]; - } - - public HttpRequestStreamReader( - Stream stream, - Encoding encoding, - int bufferSize, - ArrayPool bytePool, - ArrayPool charPool) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (!stream.CanRead) - { - throw new ArgumentException(Resources.HttpRequestStreamReader_StreamNotReadable, nameof(stream)); - } - - if (encoding == null) - { - throw new ArgumentNullException(nameof(encoding)); - } - - if (bytePool == null) - { - throw new ArgumentNullException(nameof(bytePool)); - } - - if (charPool == null) - { - throw new ArgumentNullException(nameof(charPool)); - } - - if (bufferSize <= 0) - { - throw new ArgumentOutOfRangeException(nameof(bufferSize)); - } - - _stream = stream; - _encoding = encoding; - _byteBufferSize = bufferSize; - _bytePool = bytePool; - _charPool = charPool; - - _decoder = encoding.GetDecoder(); - - _byteBuffer = _bytePool.Rent(bufferSize); - - try - { - var requiredLength = encoding.GetMaxCharCount(bufferSize); - _charBuffer = _charPool.Rent(requiredLength); - } - catch - { - _bytePool.Return(_byteBuffer); - _byteBuffer = null; - - if (_charBuffer != null) - { - _charPool.Return(_charBuffer); - _charBuffer = null; - } - } - } - -#if dnx451 - public override void Close() - { - Dispose(true); - } -#endif - - protected override void Dispose(bool disposing) - { - if (disposing && _stream != null) - { - _stream = null; - - if (_bytePool != null) - { - _bytePool.Return(_byteBuffer); - _byteBuffer = null; - } - - if (_charPool != null) - { - _charPool.Return(_charBuffer); - _charBuffer = null; - } - } - - base.Dispose(disposing); - } - - public override int Peek() - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (_charBufferIndex == _charsRead) - { - if (_isBlocked || ReadIntoBuffer() == 0) - { - return -1; - } - } - - return _charBuffer[_charBufferIndex]; - } - - public override int Read() - { - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (_charBufferIndex == _charsRead) - { - if (ReadIntoBuffer() == 0) - { - return -1; - } - } - - return _charBuffer[_charBufferIndex++]; - } - - public override int Read(char[] buffer, int index, int count) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (index < 0) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - if (count < 0 || index + count > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - var charsRead = 0; - while (count > 0) - { - var charsRemaining = _charsRead - _charBufferIndex; - if (charsRemaining == 0) - { - charsRemaining = ReadIntoBuffer(); - } - - if (charsRemaining == 0) - { - break; // We're at EOF - } - - if (charsRemaining > count) - { - charsRemaining = count; - } - - Buffer.BlockCopy( - _charBuffer, - _charBufferIndex * 2, - buffer, - (index + charsRead) * 2, - charsRemaining * 2); - _charBufferIndex += charsRemaining; - - charsRead += charsRemaining; - count -= charsRemaining; - - // If we got back fewer chars than we asked for, then it's likely the underlying stream is blocked. - // Send the data back to the caller so they can process it. - if (_isBlocked) - { - break; - } - } - - return charsRead; - } - - public override async Task ReadAsync(char[] buffer, int index, int count) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (index < 0) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - if (count < 0 || index + count > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - if (_stream == null) - { - throw new ObjectDisposedException("stream"); - } - - if (_charBufferIndex == _charsRead && await ReadIntoBufferAsync() == 0) - { - return 0; - } - - var charsRead = 0; - while (count > 0) - { - // n is the characters available in _charBuffer - var n = _charsRead - _charBufferIndex; - - // charBuffer is empty, let's read from the stream - if (n == 0) - { - _charsRead = 0; - _charBufferIndex = 0; - _bytesRead = 0; - - // We loop here so that we read in enough bytes to yield at least 1 char. - // We break out of the loop if the stream is blocked (EOF is reached). - do - { - Debug.Assert(n == 0); - _bytesRead = await _stream.ReadAsync( - _byteBuffer, - 0, - _byteBufferSize); - if (_bytesRead == 0) // EOF - { - _isBlocked = true; - break; - } - - // _isBlocked == whether we read fewer bytes than we asked for. - _isBlocked = (_bytesRead < _byteBufferSize); - - Debug.Assert(n == 0); - - _charBufferIndex = 0; - n = _decoder.GetChars( - _byteBuffer, - 0, - _bytesRead, - _charBuffer, - 0); - - Debug.Assert(n > 0); - - _charsRead += n; // Number of chars in StreamReader's buffer. - } - while (n == 0); - - if (n == 0) - { - break; // We're at EOF - } - } - - // Got more chars in charBuffer than the user requested - if (n > count) - { - n = count; - } - - Buffer.BlockCopy( - _charBuffer, - _charBufferIndex * 2, - buffer, - (index + charsRead) * 2, - n * 2); - - _charBufferIndex += n; - - charsRead += n; - count -= n; - - // This function shouldn't block for an indefinite amount of time, - // or reading from a network stream won't work right. If we got - // fewer bytes than we requested, then we want to break right here. - if (_isBlocked) - { - break; - } - } - - return charsRead; - } - - private int ReadIntoBuffer() - { - _charsRead = 0; - _charBufferIndex = 0; - _bytesRead = 0; - - do - { - _bytesRead = _stream.Read(_byteBuffer, 0, _byteBufferSize); - if (_bytesRead == 0) // We're at EOF - { - return _charsRead; - } - - _isBlocked = (_bytesRead < _byteBufferSize); - _charsRead += _decoder.GetChars( - _byteBuffer, - 0, - _bytesRead, - _charBuffer, - _charsRead); - } - while (_charsRead == 0); - - return _charsRead; - } - - private async Task ReadIntoBufferAsync() - { - _charsRead = 0; - _charBufferIndex = 0; - _bytesRead = 0; - - do - { - - _bytesRead = await _stream.ReadAsync( - _byteBuffer, - 0, - _byteBufferSize).ConfigureAwait(false); - if (_bytesRead == 0) - { - // We're at EOF - return _charsRead; - } - - // _isBlocked == whether we read fewer bytes than we asked for. - _isBlocked = (_bytesRead < _byteBufferSize); - - _charsRead += _decoder.GetChars( - _byteBuffer, - 0, - _bytesRead, - _charBuffer, - _charsRead); - } - while (_charsRead == 0); - - return _charsRead; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpRequestStreamReaderFactory.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpRequestStreamReaderFactory.cs index 0e2cc41fe3..d006ebcb54 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpRequestStreamReaderFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpRequestStreamReaderFactory.cs @@ -5,7 +5,7 @@ using System; using System.Buffers; using System.IO; using System.Text; -using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.WebUtilities; namespace Microsoft.AspNetCore.Mvc.Internal { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpResponseStreamWriterFactory.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpResponseStreamWriterFactory.cs index 4ea586adf5..4d66f3af3a 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpResponseStreamWriterFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MemoryPoolHttpResponseStreamWriterFactory.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.IO; using System.Text; +using Microsoft.AspNetCore.WebUtilities; namespace Microsoft.AspNetCore.Mvc.Internal { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx index cd6bcce648..7a5bf847d5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx @@ -313,12 +313,6 @@ The supplied URL is not local. A URL with an absolute path is considered local if it does not have a host/authority part. URLs using virtual paths ('~/') are also local. - - The stream must support reading. - - - The stream must support writing. - The argument '{0}' is invalid. Empty or null formats are not supported. diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponentResult.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponentResult.cs index 3e29a5c8de..feb16b3b8f 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponentResult.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponentResult.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; +using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpResponseStreamWriterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpResponseStreamWriterTest.cs deleted file mode 100644 index c8b349d6f3..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/HttpResponseStreamWriterTest.cs +++ /dev/null @@ -1,462 +0,0 @@ -// 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.Buffers; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc -{ - public class HttpResponseStreamWriterTest - { - [Fact] - public async Task DoesNotWriteBOM() - { - // Arrange - var memoryStream = new MemoryStream(); - var encodingWithBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); - var writer = new HttpResponseStreamWriter(memoryStream, encodingWithBOM); - var expectedData = new byte[] { 97, 98, 99, 100 }; // without BOM - - // Act - using (writer) - { - await writer.WriteAsync("abcd"); - } - - // Assert - Assert.Equal(expectedData, memoryStream.ToArray()); - } - -#if DNX451 - [Fact] - public async Task DoesNotFlush_UnderlyingStream_OnClosingWriter() - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - await writer.WriteAsync("Hello"); - writer.Close(); - - // Assert - Assert.Equal(0, stream.FlushCallCount); - Assert.Equal(0, stream.FlushAsyncCallCount); - } -#endif - - [Fact] - public async Task DoesNotFlush_UnderlyingStream_OnDisposingWriter() - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - await writer.WriteAsync("Hello"); - writer.Dispose(); - - // Assert - Assert.Equal(0, stream.FlushCallCount); - Assert.Equal(0, stream.FlushAsyncCallCount); - } - -#if DNX451 - [Fact] - public async Task DoesNotClose_UnderlyingStream_OnDisposingWriter() - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - await writer.WriteAsync("Hello"); - writer.Close(); - - // Assert - Assert.Equal(0, stream.CloseCallCount); - } -#endif - - [Fact] - public async Task DoesNotDispose_UnderlyingStream_OnDisposingWriter() - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - await writer.WriteAsync("Hello world"); - writer.Dispose(); - - // Assert - Assert.Equal(0, stream.DisposeCallCount); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public async Task FlushesBuffer_OnClose(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - await writer.WriteAsync(new string('a', byteLength)); - - // Act -#if DNX451 - writer.Close(); -#else - writer.Dispose(); -#endif - - // Assert - Assert.Equal(0, stream.FlushCallCount); - Assert.Equal(0, stream.FlushAsyncCallCount); - Assert.Equal(byteLength, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public async Task FlushesBuffer_OnDispose(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - await writer.WriteAsync(new string('a', byteLength)); - - // Act - writer.Dispose(); - - // Assert - Assert.Equal(0, stream.FlushCallCount); - Assert.Equal(0, stream.FlushAsyncCallCount); - Assert.Equal(byteLength, stream.Length); - } - - [Fact] - public void NoDataWritten_Flush_DoesNotFlushUnderlyingStream() - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - writer.Flush(); - - // Assert - Assert.Equal(0, stream.FlushCallCount); - Assert.Equal(0, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public void FlushesBuffer_ButNotStream_OnFlush(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - writer.Write(new string('a', byteLength)); - - var expectedWriteCount = Math.Ceiling((double)byteLength / HttpResponseStreamWriter.DefaultBufferSize); - - // Act - writer.Flush(); - - // Assert - Assert.Equal(0, stream.FlushCallCount); - Assert.Equal(expectedWriteCount, stream.WriteCallCount); - Assert.Equal(byteLength, stream.Length); - } - - [Fact] - public async Task NoDataWritten_FlushAsync_DoesNotFlushUnderlyingStream() - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - await writer.FlushAsync(); - - // Assert - Assert.Equal(0, stream.FlushAsyncCallCount); - Assert.Equal(0, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public async Task FlushesBuffer_ButNotStream_OnFlushAsync(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - await writer.WriteAsync(new string('a', byteLength)); - - var expectedWriteCount = Math.Ceiling((double)byteLength / HttpResponseStreamWriter.DefaultBufferSize); - - // Act - await writer.FlushAsync(); - - // Assert - Assert.Equal(0, stream.FlushAsyncCallCount); - Assert.Equal(expectedWriteCount, stream.WriteAsyncCallCount); - Assert.Equal(byteLength, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public void WriteChar_WritesToStream(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - using (writer) - { - for (var i = 0; i < byteLength; i++) - { - writer.Write('a'); - } - } - - // Assert - Assert.Equal(byteLength, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public void WriteCharArray_WritesToStream(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - using (writer) - { - writer.Write((new string('a', byteLength)).ToCharArray()); - } - - // Assert - Assert.Equal(byteLength, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public async Task WriteCharAsync_WritesToStream(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - using (writer) - { - for (var i = 0; i < byteLength; i++) - { - await writer.WriteAsync('a'); - } - } - - // Assert - Assert.Equal(byteLength, stream.Length); - } - - [Theory] - [InlineData(1023)] - [InlineData(1024)] - [InlineData(1050)] - [InlineData(2048)] - public async Task WriteCharArrayAsync_WritesToStream(int byteLength) - { - // Arrange - var stream = new TestMemoryStream(); - var writer = new HttpResponseStreamWriter(stream, Encoding.UTF8); - - // Act - using (writer) - { - await writer.WriteAsync((new string('a', byteLength)).ToCharArray()); - } - - // Assert - Assert.Equal(byteLength, stream.Length); - } - - [Theory] - [InlineData("你好世界", "utf-16")] -#if !DNXCORE50 - // CoreCLR does not like shift_jis as an encoding. - [InlineData("こんにちは世界", "shift_jis")] -#endif - [InlineData("హలో ప్రపంచ", "iso-8859-1")] - [InlineData("வணக்கம் உலக", "utf-32")] - public async Task WritesData_InExpectedEncoding(string data, string encodingName) - { - // Arrange - var encoding = Encoding.GetEncoding(encodingName); - var expectedBytes = encoding.GetBytes(data); - var stream = new MemoryStream(); - var writer = new HttpResponseStreamWriter(stream, encoding); - - // Act - using (writer) - { - await writer.WriteAsync(data); - } - - // Assert - Assert.Equal(expectedBytes, stream.ToArray()); - } - - [Theory] - [InlineData('ん', 1023, "utf-8")] - [InlineData('ん', 1024, "utf-8")] - [InlineData('ん', 1050, "utf-8")] - [InlineData('你', 1023, "utf-16")] - [InlineData('你', 1024, "utf-16")] - [InlineData('你', 1050, "utf-16")] -#if !DNXCORE50 - // CoreCLR does not like shift_jis as an encoding. - [InlineData('こ', 1023, "shift_jis")] - [InlineData('こ', 1024, "shift_jis")] - [InlineData('こ', 1050, "shift_jis")] -#endif - [InlineData('హ', 1023, "iso-8859-1")] - [InlineData('హ', 1024, "iso-8859-1")] - [InlineData('హ', 1050, "iso-8859-1")] - [InlineData('வ', 1023, "utf-32")] - [InlineData('வ', 1024, "utf-32")] - [InlineData('வ', 1050, "utf-32")] - public async Task WritesData_OfDifferentLength_InExpectedEncoding( - char character, - int charCount, - string encodingName) - { - // Arrange - var encoding = Encoding.GetEncoding(encodingName); - string data = new string(character, charCount); - var expectedBytes = encoding.GetBytes(data); - var stream = new MemoryStream(); - var writer = new HttpResponseStreamWriter(stream, encoding); - - // Act - using (writer) - { - await writer.WriteAsync(data); - } - - // Assert - Assert.Equal(expectedBytes, stream.ToArray()); - } - - // None of the code in HttpResponseStreamWriter differs significantly when using pooled buffers. - // - // This test effectively verifies that things are correctly constructed and disposed. Pooled buffers - // throw on the finalizer thread if not disposed, so that's why it's complicated. - [Fact] - public void HttpResponseStreamWriter_UsingPooledBuffers() - { - // Arrange - var encoding = Encoding.UTF8; - var stream = new MemoryStream(); - - var expectedBytes = encoding.GetBytes("Hello, World!"); - - using (var writer = new HttpResponseStreamWriter( - stream, - encoding, - 1024, - ArrayPool.Shared, - ArrayPool.Shared)) - { - // Act - writer.Write("Hello, World!"); - } - - // Assert - Assert.Equal(expectedBytes, stream.ToArray()); - } - - private class TestMemoryStream : MemoryStream - { - public int FlushCallCount { get; private set; } - - public int FlushAsyncCallCount { get; private set; } - - public int CloseCallCount { get; private set; } - - public int DisposeCallCount { get; private set; } - - public int WriteCallCount { get; private set; } - - public int WriteAsyncCallCount { get; private set; } - - public override void Flush() - { - FlushCallCount++; - base.Flush(); - } - - public override Task FlushAsync(CancellationToken cancellationToken) - { - FlushAsyncCallCount++; - return base.FlushAsync(cancellationToken); - } - - public override void Write(byte[] buffer, int offset, int count) - { - WriteCallCount++; - base.Write(buffer, offset, count); - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - WriteAsyncCallCount++; - return base.WriteAsync(buffer, offset, count, cancellationToken); - } - -#if DNX451 - public override void Close() - { - CloseCallCount++; - base.Close(); - } -#endif - - protected override void Dispose(bool disposing) - { - DisposeCallCount++; - base.Dispose(disposing); - } - } - } -} diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/HttpResponseStreamReaderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/HttpResponseStreamReaderTest.cs deleted file mode 100644 index 4a3f1b4440..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/HttpResponseStreamReaderTest.cs +++ /dev/null @@ -1,226 +0,0 @@ -// 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.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Infrastructure -{ - public class HttpResponseStreamReaderTest - { - private static readonly char[] CharData = new char[] - { - char.MinValue, - char.MaxValue, - '\t', - ' ', - '$', - '@', - '#', - '\0', - '\v', - '\'', - '\u3190', - '\uC3A0', - 'A', - '5', - '\r', - '\uFE70', - '-', - ';', - '\r', - '\n', - 'T', - '3', - '\n', - 'K', - '\u00E6', - }; - - [Fact] - public static async Task ReadToEndAsync() - { - // Arrange - var reader = new HttpRequestStreamReader(GetLargeStream(), Encoding.UTF8); - - var result = await reader.ReadToEndAsync(); - - Assert.Equal(5000, result.Length); - } - - [Fact] - public static void TestRead() - { - // Arrange - var reader = CreateReader(); - - // Act & Assert - for (var i = 0; i < CharData.Length; i++) - { - var tmp = reader.Read(); - Assert.Equal((int)CharData[i], tmp); - } - } - - [Fact] - public static void TestPeek() - { - // Arrange - var reader = CreateReader(); - - // Act & Assert - for (var i = 0; i < CharData.Length; i++) - { - var peek = reader.Peek(); - Assert.Equal((int)CharData[i], peek); - - reader.Read(); - } - } - - [Fact] - public static void EmptyStream() - { - // Arrange - var reader = new HttpRequestStreamReader(new MemoryStream(), Encoding.UTF8); - var buffer = new char[10]; - - // Act - var read = reader.Read(buffer, 0, 1); - - // Assert - Assert.Equal(0, read); - } - - [Fact] - public static void Read_ReadAllCharactersAtOnce() - { - // Arrange - var reader = CreateReader(); - var chars = new char[CharData.Length]; - - // Act - var read = reader.Read(chars, 0, chars.Length); - - // Assert - Assert.Equal(chars.Length, read); - for (var i = 0; i < CharData.Length; i++) - { - Assert.Equal(CharData[i], chars[i]); - } - } - - [Fact] - public static async Task Read_ReadInTwoChunks() - { - // Arrange - var reader = CreateReader(); - var chars = new char[CharData.Length]; - - // Act - var read = await reader.ReadAsync(chars, 4, 3); - - // Assert - Assert.Equal(read, 3); - for (var i = 0; i < 3; i++) - { - Assert.Equal(CharData[i], chars[i + 4]); - } - } - - [Fact] - public static void ReadLine_ReadMultipleLines() - { - // Arrange - var reader = CreateReader(); - var valueString = new string(CharData); - - // Act & Assert - var data = reader.ReadLine(); - Assert.Equal(valueString.Substring(0, valueString.IndexOf('\r')), data); - - data = reader.ReadLine(); - Assert.Equal(valueString.Substring(valueString.IndexOf('\r') + 1, 3), data); - - data = reader.ReadLine(); - Assert.Equal(valueString.Substring(valueString.IndexOf('\n') + 1, 2), data); - - data = reader.ReadLine(); - Assert.Equal((valueString.Substring(valueString.LastIndexOf('\n') + 1)), data); - } - - [Fact] - public static void ReadLine_ReadWithNoNewlines() - { - // Arrange - var reader = CreateReader(); - var valueString = new string(CharData); - var temp = new char[10]; - - // Act - reader.Read(temp, 0, 1); - var data = reader.ReadLine(); - - // Assert - Assert.Equal(valueString.Substring(1, valueString.IndexOf('\r') - 1), data); - } - - [Fact] - public static async Task ReadLineAsync_MultipleContinuousLines() - { - // Arrange - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write("\n\n\r\r\n"); - writer.Flush(); - stream.Position = 0; - - var reader = new HttpRequestStreamReader(stream, Encoding.UTF8); - - // Act & Assert - for (var i = 0; i < 4; i++) - { - var data = await reader.ReadLineAsync(); - Assert.Equal(string.Empty, data); - } - - var eol = await reader.ReadLineAsync(); - Assert.Null(eol); - } - - private static HttpRequestStreamReader CreateReader() - { - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(CharData); - writer.Flush(); - stream.Position = 0; - - return new HttpRequestStreamReader(stream, Encoding.UTF8); - } - - private static MemoryStream GetSmallStream() - { - var testData = new byte[] { 72, 69, 76, 76, 79 }; - return new MemoryStream(testData); - } - - private static MemoryStream GetLargeStream() - { - var testData = new byte[] { 72, 69, 76, 76, 79 }; - // System.Collections.Generic. - - var data = new List(); - for (var i = 0; i < 1000; i++) - { - data.AddRange(testData); - } - - return new MemoryStream(data.ToArray()); - } - } -} diff --git a/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpRequestStreamReaderFactory.cs b/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpRequestStreamReaderFactory.cs index 2f69699c17..cd4d765ea1 100644 --- a/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpRequestStreamReaderFactory.cs +++ b/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpRequestStreamReaderFactory.cs @@ -3,8 +3,8 @@ using System.IO; using System.Text; -using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Internal; +using Microsoft.AspNetCore.WebUtilities; namespace Microsoft.AspNetCore.Mvc { diff --git a/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpResponseStreamWriterFactory.cs b/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpResponseStreamWriterFactory.cs index 3e94372062..3b48544ff9 100644 --- a/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpResponseStreamWriterFactory.cs +++ b/test/Microsoft.AspNetCore.Mvc.TestCommon/TestHttpResponseStreamWriterFactory.cs @@ -4,6 +4,7 @@ using System.IO; using System.Text; using Microsoft.AspNetCore.Mvc.Internal; +using Microsoft.AspNetCore.WebUtilities; namespace Microsoft.AspNetCore.Mvc { diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs index 63bdf73e63..2f9651dd75 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.TestCommon; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; using Moq; @@ -338,7 +339,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Assert stream.Verify(s => s.FlushAsync(It.IsAny()), Times.Never()); stream.Verify( - s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), + s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly((int)expectedWriteCallCount)); stream.Verify(s => s.Write(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } diff --git a/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs b/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs index 38ef3c702c..3b48544ff9 100644 --- a/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs +++ b/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs @@ -3,8 +3,8 @@ using System.IO; using System.Text; -using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Internal; +using Microsoft.AspNetCore.WebUtilities; namespace Microsoft.AspNetCore.Mvc {