Use system.buffers for our reader/writer
This commit is contained in:
parent
5f66403248
commit
8fb187bf09
|
|
@ -2,8 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNet.Http;
|
using System.Buffers;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.ActionConstraints;
|
using Microsoft.AspNet.Mvc.ActionConstraints;
|
||||||
|
|
@ -18,7 +17,6 @@ using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||||
using Microsoft.AspNet.Mvc.Routing;
|
using Microsoft.AspNet.Mvc.Routing;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
using Microsoft.Extensions.OptionsModel;
|
using Microsoft.Extensions.OptionsModel;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
|
||||||
|
|
@ -144,8 +142,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.TryAddSingleton<IUrlHelperFactory, UrlHelperFactory>();
|
services.TryAddSingleton<IUrlHelperFactory, UrlHelperFactory>();
|
||||||
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
|
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
|
||||||
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();
|
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();
|
||||||
services.TryAddSingleton<IArraySegmentPool<byte>, DefaultArraySegmentPool<byte>>();
|
services.TryAddSingleton(ArrayPool<byte>.Shared);
|
||||||
services.TryAddSingleton<IArraySegmentPool<char>, DefaultArraySegmentPool<char>>();
|
services.TryAddSingleton(ArrayPool<char>.Shared);
|
||||||
services.TryAddSingleton<ObjectResultExecutor>();
|
services.TryAddSingleton<ObjectResultExecutor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -23,13 +23,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int DefaultBufferSize = 1024;
|
public const int DefaultBufferSize = 1024;
|
||||||
|
|
||||||
private readonly Stream _stream;
|
private Stream _stream;
|
||||||
private Encoder _encoder;
|
private readonly Encoder _encoder;
|
||||||
private LeasedArraySegment<byte> _leasedByteBuffer;
|
private readonly ArrayPool<byte> _bytePool;
|
||||||
private LeasedArraySegment<char> _leasedCharBuffer;
|
private readonly ArrayPool<char> _charPool;
|
||||||
private ArraySegment<byte> _byteBuffer;
|
private readonly int _charBufferSize;
|
||||||
private ArraySegment<char> _charBuffer;
|
|
||||||
private int _charBufferSize;
|
private byte[] _byteBuffer;
|
||||||
|
private char[] _charBuffer;
|
||||||
|
|
||||||
private int _charBufferCount;
|
private int _charBufferCount;
|
||||||
|
|
||||||
public HttpResponseStreamWriter(Stream stream, Encoding encoding)
|
public HttpResponseStreamWriter(Stream stream, Encoding encoding)
|
||||||
|
|
@ -64,16 +66,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
_encoder = encoding.GetEncoder();
|
_encoder = encoding.GetEncoder();
|
||||||
_byteBuffer = new ArraySegment<byte>(new byte[encoding.GetMaxByteCount(bufferSize)]);
|
_byteBuffer = new byte[encoding.GetMaxByteCount(bufferSize)];
|
||||||
_charBuffer = new ArraySegment<char>(new char[bufferSize]);
|
_charBuffer = new char[bufferSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpResponseStreamWriter(
|
public HttpResponseStreamWriter(
|
||||||
Stream stream,
|
Stream stream,
|
||||||
Encoding encoding,
|
Encoding encoding,
|
||||||
int bufferSize,
|
int bufferSize,
|
||||||
LeasedArraySegment<byte> leasedByteBuffer,
|
ArrayPool<byte> bytePool,
|
||||||
LeasedArraySegment<char> leasedCharBuffer)
|
ArrayPool<char> charPool)
|
||||||
{
|
{
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
|
|
@ -90,59 +92,71 @@ namespace Microsoft.AspNet.Mvc
|
||||||
throw new ArgumentNullException(nameof(encoding));
|
throw new ArgumentNullException(nameof(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leasedByteBuffer == null)
|
if (bytePool == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(leasedByteBuffer));
|
throw new ArgumentNullException(nameof(bytePool));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leasedCharBuffer == null)
|
if (charPool == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(leasedCharBuffer));
|
throw new ArgumentNullException(nameof(charPool));
|
||||||
}
|
|
||||||
|
|
||||||
if (bufferSize <= 0 || bufferSize > leasedCharBuffer.Data.Count)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
var requiredLength = encoding.GetMaxByteCount(bufferSize);
|
|
||||||
if (requiredLength > leasedByteBuffer.Data.Count)
|
|
||||||
{
|
|
||||||
var message = Resources.FormatHttpResponseStreamWriter_InvalidBufferSize(
|
|
||||||
requiredLength,
|
|
||||||
bufferSize,
|
|
||||||
encoding.EncodingName,
|
|
||||||
typeof(Encoding).FullName,
|
|
||||||
nameof(Encoding.GetMaxByteCount));
|
|
||||||
throw new ArgumentException(message, nameof(leasedByteBuffer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_stream = stream;
|
_stream = stream;
|
||||||
Encoding = encoding;
|
Encoding = encoding;
|
||||||
_charBufferSize = bufferSize;
|
_charBufferSize = bufferSize;
|
||||||
_leasedByteBuffer = leasedByteBuffer;
|
|
||||||
_leasedCharBuffer = leasedCharBuffer;
|
|
||||||
|
|
||||||
_encoder = encoding.GetEncoder();
|
_encoder = encoding.GetEncoder();
|
||||||
_byteBuffer = leasedByteBuffer.Data;
|
_bytePool = bytePool;
|
||||||
_charBuffer = leasedCharBuffer.Data;
|
_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 Encoding Encoding { get; }
|
||||||
|
|
||||||
public override void Write(char value)
|
public override void Write(char value)
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
if (_charBufferCount == _charBufferSize)
|
if (_charBufferCount == _charBufferSize)
|
||||||
{
|
{
|
||||||
FlushInternal();
|
FlushInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
_charBuffer.Array[_charBuffer.Offset + _charBufferCount] = value;
|
_charBuffer[_charBufferCount] = value;
|
||||||
_charBufferCount++;
|
_charBufferCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(char[] values, int index, int count)
|
public override void Write(char[] values, int index, int count)
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
if (values == null)
|
if (values == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -161,6 +175,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public override void Write(string value)
|
public override void Write(string value)
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -181,17 +200,27 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public override async Task WriteAsync(char value)
|
public override async Task WriteAsync(char value)
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
if (_charBufferCount == _charBufferSize)
|
if (_charBufferCount == _charBufferSize)
|
||||||
{
|
{
|
||||||
await FlushInternalAsync();
|
await FlushInternalAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
_charBuffer.Array[_charBuffer.Offset + _charBufferCount] = value;
|
_charBuffer[_charBufferCount] = value;
|
||||||
_charBufferCount++;
|
_charBufferCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task WriteAsync(char[] values, int index, int count)
|
public override async Task WriteAsync(char[] values, int index, int count)
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
if (values == null)
|
if (values == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -210,6 +239,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public override async Task WriteAsync(string value)
|
public override async Task WriteAsync(string value)
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -233,11 +267,21 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
FlushInternal(true, true);
|
FlushInternal(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task FlushAsync()
|
public override Task FlushAsync()
|
||||||
{
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
return FlushInternalAsync(flushStream: true, flushEncoder: true);
|
return FlushInternalAsync(flushStream: true, flushEncoder: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +289,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// sent in chunked encoding in case of Helios.
|
// sent in chunked encoding in case of Helios.
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing && _stream != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -253,14 +297,18 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (_leasedByteBuffer != null)
|
_stream = null;
|
||||||
|
|
||||||
|
if (_bytePool != null)
|
||||||
{
|
{
|
||||||
_leasedByteBuffer.Owner.Return(_leasedByteBuffer);
|
_bytePool.Return(_byteBuffer);
|
||||||
|
_byteBuffer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_leasedCharBuffer != null)
|
if (_charPool != null)
|
||||||
{
|
{
|
||||||
_leasedCharBuffer.Owner.Return(_leasedCharBuffer);
|
_charPool.Return(_charBuffer);
|
||||||
|
_charBuffer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,16 +322,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = _encoder.GetBytes(
|
var count = _encoder.GetBytes(
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
_charBuffer.Offset,
|
0,
|
||||||
_charBufferCount,
|
_charBufferCount,
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
flushEncoder);
|
flushEncoder);
|
||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
_stream.Write(_byteBuffer.Array, _byteBuffer.Offset, count);
|
_stream.Write(_byteBuffer, 0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
_charBufferCount = 0;
|
_charBufferCount = 0;
|
||||||
|
|
@ -302,16 +350,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = _encoder.GetBytes(
|
var count = _encoder.GetBytes(
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
_charBuffer.Offset,
|
0,
|
||||||
_charBufferCount,
|
_charBufferCount,
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
flushEncoder);
|
flushEncoder);
|
||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
await _stream.WriteAsync(_byteBuffer.Array, _byteBuffer.Offset, count);
|
await _stream.WriteAsync(_byteBuffer, 0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
_charBufferCount = 0;
|
_charBufferCount = 0;
|
||||||
|
|
@ -328,8 +376,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
value.CopyTo(
|
value.CopyTo(
|
||||||
sourceIndex: index,
|
sourceIndex: index,
|
||||||
destination: _charBuffer.Array,
|
destination: _charBuffer,
|
||||||
destinationIndex: _charBuffer.Offset + _charBufferCount,
|
destinationIndex: _charBufferCount,
|
||||||
count: remaining);
|
count: remaining);
|
||||||
|
|
||||||
_charBufferCount += remaining;
|
_charBufferCount += remaining;
|
||||||
|
|
@ -344,8 +392,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Buffer.BlockCopy(
|
Buffer.BlockCopy(
|
||||||
src: values,
|
src: values,
|
||||||
srcOffset: index * sizeof(char),
|
srcOffset: index * sizeof(char),
|
||||||
dst: _charBuffer.Array,
|
dst: _charBuffer,
|
||||||
dstOffset: (_charBuffer.Offset + _charBufferCount) * sizeof(char),
|
dstOffset: _charBufferCount * sizeof(char),
|
||||||
count: remaining * sizeof(char));
|
count: remaining * sizeof(char));
|
||||||
|
|
||||||
_charBufferCount += remaining;
|
_charBufferCount += remaining;
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
@ -21,12 +21,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
private readonly Encoding _encoding;
|
private readonly Encoding _encoding;
|
||||||
private readonly Decoder _decoder;
|
private readonly Decoder _decoder;
|
||||||
|
|
||||||
private readonly LeasedArraySegment<byte> _leasedByteBuffer;
|
private readonly ArrayPool<byte> _bytePool;
|
||||||
private readonly LeasedArraySegment<char> _leasedCharBuffer;
|
private readonly ArrayPool<char> _charPool;
|
||||||
|
|
||||||
private readonly int _byteBufferSize;
|
private readonly int _byteBufferSize;
|
||||||
private readonly ArraySegment<byte> _byteBuffer;
|
private byte[] _byteBuffer;
|
||||||
private readonly ArraySegment<char> _charBuffer;
|
private char[] _charBuffer;
|
||||||
|
|
||||||
private int _charBufferIndex;
|
private int _charBufferIndex;
|
||||||
private int _charsRead;
|
private int _charsRead;
|
||||||
|
|
@ -66,17 +66,17 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
_byteBufferSize = bufferSize;
|
_byteBufferSize = bufferSize;
|
||||||
_byteBuffer = new ArraySegment<byte>(new byte[bufferSize]);
|
_byteBuffer = new byte[bufferSize];
|
||||||
var maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
|
var maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
|
||||||
_charBuffer = new ArraySegment<char>(new char[maxCharsPerBuffer]);
|
_charBuffer = new char[maxCharsPerBuffer];
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequestStreamReader(
|
public HttpRequestStreamReader(
|
||||||
Stream stream,
|
Stream stream,
|
||||||
Encoding encoding,
|
Encoding encoding,
|
||||||
int bufferSize,
|
int bufferSize,
|
||||||
LeasedArraySegment<byte> leasedByteBuffer,
|
ArrayPool<byte> bytePool,
|
||||||
LeasedArraySegment<char> leasedCharBuffer)
|
ArrayPool<char> charPool)
|
||||||
{
|
{
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
|
|
@ -93,42 +93,47 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
throw new ArgumentNullException(nameof(encoding));
|
throw new ArgumentNullException(nameof(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leasedByteBuffer == null)
|
if (bytePool == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(leasedByteBuffer));
|
throw new ArgumentNullException(nameof(bytePool));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leasedCharBuffer == null)
|
if (charPool == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(leasedCharBuffer));
|
throw new ArgumentNullException(nameof(charPool));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferSize <= 0 || bufferSize > leasedByteBuffer.Data.Count)
|
if (bufferSize <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
var requiredLength = encoding.GetMaxCharCount(bufferSize);
|
|
||||||
if (requiredLength > leasedCharBuffer.Data.Count)
|
|
||||||
{
|
|
||||||
var message = Resources.FormatHttpRequestStreamReader_InvalidBufferSize(
|
|
||||||
requiredLength,
|
|
||||||
bufferSize,
|
|
||||||
encoding.EncodingName,
|
|
||||||
typeof(Encoding).FullName,
|
|
||||||
nameof(Encoding.GetMaxCharCount));
|
|
||||||
throw new ArgumentException(message, nameof(leasedCharBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
_stream = stream;
|
_stream = stream;
|
||||||
_encoding = encoding;
|
_encoding = encoding;
|
||||||
_byteBufferSize = bufferSize;
|
_byteBufferSize = bufferSize;
|
||||||
_leasedByteBuffer = leasedByteBuffer;
|
_bytePool = bytePool;
|
||||||
_leasedCharBuffer = leasedCharBuffer;
|
_charPool = charPool;
|
||||||
|
|
||||||
_decoder = encoding.GetDecoder();
|
_decoder = encoding.GetDecoder();
|
||||||
_byteBuffer = _leasedByteBuffer.Data;
|
|
||||||
_charBuffer = _leasedCharBuffer.Data;
|
_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
|
#if dnx451
|
||||||
|
|
@ -144,14 +149,16 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
_stream = null;
|
_stream = null;
|
||||||
|
|
||||||
if (_leasedByteBuffer != null)
|
if (_bytePool != null)
|
||||||
{
|
{
|
||||||
_leasedByteBuffer.Owner.Return(_leasedByteBuffer);
|
_bytePool.Return(_byteBuffer);
|
||||||
|
_byteBuffer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_leasedCharBuffer != null)
|
if (_charPool != null)
|
||||||
{
|
{
|
||||||
_leasedCharBuffer.Owner.Return(_leasedCharBuffer);
|
_charPool.Return(_charBuffer);
|
||||||
|
_charBuffer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,7 +180,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _charBuffer.Array[_charBuffer.Offset + _charBufferIndex];
|
return _charBuffer[_charBufferIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read()
|
public override int Read()
|
||||||
|
|
@ -191,7 +198,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _charBuffer.Array[_charBuffer.Offset + _charBufferIndex++];
|
return _charBuffer[_charBufferIndex++];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read(char[] buffer, int index, int count)
|
public override int Read(char[] buffer, int index, int count)
|
||||||
|
|
@ -236,8 +243,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer.BlockCopy(
|
Buffer.BlockCopy(
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
(_charBuffer.Offset + _charBufferIndex) * 2,
|
_charBufferIndex * 2,
|
||||||
buffer,
|
buffer,
|
||||||
(index + charsRead) * 2,
|
(index + charsRead) * 2,
|
||||||
charsRemaining * 2);
|
charsRemaining * 2);
|
||||||
|
|
@ -303,8 +310,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
Debug.Assert(n == 0);
|
Debug.Assert(n == 0);
|
||||||
_bytesRead = await _stream.ReadAsync(
|
_bytesRead = await _stream.ReadAsync(
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
_byteBufferSize);
|
_byteBufferSize);
|
||||||
if (_bytesRead == 0) // EOF
|
if (_bytesRead == 0) // EOF
|
||||||
{
|
{
|
||||||
|
|
@ -319,12 +326,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
_charBufferIndex = 0;
|
_charBufferIndex = 0;
|
||||||
n = _decoder.GetChars(
|
n = _decoder.GetChars(
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
_bytesRead,
|
_bytesRead,
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
_charBuffer.Offset);
|
0);
|
||||||
|
|
||||||
Debug.Assert(n > 0);
|
Debug.Assert(n > 0);
|
||||||
|
|
||||||
_charsRead += n; // Number of chars in StreamReader's buffer.
|
_charsRead += n; // Number of chars in StreamReader's buffer.
|
||||||
|
|
@ -344,8 +351,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer.BlockCopy(
|
Buffer.BlockCopy(
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
(_charBuffer.Offset + _charBufferIndex) * 2,
|
_charBufferIndex * 2,
|
||||||
buffer,
|
buffer,
|
||||||
(index + charsRead) * 2,
|
(index + charsRead) * 2,
|
||||||
n * 2);
|
n * 2);
|
||||||
|
|
@ -375,7 +382,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
_bytesRead = _stream.Read(_byteBuffer.Array, _byteBuffer.Offset, _byteBufferSize);
|
_bytesRead = _stream.Read(_byteBuffer, 0, _byteBufferSize);
|
||||||
if (_bytesRead == 0) // We're at EOF
|
if (_bytesRead == 0) // We're at EOF
|
||||||
{
|
{
|
||||||
return _charsRead;
|
return _charsRead;
|
||||||
|
|
@ -383,11 +390,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
|
|
||||||
_isBlocked = (_bytesRead < _byteBufferSize);
|
_isBlocked = (_bytesRead < _byteBufferSize);
|
||||||
_charsRead += _decoder.GetChars(
|
_charsRead += _decoder.GetChars(
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
_bytesRead,
|
_bytesRead,
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
_charBuffer.Offset + _charsRead);
|
_charsRead);
|
||||||
}
|
}
|
||||||
while (_charsRead == 0);
|
while (_charsRead == 0);
|
||||||
|
|
||||||
|
|
@ -404,8 +411,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
||||||
_bytesRead = await _stream.ReadAsync(
|
_bytesRead = await _stream.ReadAsync(
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
_byteBufferSize).ConfigureAwait(false);
|
_byteBufferSize).ConfigureAwait(false);
|
||||||
if (_bytesRead == 0)
|
if (_bytesRead == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -417,11 +424,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
_isBlocked = (_bytesRead < _byteBufferSize);
|
_isBlocked = (_bytesRead < _byteBufferSize);
|
||||||
|
|
||||||
_charsRead += _decoder.GetChars(
|
_charsRead += _decoder.GetChars(
|
||||||
_byteBuffer.Array,
|
_byteBuffer,
|
||||||
_byteBuffer.Offset,
|
0,
|
||||||
_bytesRead,
|
_bytesRead,
|
||||||
_charBuffer.Array,
|
_charBuffer,
|
||||||
_charBuffer.Offset + _charsRead);
|
_charsRead);
|
||||||
}
|
}
|
||||||
while (_charsRead == 0);
|
while (_charsRead == 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
@ -18,21 +18,21 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly int DefaultBufferSize = 1024; // 1KB - results in a 4KB byte array for UTF8.
|
public static readonly int DefaultBufferSize = 1024; // 1KB - results in a 4KB byte array for UTF8.
|
||||||
|
|
||||||
private readonly IArraySegmentPool<byte> _bytePool;
|
private readonly ArrayPool<byte> _bytePool;
|
||||||
private readonly IArraySegmentPool<char> _charPool;
|
private readonly ArrayPool<char> _charPool;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="MemoryPoolHttpRequestStreamReaderFactory"/>.
|
/// Creates a new <see cref="MemoryPoolHttpRequestStreamReaderFactory"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytePool">
|
/// <param name="bytePool">
|
||||||
/// The <see cref="IArraySegmentPool{byte}"/> for creating <see cref="byte"/> buffers.
|
/// The <see cref="ArrayPool{byte}"/> for creating <see cref="byte"/> buffers.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="charPool">
|
/// <param name="charPool">
|
||||||
/// The <see cref="IArraySegmentPool{char}"/> for creating <see cref="char"/> buffers.
|
/// The <see cref="ArrayPool{char}"/> for creating <see cref="char"/> buffers.
|
||||||
/// </param>
|
/// </param>
|
||||||
public MemoryPoolHttpRequestStreamReaderFactory(
|
public MemoryPoolHttpRequestStreamReaderFactory(
|
||||||
IArraySegmentPool<byte> bytePool,
|
ArrayPool<byte> bytePool,
|
||||||
IArraySegmentPool<char> charPool)
|
ArrayPool<char> charPool)
|
||||||
{
|
{
|
||||||
if (bytePool == null)
|
if (bytePool == null)
|
||||||
{
|
{
|
||||||
|
|
@ -61,34 +61,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
throw new ArgumentNullException(nameof(encoding));
|
throw new ArgumentNullException(nameof(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
LeasedArraySegment<byte> bytes = null;
|
return new HttpRequestStreamReader(stream, encoding, DefaultBufferSize, _bytePool, _charPool);
|
||||||
LeasedArraySegment<char> chars = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bytes = _bytePool.Lease(DefaultBufferSize);
|
|
||||||
|
|
||||||
// We need to compute the minimum size of the char buffer based on the size of the byte buffer,
|
|
||||||
// so that we have enough room to encode the buffer in one shot.
|
|
||||||
var minimumSize = encoding.GetMaxCharCount(DefaultBufferSize);
|
|
||||||
chars = _charPool.Lease(minimumSize);
|
|
||||||
|
|
||||||
return new HttpRequestStreamReader(stream, encoding, DefaultBufferSize, bytes, chars);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (bytes != null)
|
|
||||||
{
|
|
||||||
bytes.Owner.Return(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chars != null)
|
|
||||||
{
|
|
||||||
chars.Owner.Return(chars);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
@ -18,21 +18,21 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly int DefaultBufferSize = 1024; // 1KB - results in a 4KB byte array for UTF8.
|
public static readonly int DefaultBufferSize = 1024; // 1KB - results in a 4KB byte array for UTF8.
|
||||||
|
|
||||||
private readonly IArraySegmentPool<byte> _bytePool;
|
private readonly ArrayPool<byte> _bytePool;
|
||||||
private readonly IArraySegmentPool<char> _charPool;
|
private readonly ArrayPool<char> _charPool;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="MemoryPoolHttpResponseStreamWriterFactory"/>.
|
/// Creates a new <see cref="MemoryPoolHttpResponseStreamWriterFactory"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytePool">
|
/// <param name="bytePool">
|
||||||
/// The <see cref="IArraySegmentPool{byte}"/> for creating <see cref="byte"/> buffers.
|
/// The <see cref="ArrayPool{byte}"/> for creating <see cref="byte"/> buffers.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="charPool">
|
/// <param name="charPool">
|
||||||
/// The <see cref="IArraySegmentPool{char}"/> for creating <see cref="char"/> buffers.
|
/// The <see cref="ArrayPool{char}"/> for creating <see cref="char"/> buffers.
|
||||||
/// </param>
|
/// </param>
|
||||||
public MemoryPoolHttpResponseStreamWriterFactory(
|
public MemoryPoolHttpResponseStreamWriterFactory(
|
||||||
IArraySegmentPool<byte> bytePool,
|
ArrayPool<byte> bytePool,
|
||||||
IArraySegmentPool<char> charPool)
|
ArrayPool<char> charPool)
|
||||||
{
|
{
|
||||||
if (bytePool == null)
|
if (bytePool == null)
|
||||||
{
|
{
|
||||||
|
|
@ -61,34 +61,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||||
throw new ArgumentNullException(nameof(encoding));
|
throw new ArgumentNullException(nameof(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
LeasedArraySegment<byte> bytes = null;
|
return new HttpResponseStreamWriter(stream, encoding, DefaultBufferSize, _bytePool, _charPool);
|
||||||
LeasedArraySegment<char> chars = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
chars = _charPool.Lease(DefaultBufferSize);
|
|
||||||
|
|
||||||
// We need to compute the minimum size of the byte buffer based on the size of the char buffer,
|
|
||||||
// so that we have enough room to encode the buffer in one shot.
|
|
||||||
var minimumSize = encoding.GetMaxByteCount(DefaultBufferSize);
|
|
||||||
bytes = _bytePool.Lease(minimumSize);
|
|
||||||
|
|
||||||
return new HttpResponseStreamWriter(stream, encoding, DefaultBufferSize, bytes, chars);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (bytes != null)
|
|
||||||
{
|
|
||||||
bytes.Owner.Return(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chars != null)
|
|
||||||
{
|
|
||||||
chars.Owner.Return(chars);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -970,22 +970,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_NoConverterExists"), p0, p1);
|
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_NoConverterExists"), p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The byte buffer must have a length of at least '{0}' to be used with a char buffer of size '{1}' and encoding '{2}'. Use '{3}.{4}' to compute the correct size for the byte buffer.
|
|
||||||
/// </summary>
|
|
||||||
internal static string HttpResponseStreamWriter_InvalidBufferSize
|
|
||||||
{
|
|
||||||
get { return GetString("HttpResponseStreamWriter_InvalidBufferSize"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The byte buffer must have a length of at least '{0}' to be used with a char buffer of size '{1}' and encoding '{2}'. Use '{3}.{4}' to compute the correct size for the byte buffer.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatHttpResponseStreamWriter_InvalidBufferSize(object p0, object p1, object p2, object p3, object p4)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("HttpResponseStreamWriter_InvalidBufferSize"), p0, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Path '{0}' was not rooted.
|
/// Path '{0}' was not rooted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1018,22 +1002,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return GetString("UrlNotLocal");
|
return GetString("UrlNotLocal");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The char buffer must have a length of at least '{0}' to be used with a byte buffer of size '{1}' and encoding '{2}'. Use '{3}.{4}' to compute the correct size for the char buffer.
|
|
||||||
/// </summary>
|
|
||||||
internal static string HttpRequestStreamReader_InvalidBufferSize
|
|
||||||
{
|
|
||||||
get { return GetString("HttpRequestStreamReader_InvalidBufferSize"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The char buffer must have a length of at least '{0}' to be used with a byte buffer of size '{1}' and encoding '{2}'. Use '{3}.{4}' to compute the correct size for the char buffer.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatHttpRequestStreamReader_InvalidBufferSize(object p0, object p1, object p2, object p3, object p4)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("HttpRequestStreamReader_InvalidBufferSize"), p0, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The stream must support reading.
|
/// The stream must support reading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -306,9 +306,6 @@
|
||||||
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
|
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
|
||||||
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
|
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="HttpResponseStreamWriter_InvalidBufferSize" xml:space="preserve">
|
|
||||||
<value>The byte buffer must have a length of at least '{0}' to be used with a char buffer of size '{1}' and encoding '{2}'. Use '{3}.{4}' to compute the correct size for the byte buffer.</value>
|
|
||||||
</data>
|
|
||||||
<data name="FileResult_PathNotRooted" xml:space="preserve">
|
<data name="FileResult_PathNotRooted" xml:space="preserve">
|
||||||
<value>Path '{0}' was not rooted.</value>
|
<value>Path '{0}' was not rooted.</value>
|
||||||
<comment>{0} is the path which wasn't rooted</comment>
|
<comment>{0} is the path which wasn't rooted</comment>
|
||||||
|
|
@ -316,9 +313,6 @@
|
||||||
<data name="UrlNotLocal" xml:space="preserve">
|
<data name="UrlNotLocal" xml:space="preserve">
|
||||||
<value>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.</value>
|
<value>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.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="HttpRequestStreamReader_InvalidBufferSize" xml:space="preserve">
|
|
||||||
<value>The char buffer must have a length of at least '{0}' to be used with a byte buffer of size '{1}' and encoding '{2}'. Use '{3}.{4}' to compute the correct size for the char buffer.</value>
|
|
||||||
</data>
|
|
||||||
<data name="HttpRequestStreamReader_StreamNotReadable" xml:space="preserve">
|
<data name="HttpRequestStreamReader_StreamNotReadable" xml:space="preserve">
|
||||||
<value>The stream must support reading.</value>
|
<value>The stream must support reading.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
"type": "build"
|
"type": "build"
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0-*",
|
"Microsoft.Extensions.Logging.Abstractions": "1.0.0-*",
|
||||||
"Microsoft.Extensions.MemoryPool": "1.0.0-*",
|
|
||||||
"Microsoft.Extensions.PropertyActivator.Sources": {
|
"Microsoft.Extensions.PropertyActivator.Sources": {
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"type": "build"
|
"type": "build"
|
||||||
|
|
@ -39,6 +38,7 @@
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"type": "build"
|
"type": "build"
|
||||||
},
|
},
|
||||||
|
"System.Buffers": "4.0.0-*",
|
||||||
"System.Diagnostics.DiagnosticSource": "4.0.0-*"
|
"System.Diagnostics.DiagnosticSource": "4.0.0-*"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@
|
||||||
"type": "build"
|
"type": "build"
|
||||||
},
|
},
|
||||||
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
|
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
|
||||||
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*"
|
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*",
|
||||||
|
"Microsoft.Extensions.MemoryPool": "1.0.0-*"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"net451": {
|
"net451": {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
using Microsoft.Extensions.OptionsModel;
|
using Microsoft.Extensions.OptionsModel;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Buffers;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
|
@ -384,98 +384,21 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
var expectedBytes = encoding.GetBytes("Hello, World!");
|
var expectedBytes = encoding.GetBytes("Hello, World!");
|
||||||
|
|
||||||
using (var bytePool = new DefaultArraySegmentPool<byte>())
|
using (var writer = new HttpResponseStreamWriter(
|
||||||
|
stream,
|
||||||
|
encoding,
|
||||||
|
1024,
|
||||||
|
ArrayPool<byte>.Shared,
|
||||||
|
ArrayPool<char>.Shared))
|
||||||
{
|
{
|
||||||
using (var charPool = new DefaultArraySegmentPool<char>())
|
// Act
|
||||||
{
|
writer.Write("Hello, World!");
|
||||||
LeasedArraySegment<byte> bytes = null;
|
|
||||||
LeasedArraySegment<char> chars = null;
|
|
||||||
HttpResponseStreamWriter writer;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bytes = bytePool.Lease(4096);
|
|
||||||
chars = charPool.Lease(1024);
|
|
||||||
|
|
||||||
writer = new HttpResponseStreamWriter(stream, encoding, 1024, bytes, chars);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (bytes != null)
|
|
||||||
{
|
|
||||||
bytes.Owner.Return(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chars != null)
|
|
||||||
{
|
|
||||||
chars.Owner.Return(chars);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Act
|
|
||||||
using (writer)
|
|
||||||
{
|
|
||||||
writer.Write("Hello, World!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedBytes, stream.ToArray());
|
Assert.Equal(expectedBytes, stream.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This covers the error case where the byte buffer is too small. This is a safeguard, and shouldn't happen
|
|
||||||
// if we're using the writer factory.
|
|
||||||
[Fact]
|
|
||||||
public void HttpResponseStreamWriter_UsingPooledBuffers_SmallByteBuffer()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var encoding = Encoding.UTF8;
|
|
||||||
var stream = new MemoryStream();
|
|
||||||
|
|
||||||
var message =
|
|
||||||
"The byte buffer must have a length of at least '12291' to be used with a char buffer of " +
|
|
||||||
"size '4096' and encoding 'Unicode (UTF-8)'. Use 'System.Text.Encoding.GetMaxByteCount' " +
|
|
||||||
"to compute the correct size for the byte buffer.";
|
|
||||||
|
|
||||||
using (var bytePool = new DefaultArraySegmentPool<byte>())
|
|
||||||
{
|
|
||||||
using (var charPool = new DefaultArraySegmentPool<char>())
|
|
||||||
{
|
|
||||||
LeasedArraySegment<byte> bytes = null;
|
|
||||||
LeasedArraySegment<char> chars = null;
|
|
||||||
HttpResponseStreamWriter writer = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bytes = bytePool.Lease(1024);
|
|
||||||
chars = charPool.Lease(4096);
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
ExceptionAssert.ThrowsArgument(
|
|
||||||
() => writer = new HttpResponseStreamWriter(stream, encoding, chars.Data.Count, bytes, chars),
|
|
||||||
"byteBuffer",
|
|
||||||
message);
|
|
||||||
writer.Dispose();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (bytes != null)
|
|
||||||
{
|
|
||||||
bytes.Owner.Return(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chars != null)
|
|
||||||
{
|
|
||||||
chars.Owner.Return(chars);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestMemoryStream : MemoryStream
|
private class TestMemoryStream : MemoryStream
|
||||||
{
|
{
|
||||||
private int _flushCallCount;
|
private int _flushCallCount;
|
||||||
|
|
|
||||||
|
|
@ -1,50 +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.IO;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Extensions.MemoryPool;
|
|
||||||
using Moq;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
|
||||||
{
|
|
||||||
public class MemoryPoolHttpResponseStreamWriterFactoryTest
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void CreateWriter_BuffersReturned_OnException()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var bytePool = new Mock<IArraySegmentPool<byte>>(MockBehavior.Strict);
|
|
||||||
bytePool
|
|
||||||
.Setup(p => p.Lease(It.IsAny<int>()))
|
|
||||||
.Returns(new LeasedArraySegment<byte>(new ArraySegment<byte>(new byte[4096]), bytePool.Object));
|
|
||||||
bytePool
|
|
||||||
.Setup(p => p.Return(It.IsAny<LeasedArraySegment<byte>>()))
|
|
||||||
.Verifiable();
|
|
||||||
|
|
||||||
var charPool = new Mock<IArraySegmentPool<char>>(MockBehavior.Strict);
|
|
||||||
charPool
|
|
||||||
.Setup(p => p.Lease(MemoryPoolHttpResponseStreamWriterFactory.DefaultBufferSize))
|
|
||||||
.Returns(new LeasedArraySegment<char>(new ArraySegment<char>(new char[4096]), charPool.Object));
|
|
||||||
charPool
|
|
||||||
.Setup(p => p.Return(It.IsAny<LeasedArraySegment<char>>()))
|
|
||||||
.Verifiable();
|
|
||||||
|
|
||||||
var encoding = new Mock<Encoding>();
|
|
||||||
encoding
|
|
||||||
.Setup(e => e.GetEncoder())
|
|
||||||
.Throws(new InvalidOperationException());
|
|
||||||
|
|
||||||
var factory = new MemoryPoolHttpResponseStreamWriterFactory(bytePool.Object, charPool.Object);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
Assert.Throws<InvalidOperationException>(() => factory.CreateWriter(new MemoryStream(), encoding.Object));
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
bytePool.Verify();
|
|
||||||
charPool.Verify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue