Fix MaxRequestBodySize in IIS (#25096)

* Fix MaxRequestBodySize

* Apply suggestions from code review

Co-authored-by: Chris Ross <Tratcher@Outlook.com>

* Update test

* Keep IIS limit default and update API comment

* Update tests

Co-authored-by: Chris Ross <Tratcher@Outlook.com>
This commit is contained in:
Justin Kotalik 2020-08-25 09:12:58 -07:00 committed by GitHub
parent 3f81caae85
commit 6333040b5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 7 deletions

View File

@ -19,6 +19,6 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
public bool fAnonymousAuthEnable;
[MarshalAs(UnmanagedType.BStr)]
public string pwzBindings;
public int maxRequestBodySize;
public uint maxRequestBodySize;
}
}

View File

@ -3,8 +3,6 @@
using System;
using System.Buffers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;

View File

@ -42,16 +42,17 @@ namespace Microsoft.AspNetCore.Builder
// https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
private long? _maxRequestBodySize = 30000000;
internal long IisMaxRequestSizeLimit;
internal long IisMaxRequestSizeLimit; // Used for verifying if limit set in managed exceeds native
/// <summary>
/// Gets or sets the maximum allowed size of any request body in bytes.
/// When set to null, the maximum request body size is unlimited.
/// When set to null, the maximum request length will not be restricted in ASP.NET Core.
/// However, the IIS maxAllowedContentLength will still restrict content length requests (30,000,000 by default).
/// This limit has no effect on upgraded connections which are always unlimited.
/// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>.
/// </summary>
/// <remarks>
/// Defaults to null (unlimited).
/// Defaults to 30,000,000 bytes (~28.6 MB).
/// </remarks>
public long? MaxRequestBodySize
{

View File

@ -49,6 +49,7 @@ namespace Microsoft.AspNetCore.Hosting
options => {
options.ServerAddresses = iisConfigData.pwzBindings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled;
options.MaxRequestBodySize = iisConfigData.maxRequestBodySize;
options.IisMaxRequestSizeLimit = iisConfigData.maxRequestBodySize;
}
);

View File

@ -54,6 +54,46 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess
Assert.True(result.StatusCode == HttpStatusCode.NotFound || result.StatusCode == HttpStatusCode.RequestEntityTooLarge);
}
[ConditionalFact]
[RequiresNewHandler]
public async Task SetIISLimitMaxRequestBodySizeE2EWorksWithLargerLimit()
{
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
deploymentParameters.ServerConfigActionList.Add(
(config, _) => {
config
.RequiredElement("system.webServer")
.GetOrAdd("security")
.GetOrAdd("requestFiltering")
.GetOrAdd("requestLimits", "maxAllowedContentLength", "100000000");
});
var deploymentResult = await DeployAsync(deploymentParameters);
var result = await deploymentResult.HttpClient.PostAsync("/ReadRequestBodyLarger", new StringContent(new string('a', 100000000)));
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
}
[ConditionalFact]
[RequiresNewHandler]
public async Task SetIISLimitMaxRequestBodySizeE2EWorksWithIntMaxValue()
{
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
deploymentParameters.ServerConfigActionList.Add(
(config, _) => {
config
.RequiredElement("system.webServer")
.GetOrAdd("security")
.GetOrAdd("requestFiltering")
.GetOrAdd("requestLimits", "maxAllowedContentLength", "4294967295");
});
var deploymentResult = await DeployAsync(deploymentParameters);
var result = await deploymentResult.HttpClient.PostAsync("/ReadRequestBodyLarger", new StringContent(new string('a', 10000)));
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
}
[ConditionalFact]
[RequiresNewHandler]
public async Task IISRejectsContentLengthTooLargeByDefault()
@ -94,7 +134,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess
});
var deploymentResult = await DeployAsync(deploymentParameters);
var result = await deploymentResult.HttpClient.PostAsync("/DecreaseRequestLimit", new StringContent("1"));
var result = await deploymentResult.HttpClient.PostAsync("/IncreaseRequestLimit", new StringContent("1"));
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
StopServer();

View File

@ -478,6 +478,16 @@ namespace TestSite
}
}
private async Task ReadRequestBodyLarger(HttpContext ctx)
{
var readBuffer = new byte[4096];
var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, 4096);
while (result != 0)
{
result = await ctx.Request.Body.ReadAsync(readBuffer, 0, 4096);
}
}
private int _requestsInFlight = 0;
private async Task ReadAndCountRequestBody(HttpContext ctx)
{
@ -1444,6 +1454,13 @@ namespace TestSite
await Assert.ThrowsAsync<IOException>(() => readTask);
}
public Task IncreaseRequestLimit(HttpContext httpContext)
{
var maxRequestBodySizeFeature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
maxRequestBodySizeFeature.MaxRequestBodySize = 2;
return Task.CompletedTask;
}
internal static readonly HashSet<(string, StringValues, StringValues)> NullTrailers = new HashSet<(string, StringValues, StringValues)>()
{
("NullString", (string)null, (string)null),