Don't allocate the FormFeature eagerly (#6511)
- Expose FormOptions on DefaultHttpContext - Use those options on DefaultHttpContext when the FormFeature is initialized
This commit is contained in:
parent
b6bdffe247
commit
ea344bf726
|
|
@ -62,6 +62,8 @@ namespace Microsoft.AspNetCore.Http
|
|||
_websockets?.Uninitialize();
|
||||
}
|
||||
|
||||
public FormOptions FormOptions { get; set; }
|
||||
|
||||
private IItemsFeature ItemsFeature =>
|
||||
_features.Fetch(ref _features.Cache.Items, _newItemsFeature);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
{
|
||||
public class FormFeature : IFormFeature
|
||||
{
|
||||
private static readonly FormOptions DefaultFormOptions = new FormOptions();
|
||||
|
||||
private readonly HttpRequest _request;
|
||||
private readonly FormOptions _options;
|
||||
private Task<IFormCollection> _parsedFormTask;
|
||||
|
|
@ -32,7 +30,7 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
Form = form;
|
||||
}
|
||||
public FormFeature(HttpRequest request)
|
||||
: this(request, DefaultFormOptions)
|
||||
: this(request, FormOptions.Default)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
|
|
@ -8,6 +8,8 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
{
|
||||
public class FormOptions
|
||||
{
|
||||
internal static readonly FormOptions Default = new FormOptions();
|
||||
|
||||
public const int DefaultMemoryBufferThreshold = 1024 * 64;
|
||||
public const int DefaultBufferBodyLengthLimit = 1024 * 1024 * 128;
|
||||
public const int DefaultMultipartBoundaryLengthLimit = 128;
|
||||
|
|
|
|||
|
|
@ -42,13 +42,12 @@ namespace Microsoft.AspNetCore.Http
|
|||
_httpContextAccessor.HttpContext = httpContext;
|
||||
}
|
||||
|
||||
var formFeature = new FormFeature(httpContext.Request, _formOptions);
|
||||
featureCollection.Set<IFormFeature>(formFeature);
|
||||
httpContext.FormOptions = _formOptions;
|
||||
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
private static HttpContext CreateHttpContext(IFeatureCollection featureCollection)
|
||||
private static DefaultHttpContext CreateHttpContext(IFeatureCollection featureCollection)
|
||||
{
|
||||
if (featureCollection is IHttpContextContainer container)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ namespace Microsoft.AspNetCore.Http
|
|||
{
|
||||
public interface IHttpContextContainer
|
||||
{
|
||||
HttpContext HttpContext { get; }
|
||||
DefaultHttpContext HttpContext { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Http.Internal
|
|||
// Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
|
||||
private readonly static Func<IFeatureCollection, IHttpRequestFeature> _nullRequestFeature = f => null;
|
||||
private readonly static Func<IFeatureCollection, IQueryFeature> _newQueryFeature = f => new QueryFeature(f);
|
||||
private readonly static Func<HttpRequest, IFormFeature> _newFormFeature = r => new FormFeature(r);
|
||||
private readonly static Func<DefaultHttpRequest, IFormFeature> _newFormFeature = r => new FormFeature(r, r._context.FormOptions ?? FormOptions.Default);
|
||||
private readonly static Func<IFeatureCollection, IRequestCookiesFeature> _newRequestCookiesFeature = f => new RequestCookiesFeature(f);
|
||||
private readonly static Func<IFeatureCollection, IRouteValuesFeature> _newRouteValuesFeature = f => new RouteValuesFeature();
|
||||
private readonly static Func<HttpContext, IRequestBodyPipeFeature> _newRequestBodyPipeFeature = context => new RequestBodyPipeFeature(context);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,24 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
Assert.Same(FormCollection.Empty, formCollection);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormFeatureReadsOptionsFromDefaultHttpContext()
|
||||
{
|
||||
var context = new DefaultHttpContext();
|
||||
context.Request.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
|
||||
context.FormOptions = new FormOptions
|
||||
{
|
||||
ValueCountLimit = 1
|
||||
};
|
||||
|
||||
var formContent = Encoding.UTF8.GetBytes("foo=bar&baz=2");
|
||||
context.Request.Body = new NonSeekableReadStream(formContent);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
|
||||
|
||||
Assert.Equal("Form value count limit 1 exceeded.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
|
|
@ -391,7 +409,7 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 });
|
||||
context.Features.Set<IFormFeature>(formFeature);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<InvalidDataException> (() => context.Request.ReadFormAsync());
|
||||
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
|
||||
Assert.Equal("Form value count limit 2 exceeded.", exception.Message);
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +434,7 @@ namespace Microsoft.AspNetCore.Http.Features
|
|||
IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 });
|
||||
context.Features.Set<IFormFeature>(formFeature);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<InvalidDataException> (() => context.Request.ReadFormAsync());
|
||||
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
|
||||
Assert.Equal("Form value count limit 2 exceeded.", exception.Message);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
|
||||
protected HttpResponseHeaders HttpResponseHeaders { get; } = new HttpResponseHeaders();
|
||||
|
||||
HttpContext IHttpContextContainer.HttpContext
|
||||
DefaultHttpContext IHttpContextContainer.HttpContext
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue