From 620c673705bb17b33cbc5ff32872d85a5fbf82b9 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 2 Jun 2019 13:53:36 -0700 Subject: [PATCH] Noop on the request body stream in TestServer (#10738) * Noop on the request body stream in TestServer - Disposable should not be observable on the client side if the server disposes the body. This is similar to how Kestrel noops on dispose to avoid common usages like StreamReader disposing the underlying stream. --- .../TestHost/src/AsyncStreamWrapper.cs | 7 ++-- src/Hosting/TestHost/test/TestServerTests.cs | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Hosting/TestHost/src/AsyncStreamWrapper.cs b/src/Hosting/TestHost/src/AsyncStreamWrapper.cs index 4766f8fcf1..705d5a7a0e 100644 --- a/src/Hosting/TestHost/src/AsyncStreamWrapper.cs +++ b/src/Hosting/TestHost/src/AsyncStreamWrapper.cs @@ -116,17 +116,18 @@ namespace Microsoft.AspNetCore.TestHost public override void Close() { - _inner.Close(); + // Don't dispose the inner stream, we don't want to impact the client stream } protected override void Dispose(bool disposing) { - _inner.Dispose(); + // Don't dispose the inner stream, we don't want to impact the client stream } public override ValueTask DisposeAsync() { - return _inner.DisposeAsync(); + // Don't dispose the inner stream, we don't want to impact the client stream + return default; } } } diff --git a/src/Hosting/TestHost/test/TestServerTests.cs b/src/Hosting/TestHost/test/TestServerTests.cs index cc789962c7..2eb474b496 100644 --- a/src/Hosting/TestHost/test/TestServerTests.cs +++ b/src/Hosting/TestHost/test/TestServerTests.cs @@ -3,8 +3,10 @@ using System; using System.Diagnostics; +using System.IO; using System.Net; using System.Net.Http; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; @@ -18,6 +20,7 @@ using Microsoft.Extensions.DiagnosticAdapter; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; +using Moq; using Xunit; namespace Microsoft.AspNetCore.TestHost @@ -191,6 +194,28 @@ namespace Microsoft.AspNetCore.TestHost Assert.Equal("RequestServices:True", result); } + [Fact] + public async Task DispoingTheRequestBodyDoesNotDisposeClientStreams() + { + var builder = new WebHostBuilder().Configure(app => + { + app.Run(async context => + { + using (var sr = new StreamReader(context.Request.Body)) + { + await context.Response.WriteAsync(await sr.ReadToEndAsync()); + } + }); + }); + var server = new TestServer(builder); + + var stream = new ThrowOnDisposeStream(); + stream.Write(Encoding.ASCII.GetBytes("Hello World")); + var response = await server.CreateClient().PostAsync("/", new StreamContent(stream)); + Assert.True(response.IsSuccessStatusCode); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + } + public class CustomContainerStartup { public IServiceProvider Services; @@ -662,6 +687,19 @@ namespace Microsoft.AspNetCore.TestHost Assert.Equal("otherhost:5678", responseBody); } + private class ThrowOnDisposeStream : MemoryStream + { + protected override void Dispose(bool disposing) + { + throw new InvalidOperationException("Dispose should not happen!"); + } + + public override ValueTask DisposeAsync() + { + throw new InvalidOperationException("DisposeAsync should not happen!"); + } + } + public class TestDiagnosticListener { public class OnBeginRequestEventData