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:
parent
3f81caae85
commit
6333040b5a
|
|
@ -19,6 +19,6 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
public bool fAnonymousAuthEnable;
|
public bool fAnonymousAuthEnable;
|
||||||
[MarshalAs(UnmanagedType.BStr)]
|
[MarshalAs(UnmanagedType.BStr)]
|
||||||
public string pwzBindings;
|
public string pwzBindings;
|
||||||
public int maxRequestBodySize;
|
public uint maxRequestBodySize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
|
|
||||||
|
|
@ -42,16 +42,17 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
// https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
|
// https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
|
||||||
private long? _maxRequestBodySize = 30000000;
|
private long? _maxRequestBodySize = 30000000;
|
||||||
|
|
||||||
internal long IisMaxRequestSizeLimit;
|
internal long IisMaxRequestSizeLimit; // Used for verifying if limit set in managed exceeds native
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the maximum allowed size of any request body in bytes.
|
/// 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 limit has no effect on upgraded connections which are always unlimited.
|
||||||
/// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>.
|
/// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Defaults to null (unlimited).
|
/// Defaults to 30,000,000 bytes (~28.6 MB).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public long? MaxRequestBodySize
|
public long? MaxRequestBodySize
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
options => {
|
options => {
|
||||||
options.ServerAddresses = iisConfigData.pwzBindings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
options.ServerAddresses = iisConfigData.pwzBindings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled;
|
options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled;
|
||||||
|
options.MaxRequestBodySize = iisConfigData.maxRequestBodySize;
|
||||||
options.IisMaxRequestSizeLimit = iisConfigData.maxRequestBodySize;
|
options.IisMaxRequestSizeLimit = iisConfigData.maxRequestBodySize;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,46 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess
|
||||||
Assert.True(result.StatusCode == HttpStatusCode.NotFound || result.StatusCode == HttpStatusCode.RequestEntityTooLarge);
|
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]
|
[ConditionalFact]
|
||||||
[RequiresNewHandler]
|
[RequiresNewHandler]
|
||||||
public async Task IISRejectsContentLengthTooLargeByDefault()
|
public async Task IISRejectsContentLengthTooLargeByDefault()
|
||||||
|
|
@ -94,7 +134,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess
|
||||||
});
|
});
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
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);
|
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
|
||||||
|
|
||||||
StopServer();
|
StopServer();
|
||||||
|
|
|
||||||
|
|
@ -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 int _requestsInFlight = 0;
|
||||||
private async Task ReadAndCountRequestBody(HttpContext ctx)
|
private async Task ReadAndCountRequestBody(HttpContext ctx)
|
||||||
{
|
{
|
||||||
|
|
@ -1444,6 +1454,13 @@ namespace TestSite
|
||||||
await Assert.ThrowsAsync<IOException>(() => readTask);
|
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)>()
|
internal static readonly HashSet<(string, StringValues, StringValues)> NullTrailers = new HashSet<(string, StringValues, StringValues)>()
|
||||||
{
|
{
|
||||||
("NullString", (string)null, (string)null),
|
("NullString", (string)null, (string)null),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue