Skip to content

Commit 6333040

Browse files
jkotalikTratcher
andauthored
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>
1 parent 3f81caa commit 6333040

File tree

6 files changed

+64
-7
lines changed

6 files changed

+64
-7
lines changed

src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ internal struct IISConfigurationData
1919
public bool fAnonymousAuthEnable;
2020
[MarshalAs(UnmanagedType.BStr)]
2121
public string pwzBindings;
22-
public int maxRequestBodySize;
22+
public uint maxRequestBodySize;
2323
}
2424
}

src/Servers/IIS/IIS/src/Core/IISHttpContextOfT.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
using System;
55
using System.Buffers;
6-
using System.Text;
7-
using System.Threading;
86
using System.Threading.Tasks;
97
using Microsoft.AspNetCore.Builder;
108
using Microsoft.AspNetCore.Hosting.Server;

src/Servers/IIS/IIS/src/IISServerOptions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,17 @@ public class IISServerOptions
4242
// https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
4343
private long? _maxRequestBodySize = 30000000;
4444

45-
internal long IisMaxRequestSizeLimit;
45+
internal long IisMaxRequestSizeLimit; // Used for verifying if limit set in managed exceeds native
4646

4747
/// <summary>
4848
/// Gets or sets the maximum allowed size of any request body in bytes.
49-
/// When set to null, the maximum request body size is unlimited.
49+
/// When set to null, the maximum request length will not be restricted in ASP.NET Core.
50+
/// However, the IIS maxAllowedContentLength will still restrict content length requests (30,000,000 by default).
5051
/// This limit has no effect on upgraded connections which are always unlimited.
5152
/// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>.
5253
/// </summary>
5354
/// <remarks>
54-
/// Defaults to null (unlimited).
55+
/// Defaults to 30,000,000 bytes (~28.6 MB).
5556
/// </remarks>
5657
public long? MaxRequestBodySize
5758
{

src/Servers/IIS/IIS/src/WebHostBuilderIISExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static IWebHostBuilder UseIIS(this IWebHostBuilder hostBuilder)
4949
options => {
5050
options.ServerAddresses = iisConfigData.pwzBindings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
5151
options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled;
52+
options.MaxRequestBodySize = iisConfigData.maxRequestBodySize;
5253
options.IisMaxRequestSizeLimit = iisConfigData.maxRequestBodySize;
5354
}
5455
);

src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/MaxRequestBodySizeTests.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,46 @@ public async Task SetIISLimitMaxRequestBodySizeE2EWorks()
5454
Assert.True(result.StatusCode == HttpStatusCode.NotFound || result.StatusCode == HttpStatusCode.RequestEntityTooLarge);
5555
}
5656

57+
[ConditionalFact]
58+
[RequiresNewHandler]
59+
public async Task SetIISLimitMaxRequestBodySizeE2EWorksWithLargerLimit()
60+
{
61+
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
62+
deploymentParameters.ServerConfigActionList.Add(
63+
(config, _) => {
64+
config
65+
.RequiredElement("system.webServer")
66+
.GetOrAdd("security")
67+
.GetOrAdd("requestFiltering")
68+
.GetOrAdd("requestLimits", "maxAllowedContentLength", "100000000");
69+
});
70+
var deploymentResult = await DeployAsync(deploymentParameters);
71+
72+
var result = await deploymentResult.HttpClient.PostAsync("/ReadRequestBodyLarger", new StringContent(new string('a', 100000000)));
73+
74+
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
75+
}
76+
77+
[ConditionalFact]
78+
[RequiresNewHandler]
79+
public async Task SetIISLimitMaxRequestBodySizeE2EWorksWithIntMaxValue()
80+
{
81+
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
82+
deploymentParameters.ServerConfigActionList.Add(
83+
(config, _) => {
84+
config
85+
.RequiredElement("system.webServer")
86+
.GetOrAdd("security")
87+
.GetOrAdd("requestFiltering")
88+
.GetOrAdd("requestLimits", "maxAllowedContentLength", "4294967295");
89+
});
90+
var deploymentResult = await DeployAsync(deploymentParameters);
91+
92+
var result = await deploymentResult.HttpClient.PostAsync("/ReadRequestBodyLarger", new StringContent(new string('a', 10000)));
93+
94+
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
95+
}
96+
5797
[ConditionalFact]
5898
[RequiresNewHandler]
5999
public async Task IISRejectsContentLengthTooLargeByDefault()
@@ -94,7 +134,7 @@ public async Task SetIISLimitMaxRequestBodyLogsWarning()
94134
});
95135
var deploymentResult = await DeployAsync(deploymentParameters);
96136

97-
var result = await deploymentResult.HttpClient.PostAsync("/DecreaseRequestLimit", new StringContent("1"));
137+
var result = await deploymentResult.HttpClient.PostAsync("/IncreaseRequestLimit", new StringContent("1"));
98138
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
99139

100140
StopServer();

src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,16 @@ private async Task ReadRequestBody(HttpContext ctx)
478478
}
479479
}
480480

481+
private async Task ReadRequestBodyLarger(HttpContext ctx)
482+
{
483+
var readBuffer = new byte[4096];
484+
var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, 4096);
485+
while (result != 0)
486+
{
487+
result = await ctx.Request.Body.ReadAsync(readBuffer, 0, 4096);
488+
}
489+
}
490+
481491
private int _requestsInFlight = 0;
482492
private async Task ReadAndCountRequestBody(HttpContext ctx)
483493
{
@@ -1444,6 +1454,13 @@ public async Task Reset_CompleteAsyncDuringRequestBody_Resets(HttpContext httpCo
14441454
await Assert.ThrowsAsync<IOException>(() => readTask);
14451455
}
14461456

1457+
public Task IncreaseRequestLimit(HttpContext httpContext)
1458+
{
1459+
var maxRequestBodySizeFeature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
1460+
maxRequestBodySizeFeature.MaxRequestBodySize = 2;
1461+
return Task.CompletedTask;
1462+
}
1463+
14471464
internal static readonly HashSet<(string, StringValues, StringValues)> NullTrailers = new HashSet<(string, StringValues, StringValues)>()
14481465
{
14491466
("NullString", (string)null, (string)null),

0 commit comments

Comments
 (0)