Merge remote-tracking branch 'HttpSysServer/rybrande/masterToSrc' into rybrande/Mondo22ToMaster
This commit is contained in:
commit
a84b7d242b
|
|
@ -1,10 +1,8 @@
|
|||
HttpSysServer
|
||||
=================
|
||||
HttpSysServer [Archived]
|
||||
========================
|
||||
|
||||
| AppVeyor | Travis |
|
||||
| ---- | ----
|
||||
| [](https://ci.appveyor.com/project/aspnetci/HttpSysServer/branch/dev) | [](https://travis-ci.org/aspnet/HttpSysServer) |
|
||||
**This GitHub project has been archived.** Ongoing development on this project can be found in <https://github.com/aspnet/AspNetCore>.
|
||||
|
||||
This repo contains a web server for ASP.NET Core based on the Windows [Http Server API](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364510.aspx).
|
||||
|
||||
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
|
||||
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [AspNetCore](https://github.com/aspnet/AspNetCore) repo.
|
||||
|
|
|
|||
|
|
@ -3,21 +3,20 @@
|
|||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Package Versions">
|
||||
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview2-20181011.2</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview3-35457</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
|
||||
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview3-35457</MicrosoftAspNetCoreHostingPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview3-35457</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview3-35457</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<InternalAspNetCoreSdkPackageVersion>3.0.0-alpha1-20181011.3</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>3.0.0-alpha1-10653</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
|
||||
<MicrosoftAspNetCoreHostingPackageVersion>3.0.0-alpha1-10653</MicrosoftAspNetCoreHostingPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>3.0.0-alpha1-10653</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>3.0.0-alpha1-10653</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.3</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview3-27008-03</MicrosoftNETCoreApp22PackageVersion>
|
||||
<MicrosoftNETFrameworkReferenceAssemblies>1.0.0-alpha-004</MicrosoftNETFrameworkReferenceAssemblies>
|
||||
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview3-35457</MicrosoftNetHttpHeadersPackageVersion>
|
||||
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview3-27014-02</MicrosoftNETCoreApp22PackageVersion>
|
||||
<MicrosoftNetHttpHeadersPackageVersion>3.0.0-alpha1-10653</MicrosoftNetHttpHeadersPackageVersion>
|
||||
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
|
||||
<MicrosoftWin32RegistryPackageVersion>4.5.0</MicrosoftWin32RegistryPackageVersion>
|
||||
<MicrosoftWin32RegistryPackageVersion>4.6.0-preview1-26907-04</MicrosoftWin32RegistryPackageVersion>
|
||||
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
||||
<SystemNetHttpWinHttpHandlerPackageVersion>4.5.0</SystemNetHttpWinHttpHandlerPackageVersion>
|
||||
<SystemSecurityPrincipalWindowsPackageVersion>4.5.0</SystemSecurityPrincipalWindowsPackageVersion>
|
||||
<SystemNetHttpWinHttpHandlerPackageVersion>4.6.0-preview1-26907-04</SystemNetHttpWinHttpHandlerPackageVersion>
|
||||
<SystemSecurityPrincipalWindowsPackageVersion>4.6.0-preview1-26907-04</SystemSecurityPrincipalWindowsPackageVersion>
|
||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
||||
<XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
<PropertyGroup>
|
||||
<!-- These properties are use by the automation that updates dependencies.props -->
|
||||
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
|
||||
<LineupPackageVersion>2.2.0-*</LineupPackageVersion>
|
||||
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/roslyn-tools/api/v3/index.json;
|
||||
</RestoreSources>
|
||||
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
|
||||
$(RestoreSources);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
<DeveloperBuildTestTfms>netcoreapp2.2</DeveloperBuildTestTfms>
|
||||
<StandardTestTfms>$(DeveloperBuildTestTfms)</StandardTestTfms>
|
||||
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' ">$(StandardTestTfms)</StandardTestTfms>
|
||||
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(StandardTestTfms);net472</StandardTestTfms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -16,8 +15,4 @@
|
|||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework' ">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="$(MicrosoftNETFrameworkReferenceAssemblies)" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -159,19 +159,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
|
|||
var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#if NET472
|
||||
// HttpClient retries the request because it didn't get a response.
|
||||
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#elif NETCOREAPP2_2
|
||||
#else
|
||||
#error Target framework needs to be updated
|
||||
#endif
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
}
|
||||
}
|
||||
|
|
@ -191,19 +179,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
|
|||
var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#if NET472
|
||||
// HttpClient retries the request because it didn't get a response.
|
||||
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#elif NETCOREAPP2_2
|
||||
#else
|
||||
#error Target framework needs to be updated
|
||||
#endif
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,344 +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.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys.Listener
|
||||
{
|
||||
public class ResponseSendFileTests
|
||||
{
|
||||
private readonly string AbsoluteFilePath;
|
||||
private readonly string RelativeFilePath;
|
||||
private readonly long FileLength;
|
||||
|
||||
public ResponseSendFileTests()
|
||||
{
|
||||
AbsoluteFilePath = Directory.GetFiles(Directory.GetCurrentDirectory()).First();
|
||||
RelativeFilePath = Path.GetFileName(AbsoluteFilePath);
|
||||
FileLength = new FileInfo(AbsoluteFilePath).Length;
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_EmptyFileCountUnspecified_SetsChunkedAndFlushesHeaders()
|
||||
{
|
||||
var emptyFilePath = Path.Combine(Directory.GetCurrentDirectory(), "zz_" + Guid.NewGuid().ToString() + "EmptyTestFile.txt");
|
||||
var emptyFile = File.Create(emptyFilePath, 1024);
|
||||
emptyFile.Dispose();
|
||||
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None);
|
||||
Assert.True(context.Response.HasStarted);
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None);
|
||||
context.Dispose();
|
||||
File.Delete(emptyFilePath);
|
||||
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
Assert.True(response.Headers.TransferEncodingChunked.HasValue);
|
||||
Assert.Equal(10, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_WithActiveCancellationToken_Success()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_WithTimerCancellationToken_Success()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(10));
|
||||
// First write sends headers
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileWriteExceptions_FirstCallWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
server.Options.ThrowWriteExceptions = true;
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#if NET472
|
||||
// .NET HttpClient automatically retries a request if it does not get a response.
|
||||
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#elif NETCOREAPP2_2
|
||||
#else
|
||||
#error Target framework needs to be updated
|
||||
#endif
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_FirstSendWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#if NET472
|
||||
// .NET HttpClient automatically retries a request if it does not get a response.
|
||||
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
#elif NETCOREAPP2_2
|
||||
#else
|
||||
#error Target framework needs to be updated
|
||||
#endif
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileExceptions_SecondSendWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
server.Options.ThrowWriteExceptions = true;
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
cts.Cancel();
|
||||
var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_SecondSendWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
cts.Cancel();
|
||||
var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
context.Dispose();
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeFirstSend_SendThrows()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
server.Options.ThrowWriteExceptions = true;
|
||||
var cts = new CancellationTokenSource();
|
||||
var responseTask = SendRequestAsync(address, cts.Token);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
|
||||
// First write sends headers
|
||||
cts.Cancel();
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
|
||||
|
||||
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
|
||||
await Assert.ThrowsAsync<IOException>(async () =>
|
||||
{
|
||||
// It can take several tries before Send notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
}
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() =>
|
||||
context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None));
|
||||
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_ClientDisconnectsBeforeFirstSend_SendCompletesSilently()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var responseTask = SendRequestAsync(address, cts.Token);
|
||||
|
||||
var context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
// First write sends headers
|
||||
cts.Cancel();
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
|
||||
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
|
||||
// It can take several tries before Send notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
}
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
server.Options.ThrowWriteExceptions = true;
|
||||
RequestContext context;
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
// First write sends headers
|
||||
var sendFileTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
|
||||
var response = await responseTask;
|
||||
response.EnsureSuccessStatusCode();
|
||||
// Drain data from the connection so that SendFileAsync can complete.
|
||||
var bufferTask = response.Content.LoadIntoBufferAsync();
|
||||
|
||||
await sendFileTask;
|
||||
response.Dispose();
|
||||
}
|
||||
|
||||
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
|
||||
await Assert.ThrowsAsync<IOException>(async () =>
|
||||
{
|
||||
// It can take several tries before Write notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
}
|
||||
});
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_ClientDisconnectsBeforeSecondSend_SendCompletesSilently()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
RequestContext context;
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
context = await server.AcceptAsync(Utilities.DefaultTimeout).Before(responseTask);
|
||||
// First write sends headers
|
||||
var sendFileTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
|
||||
var response = await responseTask;
|
||||
response.EnsureSuccessStatusCode();
|
||||
// Drain data from the connection so that SendFileAsync can complete.
|
||||
var bufferTask = response.Content.LoadIntoBufferAsync();
|
||||
|
||||
await sendFileTask;
|
||||
response.Dispose();
|
||||
}
|
||||
|
||||
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
|
||||
// It can take several tries before Write notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
}
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendRequestAsync(string uri, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
return await client.GetAsync(uri, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
ManualResetEvent waitHandle = new ManualResetEvent(false);
|
||||
bool? upgraded = null;
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Assert.Equal(15, await stream.ReadAsync(new byte[15], 0, 15));
|
||||
upgraded = true;
|
||||
waitHandle.Set();
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
using (Stream stream = await SendOpaqueRequestAsync("GET", address))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ContentLengthEqualsLimit_ReadSync_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
httpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
httpContext.Response.ContentLength = read;
|
||||
httpContext.Response.Body.Write(input, 0, read);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World");
|
||||
Assert.Equal("Hello World", response);
|
||||
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ContentLengthEqualsLimit_ReadAsync_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length);
|
||||
httpContext.Response.ContentLength = read;
|
||||
await httpContext.Response.Body.WriteAsync(input, 0, read);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World");
|
||||
Assert.Equal("Hello World", response);
|
||||
|
|
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ContentLengthEqualsLimit_ReadBeginEnd_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
httpContext.Response.ContentLength = read;
|
||||
httpContext.Response.Body.EndWrite(httpContext.Response.Body.BeginWrite(input, 0, read, null, null));
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World");
|
||||
Assert.Equal("Hello World", response);
|
||||
|
|
@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ChunkedEqualsLimit_ReadSync_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
httpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
|
|
@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
httpContext.Response.ContentLength = read;
|
||||
httpContext.Response.Body.Write(input, 0, read);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World", chunked: true);
|
||||
Assert.Equal("Hello World", response);
|
||||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ChunkedEqualsLimit_ReadAsync_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length);
|
||||
httpContext.Response.ContentLength = read;
|
||||
await httpContext.Response.Body.WriteAsync(input, 0, read);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World", chunked: true);
|
||||
Assert.Equal("Hello World", response);
|
||||
|
|
@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ChunkedEqualsLimit_ReadBeginEnd_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -140,7 +140,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
httpContext.Response.ContentLength = read;
|
||||
httpContext.Response.Body.EndWrite(httpContext.Response.Body.BeginWrite(input, 0, read, null, null));
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World", chunked: true);
|
||||
Assert.Equal("Hello World", response);
|
||||
|
|
@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ContentLengthExceedsLimit_ReadSync_ThrowsImmediately()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
httpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
|
|
@ -164,7 +164,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
|
||||
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World");
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ContentLengthExceedsLimit_ReadAsync_ThrowsImmediately()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -187,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
ex = Assert.Throws<IOException>(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); });
|
||||
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World");
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ContentLengthExceedsLimit_ReadBeginEnd_ThrowsImmediately()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
ex = Assert.Throws<IOException>(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null));
|
||||
Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World");
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ChunkedExceedsLimit_ReadSync_ThrowsAtLimit()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
httpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
|
|
@ -234,7 +234,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
|
||||
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World", chunked: true);
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -245,7 +245,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ChunkedExceedsLimit_ReadAsync_ThrowsAtLimit()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -256,7 +256,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
|
||||
ex = await Assert.ThrowsAsync<IOException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
|
||||
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World", chunked: true);
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -267,7 +267,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task ChunkedExceedsLimit_ReadBeginEnd_ThrowsAtLimit()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -280,7 +280,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
ex = Assert.Throws<IOException>(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null)));
|
||||
Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World", chunked: true);
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -292,7 +292,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
var content = new StaggardContent();
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, httpContext =>
|
||||
{
|
||||
httpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
|
|
@ -306,7 +306,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
var ex = Assert.Throws<IOException>(() => httpContext.Request.Body.Read(input, 0, input.Length));
|
||||
Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
string response = await SendRequestAsync(address, content, chunked: true);
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -318,7 +318,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
var content = new StaggardContent();
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -330,7 +330,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
content.Block.Release();
|
||||
var ex = await Assert.ThrowsAsync<IOException>(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length));
|
||||
Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 10))
|
||||
{
|
||||
string response = await SendRequestAsync(address, content, chunked: true);
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
|
@ -341,7 +341,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task AdjustLimitPerRequest_ContentLength_ReadAsync_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -354,7 +354,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Assert.True(feature.IsReadOnly);
|
||||
httpContext.Response.ContentLength = read;
|
||||
await httpContext.Response.Body.WriteAsync(input, 0, read);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World!");
|
||||
Assert.Equal("Hello World!", response);
|
||||
|
|
@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public async Task AdjustLimitPerRequest_Chunked_ReadAsync_Success()
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext =>
|
||||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||
Assert.NotNull(feature);
|
||||
|
|
@ -378,7 +378,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Assert.True(feature.IsReadOnly);
|
||||
httpContext.Response.ContentLength = read;
|
||||
await httpContext.Response.Body.WriteAsync(input, 0, read);
|
||||
}))
|
||||
}, options => options.MaxRequestBodySize = 11))
|
||||
{
|
||||
var response = await SendRequestAsync(address, "Hello World!", chunked: true);
|
||||
Assert.Equal("Hello World!", response);
|
||||
|
|
|
|||
|
|
@ -81,13 +81,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Assert.Equal(0, response.ContentLength);
|
||||
Assert.NotNull(response.Headers["Date"]);
|
||||
Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]);
|
||||
#if NETCOREAPP2_2 // WebHeaderCollection.GetValues() not available in CoreCLR.
|
||||
Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]);
|
||||
#elif NET472
|
||||
Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate"));
|
||||
#else
|
||||
#error Target framework needs to be updated
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,13 +105,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Assert.Equal(0, response.ContentLength);
|
||||
Assert.NotNull(response.Headers["Date"]);
|
||||
Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]);
|
||||
#if NETCOREAPP2_2 // WebHeaderCollection.GetValues() not available in CoreCLR.
|
||||
Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]);
|
||||
#elif NET472
|
||||
Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1"));
|
||||
#else
|
||||
#error Target framework needs to be updated
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using System.Net.Http;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
|
@ -348,11 +349,377 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendRequestAsync(string uri)
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_EmptyFileCountUnspecified_SetsChunkedAndFlushesHeaders()
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
var emptyFilePath = Path.Combine(Directory.GetCurrentDirectory(), "zz_" + Guid.NewGuid().ToString() + "EmptyTestFile.txt");
|
||||
var emptyFile = File.Create(emptyFilePath, 1024);
|
||||
emptyFile.Dispose();
|
||||
try
|
||||
{
|
||||
return await client.GetAsync(uri);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
await httpContext.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None);
|
||||
Assert.True(httpContext.Response.HasStarted);
|
||||
await httpContext.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out var contentLength), "Content-Length");
|
||||
Assert.True(response.Headers.TransferEncodingChunked.HasValue);
|
||||
Assert.Equal(10, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(emptyFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_WithActiveCancellationToken_Success()
|
||||
{
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_WithTimerCancellationToken_Success()
|
||||
{
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(10));
|
||||
// First write sends headers
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileWriteExceptions_FirstCallWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, httpContext =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
var writeTask = httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}, options => options.ThrowWriteExceptions = true))
|
||||
{
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
await testComplete.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_FirstSendWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, httpContext =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
var writeTask = httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}))
|
||||
{
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
await testComplete.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileExceptions_SecondSendWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
cts.Cancel();
|
||||
var writeTask = httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
}, options => options.ThrowWriteExceptions = true))
|
||||
{
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
await testComplete.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_SecondSendWithCanceledCancellationToken_CancelsAndAborts()
|
||||
{
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
cts.Cancel();
|
||||
var writeTask = httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
Assert.True(writeTask.IsCanceled);
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
}))
|
||||
{
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
await testComplete.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeFirstSend_SendThrows()
|
||||
{
|
||||
var requestReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var requestCancelled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var cancellationReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
httpContext.RequestAborted.Register(() => cancellationReceived.SetResult(0));
|
||||
requestReceived.SetResult(0);
|
||||
await requestCancelled.Task;
|
||||
|
||||
try
|
||||
{
|
||||
await Assert.ThrowsAsync<IOException>(async () =>
|
||||
{
|
||||
// It can take several tries before Send notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null);
|
||||
}
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() =>
|
||||
httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null));
|
||||
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
|
||||
}, options => options.ThrowWriteExceptions = true))
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var responseTask = SendRequestAsync(address, cts.Token);
|
||||
await requestReceived.Task.WithTimeout();
|
||||
// First write sends headers
|
||||
cts.Cancel();
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
|
||||
requestCancelled.SetResult(0);
|
||||
|
||||
await testComplete.Task.WithTimeout();
|
||||
await cancellationReceived.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_ClientDisconnectsBeforeFirstSend_SendCompletesSilently()
|
||||
{
|
||||
var requestReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var requestCancelled = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var cancellationReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
httpContext.RequestAborted.Register(() => cancellationReceived.SetResult(0));
|
||||
requestReceived.SetResult(0);
|
||||
await requestCancelled.Task;
|
||||
|
||||
try
|
||||
{
|
||||
// It can take several tries before Send notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null);
|
||||
}
|
||||
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
|
||||
}))
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var responseTask = SendRequestAsync(address, cts.Token);
|
||||
await requestReceived.Task.WithTimeout();
|
||||
// First write sends headers
|
||||
cts.Cancel();
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
|
||||
requestCancelled.SetResult(0);
|
||||
|
||||
await testComplete.Task.WithTimeout();
|
||||
await cancellationReceived.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows()
|
||||
{
|
||||
var firstSendComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var clientDisconnected = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var cancellationReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
httpContext.RequestAborted.Register(() => cancellationReceived.SetResult(0));
|
||||
// First write sends headers
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null);
|
||||
firstSendComplete.SetResult(0);
|
||||
await clientDisconnected.Task;
|
||||
|
||||
try
|
||||
{
|
||||
await Assert.ThrowsAsync<IOException>(async () =>
|
||||
{
|
||||
// It can take several tries before Write notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
}
|
||||
});
|
||||
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
}, options => options.ThrowWriteExceptions = true))
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var response = await client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
|
||||
response.EnsureSuccessStatusCode();
|
||||
// Drain data from the connection so that SendFileAsync can complete.
|
||||
var bufferTask = response.Content.LoadIntoBufferAsync();
|
||||
|
||||
await firstSendComplete.Task.WithTimeout();
|
||||
|
||||
// Abort
|
||||
response.Dispose();
|
||||
}
|
||||
clientDisconnected.SetResult(0);
|
||||
await testComplete.Task.WithTimeout();
|
||||
await cancellationReceived.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ResponseSendFile_ClientDisconnectsBeforeSecondSend_SendCompletesSilently()
|
||||
{
|
||||
var firstSendComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var clientDisconnected = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var cancellationReceived = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using (Utilities.CreateHttpServer(out var address, async httpContext =>
|
||||
{
|
||||
httpContext.RequestAborted.Register(() => cancellationReceived.SetResult(0));
|
||||
// First write sends headers
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null);
|
||||
firstSendComplete.SetResult(0);
|
||||
await clientDisconnected.Task;
|
||||
|
||||
try
|
||||
{
|
||||
// It can take several tries before Write notices the disconnect.
|
||||
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
|
||||
{
|
||||
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
}
|
||||
|
||||
testComplete.SetResult(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
testComplete.SetException(ex);
|
||||
}
|
||||
}))
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var response = await client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
|
||||
response.EnsureSuccessStatusCode();
|
||||
// Drain data from the connection so that SendFileAsync can complete.
|
||||
var bufferTask = response.Content.LoadIntoBufferAsync();
|
||||
|
||||
await firstSendComplete.Task.WithTimeout();
|
||||
|
||||
// Abort
|
||||
response.Dispose();
|
||||
}
|
||||
clientDisconnected.SetResult(0);
|
||||
await testComplete.Task.WithTimeout();
|
||||
await cancellationReceived.Task.WithTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendRequestAsync(string uri, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
using (HttpClient client = new HttpClient() { Timeout = Utilities.DefaultTimeout })
|
||||
{
|
||||
return await client.GetAsync(uri, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,22 +300,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task Server_SetHttp503VebosittHittingThrottle_Success()
|
||||
public async Task Server_SetHttp503VebosityHittingThrottle_Success()
|
||||
{
|
||||
// This is just to get a dynamic port
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { }
|
||||
|
||||
var server = Utilities.CreatePump();
|
||||
server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address));
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
server.Listener.Options.MaxConnections = 3;
|
||||
server.Listener.Options.Http503Verbosity = Http503VerbosityLevel.Limited;
|
||||
|
||||
using (server)
|
||||
using (Utilities.CreateDynamicHost(out var address, options =>
|
||||
{
|
||||
Assert.Null(options.MaxConnections);
|
||||
options.MaxConnections = 3;
|
||||
options.Http503Verbosity = Http503VerbosityLevel.Limited;
|
||||
}, httpContext => Task.FromResult(0)))
|
||||
{
|
||||
await server.StartAsync(new DummyApplication(), CancellationToken.None);
|
||||
|
||||
using (var client1 = await SendHungRequestAsync("GET", address))
|
||||
using (var client2 = await SendHungRequestAsync("GET", address))
|
||||
{
|
||||
|
|
@ -340,31 +333,25 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[ConditionalFact]
|
||||
public void Server_SetConnectionLimitArgumentValidation_Success()
|
||||
{
|
||||
var server = Utilities.CreatePump();
|
||||
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => server.Listener.Options.MaxConnections = -2);
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
server.Listener.Options.MaxConnections = null;
|
||||
server.Listener.Options.MaxConnections = 3;
|
||||
using (var server = Utilities.CreatePump())
|
||||
{
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => server.Listener.Options.MaxConnections = -2);
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
server.Listener.Options.MaxConnections = null;
|
||||
server.Listener.Options.MaxConnections = 3;
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task Server_SetConnectionLimit_Success()
|
||||
{
|
||||
// This is just to get a dynamic port
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { }
|
||||
|
||||
var server = Utilities.CreatePump();
|
||||
server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address));
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
server.Listener.Options.MaxConnections = 3;
|
||||
|
||||
using (server)
|
||||
using (Utilities.CreateDynamicHost(out var address, options =>
|
||||
{
|
||||
Assert.Null(options.MaxConnections);
|
||||
options.MaxConnections = 3;
|
||||
}, httpContext => Task.FromResult(0)))
|
||||
{
|
||||
await server.StartAsync(new DummyApplication(), CancellationToken.None);
|
||||
|
||||
using (var client1 = await SendHungRequestAsync("GET", address))
|
||||
using (var client2 = await SendHungRequestAsync("GET", address))
|
||||
{
|
||||
|
|
@ -384,19 +371,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[ConditionalFact]
|
||||
public async Task Server_SetConnectionLimitChangeAfterStarted_Success()
|
||||
{
|
||||
// This is just to get a dynamic port
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { }
|
||||
|
||||
var server = Utilities.CreatePump();
|
||||
server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address));
|
||||
Assert.Null(server.Listener.Options.MaxConnections);
|
||||
server.Listener.Options.MaxConnections = 3;
|
||||
|
||||
using (server)
|
||||
HttpSysOptions options = null;
|
||||
using (Utilities.CreateDynamicHost(out var address, opt =>
|
||||
{
|
||||
options = opt;
|
||||
Assert.Null(options.MaxConnections);
|
||||
options.MaxConnections = 3;
|
||||
}, httpContext => Task.FromResult(0)))
|
||||
{
|
||||
await server.StartAsync(new DummyApplication(), CancellationToken.None);
|
||||
|
||||
using (var client1 = await SendHungRequestAsync("GET", address))
|
||||
using (var client2 = await SendHungRequestAsync("GET", address))
|
||||
using (var client3 = await SendHungRequestAsync("GET", address))
|
||||
|
|
@ -404,12 +386,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// Maxed out, refuses connection and throws
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
|
||||
server.Listener.Options.MaxConnections = 4;
|
||||
options.MaxConnections = 4;
|
||||
|
||||
string responseText = await SendRequestAsync(address);
|
||||
Assert.Equal(string.Empty, responseText);
|
||||
|
||||
server.Listener.Options.MaxConnections = 2;
|
||||
options.MaxConnections = 2;
|
||||
|
||||
// Maxed out, refuses connection and throws
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
|
|
@ -420,18 +402,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[ConditionalFact]
|
||||
public async Task Server_SetConnectionLimitInfinite_Success()
|
||||
{
|
||||
// This is just to get a dynamic port
|
||||
string address;
|
||||
using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { }
|
||||
|
||||
var server = Utilities.CreatePump();
|
||||
server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address));
|
||||
server.Listener.Options.MaxConnections = -1; // infinite
|
||||
|
||||
using (server)
|
||||
using (Utilities.CreateDynamicHost(out var address, options =>
|
||||
{
|
||||
Assert.Null(options.MaxConnections);
|
||||
options.MaxConnections = -1; // infinite
|
||||
}, httpContext => Task.FromResult(0)))
|
||||
{
|
||||
await server.StartAsync(new DummyApplication(), CancellationToken.None);
|
||||
|
||||
using (var client1 = await SendHungRequestAsync("GET", address))
|
||||
using (var client2 = await SendHungRequestAsync("GET", address))
|
||||
using (var client3 = await SendHungRequestAsync("GET", address))
|
||||
|
|
@ -633,7 +609,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
private async Task<string> SendRequestAsync(string uri)
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
using (HttpClient client = new HttpClient() { Timeout = Utilities.DefaultTimeout } )
|
||||
{
|
||||
return await client.GetStringAsync(uri);
|
||||
}
|
||||
|
|
@ -641,7 +617,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
private async Task<string> SendRequestAsync(string uri, string upload)
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
using (HttpClient client = new HttpClient() { Timeout = Utilities.DefaultTimeout })
|
||||
{
|
||||
HttpResponseMessage response = await client.PostAsync(uri, new StringContent(upload));
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
|
@ -23,6 +24,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private const int MaxPort = 8000;
|
||||
private static int NextPort = BasePort;
|
||||
private static object PortLock = new object();
|
||||
internal static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(15);
|
||||
internal static readonly int WriteRetryLimit = 1000;
|
||||
|
||||
internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate app)
|
||||
{
|
||||
|
|
@ -30,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return CreateDynamicHttpServer(string.Empty, out root, out baseAddress, options => { }, app);
|
||||
}
|
||||
|
||||
internal static IServer CreateHttpServer(out string baseAddress, Action<HttpSysOptions> configureOptions, RequestDelegate app)
|
||||
internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate app, Action<HttpSysOptions> configureOptions)
|
||||
{
|
||||
string root;
|
||||
return CreateDynamicHttpServer(string.Empty, out root, out baseAddress, configureOptions, app);
|
||||
|
|
@ -61,6 +64,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}, app);
|
||||
}
|
||||
|
||||
internal static IWebHost CreateDynamicHost(out string baseAddress, Action<HttpSysOptions> configureOptions, RequestDelegate app)
|
||||
{
|
||||
return CreateDynamicHost(string.Empty, out var root, out baseAddress, configureOptions, app);
|
||||
}
|
||||
|
||||
internal static IWebHost CreateDynamicHost(string basePath, out string root, out string baseAddress, Action<HttpSysOptions> configureOptions, RequestDelegate app)
|
||||
{
|
||||
lock (PortLock)
|
||||
|
|
@ -142,5 +150,38 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
|
||||
return server;
|
||||
}
|
||||
|
||||
internal static Task WithTimeout(this Task task) => task.WithTimeout(DefaultTimeout);
|
||||
|
||||
internal static async Task WithTimeout(this Task task, TimeSpan timeout)
|
||||
{
|
||||
var completedTask = await Task.WhenAny(task, Task.Delay(timeout));
|
||||
|
||||
if (completedTask == task)
|
||||
{
|
||||
await task;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException("The task has timed out.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static Task<T> WithTimeout<T>(this Task<T> task) => task.WithTimeout(DefaultTimeout);
|
||||
|
||||
internal static async Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout)
|
||||
{
|
||||
var completedTask = await Task.WhenAny(task, Task.Delay(timeout));
|
||||
|
||||
if (completedTask == task)
|
||||
{
|
||||
return await task;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException("The task has timed out.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<Project>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>2.2.0</VersionPrefix>
|
||||
<VersionSuffix>rtm</VersionSuffix>
|
||||
<VersionPrefix>3.0.0</VersionPrefix>
|
||||
<VersionSuffix>alpha1</VersionSuffix>
|
||||
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' ">$(VersionPrefix)</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' ">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>
|
||||
<BuildNumber Condition="'$(BuildNumber)' == ''">t000</BuildNumber>
|
||||
|
|
|
|||
Loading…
Reference in New Issue