Skip to content

Commit 9bfebee

Browse files
committed
thoughts
1 parent 5d97ba7 commit 9bfebee

File tree

9 files changed

+137
-80
lines changed

9 files changed

+137
-80
lines changed

src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ConfigurationSource.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define CS_WINDOWS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/windowsAuthentication"
1414
#define CS_BASIC_AUTHENTICATION_SECTION L"system.webServer/security/authentication/basicAuthentication"
1515
#define CS_ANONYMOUS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/anonymousAuthentication"
16+
#define CS_MAX_REQUEST_BODY_SIZE_SECTION L"system.webServer/security/requestFiltering"
1617

1718
class ConfigurationSource: NonCopyable
1819
{

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
4444
m_fWindowsAuthEnabled(false),
4545
m_fBasicAuthEnabled(false),
4646
m_fAnonymousAuthEnabled(false),
47+
m_dwMaxRequestBodySize(INFINITE),
4748
m_dwStartupTimeLimitInMS(INFINITE),
4849
m_dwShutdownTimeLimitInMS(INFINITE)
4950
{
@@ -71,6 +72,16 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
7172
const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
7273
m_fAnonymousAuthEnabled = anonAuthSection && anonAuthSection->GetBool(CS_ENABLED).value_or(false);
7374

75+
const auto maxRequestBodySize = configurationSource.GetSection(CS_MAX_REQUEST_BODY_SIZE_SECTION);
76+
if (maxRequestBodySize != nullptr)
77+
{
78+
auto requestLimitSection = maxRequestBodySize->GetSection(L"requestLimits").value_or(nullptr);
79+
if (requestLimitSection != nullptr)
80+
{
81+
m_dwMaxRequestBodySize = requestLimitSection->GetLong(L"maxAllowedContentLength").value_or(INFINITE);
82+
}
83+
}
84+
7485
if (pSite != nullptr)
7586
{
7687
m_bindingInformation = BindingInformation::Load(configurationSource, *pSite);

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ class InProcessOptions: NonCopyable
9494
return m_dwShutdownTimeLimitInMS;
9595
}
9696

97+
DWORD
98+
QueryMaxRequestBodySizeLimit() const
99+
{
100+
return m_dwMaxRequestBodySize;
101+
}
102+
97103
const std::map<std::wstring, std::wstring, ignore_case_comparer>&
98104
QueryEnvironmentVariables() const
99105
{
@@ -128,6 +134,7 @@ class InProcessOptions: NonCopyable
128134
bool m_fAnonymousAuthEnabled;
129135
DWORD m_dwStartupTimeLimitInMS;
130136
DWORD m_dwShutdownTimeLimitInMS;
137+
DWORD m_dwMaxRequestBodySize;
131138
std::map<std::wstring, std::wstring, ignore_case_comparer> m_environmentVariables;
132139
std::vector<BindingInformation> m_bindingInformation;
133140

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ struct IISConfigurationData
191191
BOOL fBasicAuthEnabled;
192192
BOOL fAnonymousAuthEnable;
193193
BSTR pwzBindings;
194+
DWORD maxRequestBodySize;
194195
};
195196

196197
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
@@ -216,6 +217,7 @@ http_get_application_properties(
216217

217218
auto const serverAddresses = BindingInformation::Format(pConfiguration.QueryBindings(), pInProcessApplication->QueryApplicationVirtualPath());
218219
pIISCofigurationData->pwzBindings = SysAllocString(serverAddresses.c_str());
220+
pIISCofigurationData->maxRequestBodySize = pInProcessApplication->QueryConfig().QueryMaxRequestBodySizeLimit();
219221
return S_OK;
220222
}
221223

src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs

Lines changed: 74 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -27,79 +27,80 @@ public Startup(IAuthenticationSchemeProvider authSchemeProvider = null)
2727
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
2828
public void Configure(IApplicationBuilder app)
2929
{
30-
app.Run(async (context) =>
31-
{
32-
context.Response.ContentType = "text/plain";
33-
34-
await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine);
35-
await context.Response.WriteAsync(Environment.NewLine);
36-
37-
await context.Response.WriteAsync("Address:" + Environment.NewLine);
38-
await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine);
39-
await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine);
40-
await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine);
41-
await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine);
42-
await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine);
43-
await context.Response.WriteAsync(Environment.NewLine);
44-
45-
await context.Response.WriteAsync("Connection:" + Environment.NewLine);
46-
await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine);
47-
await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine);
48-
await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine);
49-
await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine);
50-
await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine);
51-
await context.Response.WriteAsync(Environment.NewLine);
52-
53-
await context.Response.WriteAsync("User: " + context.User.Identity.Name + Environment.NewLine);
54-
if (_authSchemeProvider != null)
55-
{
56-
var scheme = await _authSchemeProvider.GetSchemeAsync(IISServerDefaults.AuthenticationScheme);
57-
await context.Response.WriteAsync("DisplayName: " + scheme?.DisplayName + Environment.NewLine);
58-
}
59-
60-
await context.Response.WriteAsync(Environment.NewLine);
61-
62-
await context.Response.WriteAsync("Headers:" + Environment.NewLine);
63-
foreach (var header in context.Request.Headers)
64-
{
65-
await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine);
66-
}
67-
await context.Response.WriteAsync(Environment.NewLine);
68-
69-
await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine);
70-
var vars = Environment.GetEnvironmentVariables();
71-
foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key, StringComparer.OrdinalIgnoreCase))
72-
{
73-
var value = vars[key];
74-
await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
75-
}
76-
await context.Response.WriteAsync(Environment.NewLine);
77-
78-
// accessing IIS server variables
79-
await context.Response.WriteAsync("Server Variables:" + Environment.NewLine);
80-
81-
foreach (var varName in IISServerVarNames)
82-
{
83-
await context.Response.WriteAsync(varName + ": " + context.GetIISServerVariable(varName) + Environment.NewLine);
84-
}
85-
86-
await context.Response.WriteAsync(Environment.NewLine);
87-
if (context.Features.Get<IHttpUpgradeFeature>() != null)
88-
{
89-
await context.Response.WriteAsync("Websocket feature is enabled.");
90-
}
91-
else
92-
{
93-
await context.Response.WriteAsync("Websocket feature is disabled.");
94-
}
95-
96-
await context.Response.WriteAsync(Environment.NewLine);
97-
var addresses = context.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
98-
foreach (var key in addresses.Addresses)
99-
{
100-
await context.Response.WriteAsync(key + Environment.NewLine);
101-
}
102-
});
30+
throw new InvalidOperationException("Wow!");
31+
//app.Run(async (context) =>
32+
//{
33+
// context.Response.ContentType = "text/plain";
34+
35+
// await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine);
36+
// await context.Response.WriteAsync(Environment.NewLine);
37+
38+
// await context.Response.WriteAsync("Address:" + Environment.NewLine);
39+
// await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine);
40+
// await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine);
41+
// await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine);
42+
// await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine);
43+
// await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine);
44+
// await context.Response.WriteAsync(Environment.NewLine);
45+
46+
// await context.Response.WriteAsync("Connection:" + Environment.NewLine);
47+
// await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine);
48+
// await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine);
49+
// await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine);
50+
// await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine);
51+
// await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine);
52+
// await context.Response.WriteAsync(Environment.NewLine);
53+
54+
// await context.Response.WriteAsync("User: " + context.User.Identity.Name + Environment.NewLine);
55+
// if (_authSchemeProvider != null)
56+
// {
57+
// var scheme = await _authSchemeProvider.GetSchemeAsync(IISServerDefaults.AuthenticationScheme);
58+
// await context.Response.WriteAsync("DisplayName: " + scheme?.DisplayName + Environment.NewLine);
59+
// }
60+
61+
// await context.Response.WriteAsync(Environment.NewLine);
62+
63+
// await context.Response.WriteAsync("Headers:" + Environment.NewLine);
64+
// foreach (var header in context.Request.Headers)
65+
// {
66+
// await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine);
67+
// }
68+
// await context.Response.WriteAsync(Environment.NewLine);
69+
70+
// await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine);
71+
// var vars = Environment.GetEnvironmentVariables();
72+
// foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key, StringComparer.OrdinalIgnoreCase))
73+
// {
74+
// var value = vars[key];
75+
// await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
76+
// }
77+
// await context.Response.WriteAsync(Environment.NewLine);
78+
79+
// // accessing IIS server variables
80+
// await context.Response.WriteAsync("Server Variables:" + Environment.NewLine);
81+
82+
// foreach (var varName in IISServerVarNames)
83+
// {
84+
// await context.Response.WriteAsync(varName + ": " + context.GetIISServerVariable(varName) + Environment.NewLine);
85+
// }
86+
87+
// await context.Response.WriteAsync(Environment.NewLine);
88+
// if (context.Features.Get<IHttpUpgradeFeature>() != null)
89+
// {
90+
// await context.Response.WriteAsync("Websocket feature is enabled.");
91+
// }
92+
// else
93+
// {
94+
// await context.Response.WriteAsync("Websocket feature is disabled.");
95+
// }
96+
97+
// await context.Response.WriteAsync(Environment.NewLine);
98+
// var addresses = context.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
99+
// foreach (var key in addresses.Addresses)
100+
// {
101+
// await context.Response.WriteAsync(key + Environment.NewLine);
102+
// }
103+
//});
103104
}
104105

105106
private static readonly string[] IISServerVarNames =

src/Servers/IIS/IIS/samples/NativeIISSample/web.config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
66
</handlers>
77
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false" hostingModel="inprocess"/>
8+
<security>
9+
<requestFiltering>
10+
<requestLimits maxAllowedContentLength="123456" maxUrl="4097" />
11+
</requestFiltering>
12+
</security>
813
</system.webServer>
914
</configuration>

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

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

src/Servers/IIS/IIS/src/Core/IISHttpContext.IO.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,25 +98,24 @@ private async Task ReadBody()
9898

9999
var read = await AsyncIO.ReadAsync(memory);
100100

101-
_consumedBytes += read;
102-
103101
// End of body
104102
if (read == 0)
105103
{
106104
break;
107105
}
108106

109-
if (_consumedBytes > MaxRequestBodySize)
110-
{
111-
BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
112-
}
113-
114107
// Read was not canceled because of incoming write or IO stopping
115108
if (read != -1)
116109
{
110+
_consumedBytes += read;
117111
_bodyInputPipe.Writer.Advance(read);
118112
}
119113

114+
if (_consumedBytes > MaxRequestBodySize)
115+
{
116+
BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
117+
}
118+
120119
var result = await _bodyInputPipe.Writer.FlushAsync();
121120

122121
if (result.IsCompleted || result.IsCanceled)

src/Servers/IIS/IIS/test/IIS.Tests/MaxRequestBodySizeTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,36 @@ await connection.Send(
119119
}
120120
}
121121

122+
[ConditionalFact]
123+
public async Task DoesNotRejectRequestWithChunkedExceedingGlobalLimitIfLimitDisabledPerRequest()
124+
{
125+
using (var testServer = await TestServer.Create(
126+
async ctx =>
127+
{
128+
var feature = ctx.Features.Get<IHttpMaxRequestBodySizeFeature>();
129+
Assert.Equal(0, feature.MaxRequestBodySize);
130+
feature.MaxRequestBodySize = null;
131+
132+
await ctx.Request.Body.ReadAsync(new byte[2000]);
133+
134+
}, LoggerFactory, new IISServerOptions { MaxRequestBodySize = 0 }))
135+
{
136+
using (var connection = testServer.CreateConnection())
137+
{
138+
await connection.Send(
139+
"POST / HTTP/1.1",
140+
$"Transfer-Encoding: chunked",
141+
"Host: localhost",
142+
"",
143+
"1",
144+
"a",
145+
"0",
146+
"");
147+
await connection.Receive("HTTP/1.1 200 OK");
148+
}
149+
}
150+
}
151+
122152
[ConditionalFact]
123153
public async Task DoesNotRejectBodylessGetRequestWithZeroMaxRequestBodySize()
124154
{

0 commit comments

Comments
 (0)