Skip to content

Commit 7b15720

Browse files
committed
# This is a combination of 2 commits.
# This is the 1st commit message: #539 Implement request body size limit # The commit message #2 will be skipped: # Check exception messages
1 parent c13ba3e commit 7b15720

File tree

9 files changed

+609
-76
lines changed

9 files changed

+609
-76
lines changed

src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ internal class FeatureContext :
2828
IHttpRequestLifetimeFeature,
2929
IHttpAuthenticationFeature,
3030
IHttpUpgradeFeature,
31-
IHttpRequestIdentifierFeature
31+
IHttpRequestIdentifierFeature,
32+
IHttpMaxRequestBodySizeFeature
3233
{
3334
private RequestContext _requestContext;
3435
private IFeatureCollection _features;
@@ -62,11 +63,11 @@ internal class FeatureContext :
6263
private bool _responseStarted;
6364
private bool _completed;
6465

65-
internal FeatureContext(RequestContext requestContext, bool enableResponseCaching)
66+
internal FeatureContext(RequestContext requestContext)
6667
{
6768
_requestContext = requestContext;
6869
_features = new FeatureCollection(new StandardFeatureCollection(this));
69-
_enableResponseCaching = enableResponseCaching;
70+
_enableResponseCaching = _requestContext.Server.Options.EnableResponseCaching;
7071

7172
// Pre-initialize any fields that are not lazy at the lower level.
7273
_requestHeaders = Request.Headers;
@@ -78,7 +79,7 @@ internal FeatureContext(RequestContext requestContext, bool enableResponseCachin
7879
_scheme = Request.Scheme;
7980
_user = _requestContext.User;
8081

81-
_responseStream = new ResponseStream(requestContext.Response.Body, OnStart);
82+
_responseStream = new ResponseStream(requestContext.Response.Body, OnResponseStart);
8283
_responseHeaders = Response.Headers;
8384
}
8485

@@ -405,7 +406,7 @@ int IHttpResponseFeature.StatusCode
405406

406407
async Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation)
407408
{
408-
await OnStart();
409+
await OnResponseStart();
409410
await Response.SendFileAsync(path, offset, length, cancellation);
410411
}
411412

@@ -433,7 +434,7 @@ CancellationToken IHttpRequestLifetimeFeature.RequestAborted
433434

434435
async Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
435436
{
436-
await OnStart();
437+
await OnResponseStart();
437438
return await _requestContext.UpgradeAsync();
438439
}
439440

@@ -463,7 +464,15 @@ string IHttpRequestIdentifierFeature.TraceIdentifier
463464
}
464465
}
465466

466-
internal async Task OnStart()
467+
bool IHttpMaxRequestBodySizeFeature.IsReadOnly => Request.HasRequestBodyStarted;
468+
469+
long? IHttpMaxRequestBodySizeFeature.MaxRequestBodySize
470+
{
471+
get => Request.MaxRequestBodySize;
472+
set => Request.MaxRequestBodySize = value;
473+
}
474+
475+
internal async Task OnResponseStart()
467476
{
468477
if (_responseStarted)
469478
{

src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using Microsoft.AspNetCore.Http.Features;
56

67
namespace Microsoft.AspNetCore.Server.HttpSys
78
{
89
public class HttpSysOptions
910
{
1011
private const long DefaultRequestQueueLength = 1000; // Http.sys default.
1112
internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
13+
// Matches the default maxAllowedContentLength in IIS (~28.6 MB)
14+
// https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
15+
private const long DefaultMaxRequestBodySize = 30000000;
1216

1317
// The native request queue
1418
private long _requestQueueLength = DefaultRequestQueueLength;
1519
private long? _maxConnections;
1620
private RequestQueue _requestQueue;
1721
private UrlGroup _urlGroup;
22+
private long? _maxRequestBodySize = DefaultMaxRequestBodySize;
1823

1924
public HttpSysOptions()
2025
{
@@ -104,6 +109,28 @@ public long RequestQueueLimit
104109
}
105110
}
106111

112+
/// <summary>
113+
/// Gets or sets the maximum allowed size of any request body in bytes.
114+
/// When set to null, the maximum request body size is unlimited.
115+
/// This limit has no effect on upgraded connections which are always unlimited.
116+
/// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>.
117+
/// </summary>
118+
/// <remarks>
119+
/// Defaults to 30,000,000 bytes, which is approximately 28.6MB.
120+
/// </remarks>
121+
public long? MaxRequestBodySize
122+
{
123+
get => _maxRequestBodySize;
124+
set
125+
{
126+
if (value < 0)
127+
{
128+
throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty);
129+
}
130+
_maxRequestBodySize = value;
131+
}
132+
}
133+
107134
internal void Apply(UrlGroup urlGroup, RequestQueue requestQueue)
108135
{
109136
_urlGroup = urlGroup;

src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,11 @@ public MessagePump(IOptions<HttpSysOptions> options, ILoggerFactory loggerFactor
5656

5757
_processRequest = new Action<object>(ProcessRequestAsync);
5858
_maxAccepts = _options.MaxAccepts;
59-
EnableResponseCaching = _options.EnableResponseCaching;
6059
_shutdownSignal = new TaskCompletionSource<object>();
6160
}
6261

6362
internal HttpSysListener Listener { get; }
6463

65-
internal bool EnableResponseCaching { get; set; }
66-
6764
public IFeatureCollection Features { get; }
6865

6966
public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
@@ -199,12 +196,12 @@ private async void ProcessRequestAsync(object requestContextObj)
199196
Interlocked.Increment(ref _outstandingRequests);
200197
try
201198
{
202-
var featureContext = new FeatureContext(requestContext, EnableResponseCaching);
199+
var featureContext = new FeatureContext(requestContext);
203200
context = _application.CreateContext(featureContext.Features);
204201
try
205202
{
206203
await _application.ProcessRequestAsync(context).SupressContext();
207-
await featureContext.OnStart();
204+
await featureContext.OnResponseStart();
208205
requestContext.Dispose();
209206
_application.DisposeContext(context, null);
210207
}

src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ internal sealed class Request
2424

2525
private BoundaryType _contentBoundaryType;
2626
private long? _contentLength;
27-
private Stream _nativeStream;
27+
private RequestStream _nativeStream;
2828

2929
private SocketAddress _localEndPoint;
3030
private SocketAddress _remoteEndPoint;
@@ -143,15 +143,32 @@ public long? ContentLength
143143

144144
public string Method { get; }
145145

146-
public Stream Body
146+
public Stream Body => EnsureRequestStream() ?? Stream.Null;
147+
148+
private RequestStream EnsureRequestStream()
147149
{
148-
get
150+
if (_nativeStream == null && HasEntityBody)
151+
{
152+
_nativeStream = new RequestStream(RequestContext)
153+
{
154+
MaxSize = RequestContext.Server.Options.MaxRequestBodySize
155+
};
156+
}
157+
return _nativeStream;
158+
}
159+
160+
public bool HasRequestBodyStarted => _nativeStream?.HasStarted ?? false;
161+
162+
public long? MaxRequestBodySize
163+
{
164+
get => EnsureRequestStream()?.MaxSize;
165+
set
149166
{
150-
if (_nativeStream == null)
167+
EnsureRequestStream();
168+
if (_nativeStream != null)
151169
{
152-
_nativeStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null;
170+
_nativeStream.MaxSize = value;
153171
}
154-
return _nativeStream;
155172
}
156173
}
157174

@@ -319,10 +336,11 @@ private void CheckDisposed()
319336

320337
internal void SwitchToOpaqueMode()
321338
{
322-
if (_nativeStream == null || _nativeStream == Stream.Null)
339+
if (_nativeStream == null)
323340
{
324341
_nativeStream = new RequestStream(RequestContext);
325342
}
343+
_nativeStream.SwitchToOpaqueMode();
326344
}
327345
}
328346
}

0 commit comments

Comments
 (0)