Fix #19991 Made TestHost fail when Response Flush is called with AllowSynchronossIO being dissabled (#20059)

This commit is contained in:
Radek Falhar 2020-03-26 17:46:15 +01:00 committed by GitHub
parent d0cc04f957
commit e21fb7e93c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 11 deletions

View File

@ -46,6 +46,11 @@ namespace Microsoft.AspNetCore.TestHost
public override void Flush() public override void Flush()
{ {
if (!_allowSynchronousIO())
{
throw new InvalidOperationException("Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true.");
}
FlushAsync().GetAwaiter().GetResult(); FlushAsync().GetAwaiter().GetResult();
} }

View File

@ -289,7 +289,7 @@ namespace Microsoft.AspNetCore.TestHost
var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context =>
{ {
context.Response.Headers["TestHeader"] = "TestValue"; context.Response.Headers["TestHeader"] = "TestValue";
context.Response.Body.Flush(); await context.Response.Body.FlushAsync();
await block.Task; await block.Task;
await context.Response.WriteAsync("BodyFinished"); await context.Response.WriteAsync("BodyFinished");
})); }));
@ -305,11 +305,11 @@ namespace Microsoft.AspNetCore.TestHost
public async Task ClientDisposalCloses() public async Task ClientDisposalCloses()
{ {
var block = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); var block = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context =>
{ {
context.Response.Headers["TestHeader"] = "TestValue"; context.Response.Headers["TestHeader"] = "TestValue";
context.Response.Body.Flush(); await context.Response.Body.FlushAsync();
return block.Task; await block.Task;
})); }));
var httpClient = new HttpClient(handler); var httpClient = new HttpClient(handler);
HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpResponseMessage response = await httpClient.GetAsync("https://example.com/",
@ -327,11 +327,11 @@ namespace Microsoft.AspNetCore.TestHost
public async Task ClientCancellationAborts() public async Task ClientCancellationAborts()
{ {
var block = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); var block = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context =>
{ {
context.Response.Headers["TestHeader"] = "TestValue"; context.Response.Headers["TestHeader"] = "TestValue";
context.Response.Body.Flush(); await context.Response.Body.FlushAsync();
return block.Task; await block.Task;
})); }));
var httpClient = new HttpClient(handler); var httpClient = new HttpClient(handler);
HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpResponseMessage response = await httpClient.GetAsync("https://example.com/",

View File

@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.TestHost
app.Run(async c => app.Run(async c =>
{ {
c.Response.Headers["TestHeader"] = "TestValue"; c.Response.Headers["TestHeader"] = "TestValue";
c.Response.Body.Flush(); await c.Response.Body.FlushAsync();
await block.Task; await block.Task;
await c.Response.WriteAsync("BodyFinished"); await c.Response.WriteAsync("BodyFinished");
}); });
@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.TestHost
app.Run(async c => app.Run(async c =>
{ {
c.Response.Headers["TestHeader"] = "TestValue"; c.Response.Headers["TestHeader"] = "TestValue";
c.Response.Body.Flush(); await c.Response.Body.FlushAsync();
await block.Task; await block.Task;
await c.Response.WriteAsync("BodyFinished"); await c.Response.WriteAsync("BodyFinished");
}); });
@ -247,7 +247,7 @@ namespace Microsoft.AspNetCore.TestHost
app.Run(async c => app.Run(async c =>
{ {
c.Response.Headers["TestHeader"] = "TestValue"; c.Response.Headers["TestHeader"] = "TestValue";
c.Response.Body.Flush(); await c.Response.Body.FlushAsync();
await block.Task; await block.Task;
await c.Response.WriteAsync("BodyFinished"); await c.Response.WriteAsync("BodyFinished");
}); });

View File

@ -1,6 +1,8 @@
// 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;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -46,6 +48,80 @@ namespace Microsoft.AspNetCore.TestHost.Tests
Assert.Equal(length, bytes.Length); Assert.Equal(length, bytes.Length);
} }
[Fact]
public async Task BodyStream_SyncDisabled_WriteThrows()
{
var contentBytes = new byte[] {32};
using var host = await CreateHost(async httpContext =>
{
await httpContext.Response.StartAsync();
httpContext.Response.Body.Write(contentBytes, 0, contentBytes.Length);
await httpContext.Response.CompleteAsync();
});
var client = host.GetTestServer().CreateClient();
var ex = await Assert.ThrowsAsync<InvalidOperationException>(()=> client.GetAsync("/"));
Assert.Contains("Synchronous operations are disallowed.", ex.Message);
}
[Fact]
public async Task BodyStream_SyncEnabled_WriteSucceeds()
{
var contentBytes = new byte[] {32};
using var host = await CreateHost(async httpContext =>
{
await httpContext.Response.StartAsync();
httpContext.Response.Body.Write(contentBytes, 0, contentBytes.Length);
await httpContext.Response.CompleteAsync();
});
host.GetTestServer().AllowSynchronousIO = true;
var client = host.GetTestServer().CreateClient();
var response = await client.GetAsync("/");
var responseBytes = await response.Content.ReadAsByteArrayAsync();
Assert.Equal(contentBytes, responseBytes);
}
[Fact]
public async Task BodyStream_SyncDisabled_FlushThrows()
{
var contentBytes = new byte[] {32};
using var host = await CreateHost(async httpContext =>
{
await httpContext.Response.StartAsync();
await httpContext.Response.Body.WriteAsync(contentBytes, 0, contentBytes.Length);
httpContext.Response.Body.Flush();
await httpContext.Response.CompleteAsync();
});
var client = host.GetTestServer().CreateClient();
var requestException = await Assert.ThrowsAsync<HttpRequestException>(()=> client.GetAsync("/"));
var ex = (InvalidOperationException) requestException?.InnerException?.InnerException;
Assert.NotNull(ex);
Assert.Contains("Synchronous operations are disallowed.", ex.Message);
}
[Fact]
public async Task BodyStream_SyncEnabled_FlushSucceeds()
{
var contentBytes = new byte[] {32};
using var host = await CreateHost(async httpContext =>
{
await httpContext.Response.StartAsync();
await httpContext.Response.Body.WriteAsync(contentBytes, 0, contentBytes.Length);
httpContext.Response.Body.Flush();
await httpContext.Response.CompleteAsync();
});
host.GetTestServer().AllowSynchronousIO = true;
var client = host.GetTestServer().CreateClient();
var response = await client.GetAsync("/");
var responseBytes = await response.Content.ReadAsByteArrayAsync();
Assert.Equal(contentBytes, responseBytes);
}
private Task<IHost> CreateHost(RequestDelegate appDelegate) private Task<IHost> CreateHost(RequestDelegate appDelegate)
{ {
return new HostBuilder() return new HostBuilder()

View File

@ -598,7 +598,10 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
}); });
}); });
var server = new TestServer(builder); var server = new TestServer(builder)
{
AllowSynchronousIO = true // needed for synchronous flush
};
var client = server.CreateClient(); var client = server.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, ""); var request = new HttpRequestMessage(HttpMethod.Get, "");