Changed RequestSizeLimitAttribute to create an authorization filter rather than a resource filter.
[Fixes #6777] RequestSizeLimit is ignored
This commit is contained in:
parent
de38922601
commit
06f6de6c11
|
|
@ -199,10 +199,10 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
ServiceDescriptor.Singleton<IFilterProvider, DefaultFilterProvider>());
|
ServiceDescriptor.Singleton<IFilterProvider, DefaultFilterProvider>());
|
||||||
|
|
||||||
//
|
//
|
||||||
// Resource Filters
|
// RequestSizeLimit filters
|
||||||
//
|
//
|
||||||
services.TryAddTransient<RequestSizeLimitResourceFilter>();
|
services.TryAddTransient<RequestSizeLimitFilter>();
|
||||||
services.TryAddTransient<DisableRequestSizeLimitResourceFilter>();
|
services.TryAddTransient<DisableRequestSizeLimitFilter>();
|
||||||
|
|
||||||
//
|
//
|
||||||
// ModelBinding, Validation
|
// ModelBinding, Validation
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,23 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
public class DisableRequestSizeLimitAttribute : Attribute, IFilterFactory, IOrderedFilter
|
public class DisableRequestSizeLimitAttribute : Attribute, IFilterFactory, IOrderedFilter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
public int Order { get; set; }
|
/// Gets the order value for determining the order of execution of filters. Filters execute in
|
||||||
|
/// ascending numeric value of the <see cref="Order"/> property.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Filters are executed in an ordering determined by an ascending sort of the <see cref="Order"/> property.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The default Order for this attribute is 900 because it must run before ValidateAntiForgeryTokenAttribute and
|
||||||
|
/// after any filter which does authentication or login in order to allow them to behave as expected (ie Unauthenticated or Redirect instead of 400).
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Look at <see cref="IOrderedFilter.Order"/> for more detailed info.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public int Order { get; set; } = 900;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsReusable => true;
|
public bool IsReusable => true;
|
||||||
|
|
@ -23,7 +38,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
var filter = serviceProvider.GetRequiredService<DisableRequestSizeLimitResourceFilter>();
|
var filter = serviceProvider.GetRequiredService<DisableRequestSizeLimitFilter>();
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,34 +14,26 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
/// A filter that sets <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
/// A filter that sets <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
||||||
/// to <c>null</c>.
|
/// to <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DisableRequestSizeLimitResourceFilter : IResourceFilter, IRequestSizePolicy
|
public class DisableRequestSizeLimitFilter : IAuthorizationFilter, IRequestSizePolicy
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="DisableRequestSizeLimitResourceFilter"/>.
|
/// Creates a new instance of <see cref="DisableRequestSizeLimitFilter"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DisableRequestSizeLimitResourceFilter(ILoggerFactory loggerFactory)
|
public DisableRequestSizeLimitFilter(ILoggerFactory loggerFactory)
|
||||||
{
|
|
||||||
_logger = loggerFactory.CreateLogger<DisableRequestSizeLimitResourceFilter>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Order { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
|
||||||
{
|
{
|
||||||
|
_logger = loggerFactory.CreateLogger<DisableRequestSizeLimitFilter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
/// Sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
||||||
/// to <c>null</c>.
|
/// to <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The <see cref="ResourceExecutingContext"/>.</param>
|
/// <param name="context">The <see cref="AuthorizationFilterContext"/>.</param>
|
||||||
/// <remarks>If <see cref="IHttpMaxRequestBodySizeFeature"/> is not enabled or is read-only,
|
/// <remarks>If <see cref="IHttpMaxRequestBodySizeFeature"/> is not enabled or is read-only,
|
||||||
/// the <see cref="DisableRequestSizeLimitAttribute"/> is not applied.</remarks>
|
/// the <see cref="DisableRequestSizeLimitAttribute"/> is not applied.</remarks>
|
||||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
public void OnAuthorization(AuthorizationFilterContext context)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
|
|
@ -14,32 +14,27 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
/// A filter that sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
/// A filter that sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
||||||
/// to the specified <see cref="Bytes"/>.
|
/// to the specified <see cref="Bytes"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RequestSizeLimitResourceFilter : IResourceFilter, IRequestSizePolicy
|
public class RequestSizeLimitFilter : IAuthorizationFilter, IRequestSizePolicy
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="RequestSizeLimitResourceFilter"/>.
|
/// Creates a new instance of <see cref="RequestSizeLimitFilter"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RequestSizeLimitResourceFilter(ILoggerFactory loggerFactory)
|
public RequestSizeLimitFilter(ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory.CreateLogger<RequestSizeLimitResourceFilter>();
|
_logger = loggerFactory.CreateLogger<RequestSizeLimitFilter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Bytes { get; set; }
|
public long Bytes { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/> to <see cref="Bytes"/>.
|
/// Sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/> to <see cref="Bytes"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The <see cref="ResourceExecutingContext"/>.</param>
|
/// <param name="context">The <see cref="AuthorizationFilterContext"/>.</param>
|
||||||
/// <remarks>If <see cref="IHttpMaxRequestBodySizeFeature"/> is not enabled or is read-only,
|
/// <remarks>If <see cref="IHttpMaxRequestBodySizeFeature"/> is not enabled or is read-only,
|
||||||
/// the <see cref="RequestSizeLimitAttribute"/> is not applied.</remarks>
|
/// the <see cref="RequestSizeLimitAttribute"/> is not applied.</remarks>
|
||||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
public void OnAuthorization(AuthorizationFilterContext context)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
|
|
@ -25,8 +25,23 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
_bytes = bytes;
|
_bytes = bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
public int Order { get; set; }
|
/// Gets the order value for determining the order of execution of filters. Filters execute in
|
||||||
|
/// ascending numeric value of the <see cref="Order"/> property.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Filters are executed in an ordering determined by an ascending sort of the <see cref="Order"/> property.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The default Order for this attribute is 900 because it must run before ValidateAntiForgeryTokenAttribute and
|
||||||
|
/// after any filter which does authentication or login in order to allow them to behave as expected (ie Unauthenticated or Redirect instead of 400).
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Look at <see cref="IOrderedFilter.Order"/> for more detailed info.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public int Order { get; set; } = 900;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsReusable => true;
|
public bool IsReusable => true;
|
||||||
|
|
@ -34,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
var filter = serviceProvider.GetRequiredService<RequestSizeLimitResourceFilter>();
|
var filter = serviceProvider.GetRequiredService<RequestSizeLimitFilter>();
|
||||||
filter.Bytes = _bytes;
|
filter.Bytes = _bytes;
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
|
@ -14,20 +12,20 @@ using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Internal
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
public class DisableRequestSizeLimitResourceFilterTest
|
public class DisableRequestSizeLimitFilterTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void SetsMaxRequestBodySizeToNull()
|
public void SetsMaxRequestBodySizeToNull()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(NullLoggerFactory.Instance);
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
disableRequestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(httpMaxRequestBodySize.MaxRequestBodySize);
|
Assert.Null(httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
|
@ -37,16 +35,17 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
public void SkipsWhenOverridden()
|
public void SkipsWhenOverridden()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(NullLoggerFactory.Instance);
|
||||||
var disableRequestSizeLimitResourceFilterFinal = new DisableRequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
var disableRequestSizeLimitResourceFilterFinal = new DisableRequestSizeLimitFilter(NullLoggerFactory.Instance);
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter, disableRequestSizeLimitResourceFilterFinal });
|
var authorizationFilterContext = CreateauthorizationFilterContext(
|
||||||
|
new IFilterMetadata[] { disableRequestSizeLimitResourceFilter, disableRequestSizeLimitResourceFilterFinal });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
disableRequestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
disableRequestSizeLimitResourceFilterFinal.OnResourceExecuting(resourceExecutingContext);
|
disableRequestSizeLimitResourceFilterFinal.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(httpMaxRequestBodySize.MaxRequestBodySize);
|
Assert.Null(httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
|
@ -60,11 +59,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(loggerFactory);
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(loggerFactory);
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
disableRequestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var write = Assert.Single(sink.Writes);
|
var write = Assert.Single(sink.Writes);
|
||||||
|
|
@ -79,15 +78,15 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(loggerFactory);
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(loggerFactory);
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
httpMaxRequestBodySize.IsReadOnly = true;
|
httpMaxRequestBodySize.IsReadOnly = true;
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
disableRequestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var write = Assert.Single(sink.Writes);
|
var write = Assert.Single(sink.Writes);
|
||||||
|
|
@ -101,26 +100,23 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(loggerFactory);
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(loggerFactory);
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
disableRequestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var write = Assert.Single(sink.Writes);
|
var write = Assert.Single(sink.Writes);
|
||||||
Assert.Equal($"The request body size limit has been disabled.", write.State.ToString());
|
Assert.Equal($"The request body size limit has been disabled.", write.State.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResourceExecutingContext CreateResourceExecutingContext(IFilterMetadata[] filters)
|
private static AuthorizationFilterContext CreateauthorizationFilterContext(IFilterMetadata[] filters)
|
||||||
{
|
{
|
||||||
return new ResourceExecutingContext(
|
return new AuthorizationFilterContext(CreateActionContext(), filters);
|
||||||
CreateActionContext(),
|
|
||||||
filters,
|
|
||||||
new List<IValueProviderFactory>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext CreateActionContext()
|
private static ActionContext CreateActionContext()
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
|
@ -14,21 +12,21 @@ using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Internal
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
public class RequestSizeLimitResourceFilterTest
|
public class RequestSizeLimitFilterTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void SetsMaxRequestBodySize()
|
public void SetsMaxRequestBodySize()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(NullLoggerFactory.Instance);
|
||||||
requestSizeLimitResourceFilter.Bytes = 12345;
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
requestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(12345, httpMaxRequestBodySize.MaxRequestBodySize);
|
Assert.Equal(12345, httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
|
@ -38,18 +36,19 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
public void SkipsWhenOverridden()
|
public void SkipsWhenOverridden()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(NullLoggerFactory.Instance);
|
||||||
requestSizeLimitResourceFilter.Bytes = 12345;
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
var requestSizeLimitResourceFilterFinal = new RequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
var requestSizeLimitResourceFilterFinal = new RequestSizeLimitFilter(NullLoggerFactory.Instance);
|
||||||
requestSizeLimitResourceFilterFinal.Bytes = 0;
|
requestSizeLimitResourceFilterFinal.Bytes = 0;
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter, requestSizeLimitResourceFilterFinal });
|
var authorizationFilterContext = CreateauthorizationFilterContext(
|
||||||
|
new IFilterMetadata[] { requestSizeLimitResourceFilter, requestSizeLimitResourceFilterFinal });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
requestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
requestSizeLimitResourceFilterFinal.OnResourceExecuting(resourceExecutingContext);
|
requestSizeLimitResourceFilterFinal.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(0, httpMaxRequestBodySize.MaxRequestBodySize);
|
Assert.Equal(0, httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
|
@ -63,12 +62,12 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(loggerFactory);
|
var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(loggerFactory);
|
||||||
requestSizeLimitResourceFilter.Bytes = 12345;
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
requestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var write = Assert.Single(sink.Writes);
|
var write = Assert.Single(sink.Writes);
|
||||||
|
|
@ -83,16 +82,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(loggerFactory);
|
var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(loggerFactory);
|
||||||
requestSizeLimitResourceFilter.Bytes = 12345;
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
httpMaxRequestBodySize.IsReadOnly = true;
|
httpMaxRequestBodySize.IsReadOnly = true;
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
requestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var write = Assert.Single(sink.Writes);
|
var write = Assert.Single(sink.Writes);
|
||||||
|
|
@ -106,27 +105,24 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
var sink = new TestSink();
|
var sink = new TestSink();
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(loggerFactory);
|
var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(loggerFactory);
|
||||||
requestSizeLimitResourceFilter.Bytes = 12345;
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
authorizationFilterContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
requestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var write = Assert.Single(sink.Writes);
|
var write = Assert.Single(sink.Writes);
|
||||||
Assert.Equal($"The maximum request body size has been set to 12345.", write.State.ToString());
|
Assert.Equal($"The maximum request body size has been set to 12345.", write.State.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResourceExecutingContext CreateResourceExecutingContext(IFilterMetadata[] filters)
|
private static AuthorizationFilterContext CreateauthorizationFilterContext(IFilterMetadata[] filters)
|
||||||
{
|
{
|
||||||
return new ResourceExecutingContext(
|
return new AuthorizationFilterContext(CreateActionContext(), filters);
|
||||||
CreateActionContext(),
|
|
||||||
filters,
|
|
||||||
new List<IValueProviderFactory>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext CreateActionContext()
|
private static ActionContext CreateActionContext()
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
// 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
|
{
|
||||||
|
public class RequestSizeLimitTest : IClassFixture<MvcTestFixture<BasicWebSite.StartupRequestLimitSize>>
|
||||||
|
{
|
||||||
|
// Some tests require comparing the actual response body against an expected response baseline
|
||||||
|
// so they require a reference to the assembly on which the resources are located, in order to
|
||||||
|
// make the tests less verbose, we get a reference to the assembly with the resources and we
|
||||||
|
// use it on all the rest of the tests.
|
||||||
|
private static readonly Assembly _resourcesAssembly = typeof(BasicTests).GetTypeInfo().Assembly;
|
||||||
|
|
||||||
|
public RequestSizeLimitTest(MvcTestFixture<BasicWebSite.StartupRequestLimitSize> fixture)
|
||||||
|
{
|
||||||
|
Client = fixture.Client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestSizeLimitCheckHappens_BeforeAntiforgeryTokenValidation()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new HttpRequestMessage();
|
||||||
|
var kvps = new List<KeyValuePair<string, string>>();
|
||||||
|
kvps.Add(new KeyValuePair<string, string>("SampleString", new string('p', 1024)));
|
||||||
|
kvps.Add(new KeyValuePair<string, string>("RequestVerificationToken", "invalid-data"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.PostAsync(
|
||||||
|
"RequestSizeLimit/RequestSizeLimitCheckBeforeAntiforgeryValidation",
|
||||||
|
new FormUrlEncodedContent(kvps));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
var result = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Contains(
|
||||||
|
"InvalidOperationException: Request content size is greater than the limit size",
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AntiforgeryTokenValidationHappens_AfterRequestSizeLimitCheck()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new HttpRequestMessage();
|
||||||
|
var kvps = new List<KeyValuePair<string, string>>();
|
||||||
|
kvps.Add(new KeyValuePair<string, string>("SampleString", "string"));
|
||||||
|
kvps.Add(new KeyValuePair<string, string>("RequestVerificationToken", "invalid-data"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.PostAsync(
|
||||||
|
"RequestSizeLimit/RequestSizeLimitCheckBeforeAntiforgeryValidation",
|
||||||
|
new FormUrlEncodedContent(kvps));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DisableRequestSizeLimitOnAction_OverridesControllerLevelSettings()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = $"{{\"sampleInt\":10,\"sampleString\":\"{new string('p', 1024)}\"}}";
|
||||||
|
var request = new HttpRequestMessage();
|
||||||
|
request.Method = HttpMethod.Post;
|
||||||
|
request.Content = new StringContent(expected, Encoding.UTF8, "text/json");
|
||||||
|
request.RequestUri = new Uri("http://localhost/RequestSizeLimit/DisableRequestSizeLimit");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.SendAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
var actual = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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;
|
||||||
|
using BasicWebSite.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace BasicWebSite.Controllers
|
||||||
|
{
|
||||||
|
[RequestSizeLimit(500)]
|
||||||
|
public class RequestSizeLimitController : Controller
|
||||||
|
{
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public IActionResult RequestSizeLimitCheckBeforeAntiforgeryValidation(Product product)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(product);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[DisableRequestSizeLimit]
|
||||||
|
public IActionResult DisableRequestSizeLimit([FromBody] Product product)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
return Json(product);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
// 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;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace BasicWebSite
|
||||||
|
{
|
||||||
|
public class StartupRequestLimitSize
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddMvc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
|
||||||
|
app.Use((httpContext, next) =>
|
||||||
|
{
|
||||||
|
var testHttpMaxRequestBodySizeFeature = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
httpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(
|
||||||
|
testHttpMaxRequestBodySizeFeature);
|
||||||
|
|
||||||
|
httpContext.Request.Body = new RequestBodySizeCheckingStream(
|
||||||
|
httpContext.Request.Body,
|
||||||
|
testHttpMaxRequestBodySizeFeature);
|
||||||
|
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.UseMvcWithDefaultRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RequestBodySizeCheckingStream : Stream
|
||||||
|
{
|
||||||
|
private readonly Stream _innerStream;
|
||||||
|
private readonly IHttpMaxRequestBodySizeFeature _maxRequestBodySizeFeature;
|
||||||
|
|
||||||
|
public RequestBodySizeCheckingStream(
|
||||||
|
Stream innerStream,
|
||||||
|
IHttpMaxRequestBodySizeFeature maxRequestBodySizeFeature)
|
||||||
|
{
|
||||||
|
_innerStream = innerStream;
|
||||||
|
_maxRequestBodySizeFeature = maxRequestBodySizeFeature;
|
||||||
|
}
|
||||||
|
public override bool CanRead => _innerStream.CanRead;
|
||||||
|
|
||||||
|
public override bool CanSeek => _innerStream.CanSeek;
|
||||||
|
|
||||||
|
public override bool CanWrite => _innerStream.CanWrite;
|
||||||
|
|
||||||
|
public override long Length => _innerStream.Length;
|
||||||
|
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get { return _innerStream.Position; }
|
||||||
|
set { _innerStream.Position = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
_innerStream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (_maxRequestBodySizeFeature.MaxRequestBodySize != null
|
||||||
|
&& _innerStream.Length > _maxRequestBodySizeFeature.MaxRequestBodySize)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Request content size is greater than the limit size");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _innerStream.Read(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
return _innerStream.Seek(offset, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
_innerStream.SetLength(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
_innerStream.Write(buffer, offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHttpMaxRequestBodySizeFeature : IHttpMaxRequestBodySizeFeature
|
||||||
|
{
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
public long? MaxRequestBodySize { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue