diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.ReadWrite.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.ReadWrite.cs
index ad1cfdb979..89266d9e9a 100644
--- a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.ReadWrite.cs
+++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.ReadWrite.cs
@@ -15,11 +15,25 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
///
/// Reads data from the Input pipe to the user.
///
- ///
+ ///
+ ///
+ ///
///
///
- internal async Task ReadAsync(Memory memory, CancellationToken cancellationToken)
+ public async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
+ // Start a task which will continuously call ReadFromIISAsync and WriteToIISAsync
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+ if (count == 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count));
+ }
+
+ var memory = new Memory(buffer, offset, count);
+
StartProcessingRequestAndResponseBody();
while (true)
@@ -30,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
{
if (!readableBuffer.IsEmpty)
{
- var actual = Math.Min(readableBuffer.Length, memory.Length);
+ var actual = Math.Min(readableBuffer.Length, count);
readableBuffer = readableBuffer.Slice(0, actual);
readableBuffer.CopyTo(memory.Span);
return (int)actual;
@@ -53,7 +67,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
///
///
///
- internal Task WriteAsync(ReadOnlyMemory memory, CancellationToken cancellationToken = default(CancellationToken))
+ public Task WriteAsync(ReadOnlyMemory memory, CancellationToken cancellationToken = default(CancellationToken))
{
// Want to keep exceptions consistent,
@@ -74,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
///
///
///
- internal Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
+ public Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
{
if (!_hasResponseStarted)
{
diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpRequestBody.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpRequestBody.cs
index be5746c0d3..0a51d9fc7a 100644
--- a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpRequestBody.cs
+++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpRequestBody.cs
@@ -39,9 +39,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
public override unsafe Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
- var memory = new Memory(buffer, offset, count);
-
- return _httpContext.ReadAsync(memory, cancellationToken);
+ return _httpContext.ReadAsync(buffer, offset, count, cancellationToken);
}
public override long Seek(long offset, SeekOrigin origin)
diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpResponseBody.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpResponseBody.cs
index f850994a4a..38c8e64c2a 100644
--- a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpResponseBody.cs
+++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpResponseBody.cs
@@ -54,6 +54,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
public override unsafe Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+
return _httpContext.WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken);
}
diff --git a/test/IISIntegration.FunctionalTests/Inprocess/InvalidReadWriteOperationTests.cs b/test/IISIntegration.FunctionalTests/Inprocess/InvalidReadWriteOperationTests.cs
index 3d8b995e75..524bc2931f 100644
--- a/test/IISIntegration.FunctionalTests/Inprocess/InvalidReadWriteOperationTests.cs
+++ b/test/IISIntegration.FunctionalTests/Inprocess/InvalidReadWriteOperationTests.cs
@@ -26,11 +26,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
}
[ConditionalTheory]
+ [InlineData("/NullBuffer")]
[InlineData("/InvalidOffsetSmall")]
[InlineData("/InvalidOffsetLarge")]
[InlineData("/InvalidCountSmall")]
[InlineData("/InvalidCountLarge")]
[InlineData("/InvalidCountWithOffset")]
+ [InlineData("/InvalidCountZeroRead")]
public async Task TestInvalidReadOperations(string operation)
{
var result = await _fixture.Client.GetStringAsync($"/TestInvalidReadOperations{operation}");
@@ -38,6 +40,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
}
[ConditionalTheory]
+ [InlineData("/NullBuffer")]
[InlineData("/InvalidOffsetSmall")]
[InlineData("/InvalidOffsetLarge")]
[InlineData("/InvalidCountSmall")]
diff --git a/test/IISTestSite/Startup.cs b/test/IISTestSite/Startup.cs
index 75f94338d6..91f04a7aec 100644
--- a/test/IISTestSite/Startup.cs
+++ b/test/IISTestSite/Startup.cs
@@ -464,7 +464,22 @@ namespace IISTestSite
app.Run(async context =>
{
var success = false;
- if (context.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
+ if (context.Request.Path.StartsWithSegments("/NullBuffer"))
+ {
+ try
+ {
+ await context.Request.Body.ReadAsync(null, 0, 0);
+ }
+ catch (ArgumentNullException)
+ {
+ success = true;
+ }
+ catch (Exception)
+ {
+ success = true;
+ }
+ }
+ else if (context.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
{
try
{
@@ -519,6 +534,21 @@ namespace IISTestSite
success = true;
}
}
+ else if (context.Request.Path.StartsWithSegments("/InvalidCountZeroRead"))
+ {
+ try
+ {
+ await context.Request.Body.ReadAsync(new byte[1], 0, 0);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ success = true;
+ }
+ catch (Exception)
+ {
+ success = true;
+ }
+ }
await context.Response.WriteAsync(success ? "Success" : "Failure");
});
@@ -528,7 +558,18 @@ namespace IISTestSite
app.Run(async context =>
{
var success = false;
- if (context.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
+ if (context.Request.Path.StartsWithSegments("/NullBuffer"))
+ {
+ try
+ {
+ await context.Response.Body.WriteAsync(null, 0, 0);
+ }
+ catch (ArgumentNullException)
+ {
+ success = true;
+ }
+ }
+ else if (context.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
{
try
{