parent
579aca0121
commit
17f6b17a6d
|
|
@ -176,6 +176,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Singleton<IFilterProvider, DefaultFilterProvider>());
|
ServiceDescriptor.Singleton<IFilterProvider, DefaultFilterProvider>());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Resource Filters
|
||||||
|
//
|
||||||
|
services.TryAddTransient<RequestSizeLimitResourceFilter>();
|
||||||
|
services.TryAddTransient<DisableRequestSizeLimitResourceFilter>();
|
||||||
|
|
||||||
//
|
//
|
||||||
// ModelBinding, Validation
|
// ModelBinding, Validation
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Internal;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Disables the request body size limit.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
public class DisableRequestSizeLimitAttribute : Attribute, IFilterFactory, IOrderedFilter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsReusable => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var filter = serviceProvider.GetRequiredService<DisableRequestSizeLimitResourceFilter>();
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A marker interface for filters which define a policy for maximum size for the request body.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRequestSizePolicy : IFilterMetadata
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A filter that sets <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
||||||
|
/// to <c>null</c>.
|
||||||
|
/// </summary>
|
||||||
|
public class DisableRequestSizeLimitResourceFilter : IResourceFilter, IRequestSizePolicy
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="DisableRequestSizeLimitResourceFilter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public DisableRequestSizeLimitResourceFilter(ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
_logger = loggerFactory.CreateLogger<DisableRequestSizeLimitResourceFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
||||||
|
/// to <c>null</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="ResourceExecutingContext"/>.</param>
|
||||||
|
/// <remarks>If <see cref="IHttpMaxRequestBodySizeFeature"/> is not enabled or is read-only,
|
||||||
|
/// the <see cref="DisableRequestSizeLimitAttribute"/> is not applied.</remarks>
|
||||||
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
|
{
|
||||||
|
if (context == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsClosestRequestSizePolicy(context.Filters))
|
||||||
|
{
|
||||||
|
var maxRequestBodySizeFeature = context.HttpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||||
|
|
||||||
|
if (maxRequestBodySizeFeature == null)
|
||||||
|
{
|
||||||
|
_logger.FeatureNotFound();
|
||||||
|
}
|
||||||
|
else if (maxRequestBodySizeFeature.IsReadOnly)
|
||||||
|
{
|
||||||
|
_logger.FeatureIsReadOnly();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxRequestBodySizeFeature.MaxRequestBodySize = null;
|
||||||
|
_logger.RequestBodySizeLimitDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsClosestRequestSizePolicy(IList<IFilterMetadata> filters)
|
||||||
|
{
|
||||||
|
// Determine if this instance is the 'effective' request size policy.
|
||||||
|
for (var i = filters.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var filter = filters[i];
|
||||||
|
if (filter is IRequestSizePolicy)
|
||||||
|
{
|
||||||
|
return ReferenceEquals(this, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Fail("The current instance should be in the list of filters.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -72,6 +72,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
||||||
private static readonly Action<ILogger, string, Exception> _redirectToPageResultExecuting;
|
private static readonly Action<ILogger, string, Exception> _redirectToPageResultExecuting;
|
||||||
|
|
||||||
|
private static readonly Action<ILogger, Exception> _featureNotFound;
|
||||||
|
private static readonly Action<ILogger, Exception> _featureIsReadOnly;
|
||||||
|
private static readonly Action<ILogger, string, Exception> _maxRequestBodySizeSet;
|
||||||
|
private static readonly Action<ILogger, Exception> _requestBodySizeLimitDisabled;
|
||||||
|
|
||||||
static MvcCoreLoggerExtensions()
|
static MvcCoreLoggerExtensions()
|
||||||
{
|
{
|
||||||
_actionExecuting = LoggerMessage.Define<string>(
|
_actionExecuting = LoggerMessage.Define<string>(
|
||||||
|
|
@ -243,6 +248,26 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
LogLevel.Debug,
|
LogLevel.Debug,
|
||||||
3,
|
3,
|
||||||
"No actions matched the current request. Route values: {RouteValues}");
|
"No actions matched the current request. Route values: {RouteValues}");
|
||||||
|
|
||||||
|
_featureNotFound = LoggerMessage.Define(
|
||||||
|
LogLevel.Warning,
|
||||||
|
1,
|
||||||
|
"A request body size limit could not be applied. This server does not support the IHttpRequestBodySizeFeature.");
|
||||||
|
|
||||||
|
_featureIsReadOnly = LoggerMessage.Define(
|
||||||
|
LogLevel.Warning,
|
||||||
|
2,
|
||||||
|
"A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only.");
|
||||||
|
|
||||||
|
_maxRequestBodySizeSet = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Debug,
|
||||||
|
3,
|
||||||
|
"The maximum request body size has been set to {RequestSize}.");
|
||||||
|
|
||||||
|
_requestBodySizeLimitDisabled = LoggerMessage.Define(
|
||||||
|
LogLevel.Debug,
|
||||||
|
3,
|
||||||
|
"The request body size limit has been disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDisposable ActionScope(this ILogger logger, ActionDescriptor action)
|
public static IDisposable ActionScope(this ILogger logger, ActionDescriptor action)
|
||||||
|
|
@ -522,6 +547,26 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
public static void RedirectToPageResultExecuting(this ILogger logger, string page)
|
public static void RedirectToPageResultExecuting(this ILogger logger, string page)
|
||||||
=> _redirectToPageResultExecuting(logger, page, null);
|
=> _redirectToPageResultExecuting(logger, page, null);
|
||||||
|
|
||||||
|
public static void FeatureNotFound(this ILogger logger)
|
||||||
|
{
|
||||||
|
_featureNotFound(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FeatureIsReadOnly(this ILogger logger)
|
||||||
|
{
|
||||||
|
_featureIsReadOnly(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MaxRequestBodySizeSet(this ILogger logger, string requestSize)
|
||||||
|
{
|
||||||
|
_maxRequestBodySizeSet(logger, requestSize, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RequestBodySizeLimitDisabled(this ILogger logger)
|
||||||
|
{
|
||||||
|
_requestBodySizeLimitDisabled(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
private class ActionLogScope : IReadOnlyList<KeyValuePair<string, object>>
|
private class ActionLogScope : IReadOnlyList<KeyValuePair<string, object>>
|
||||||
{
|
{
|
||||||
private readonly ActionDescriptor _action;
|
private readonly ActionDescriptor _action;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A filter that sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/>
|
||||||
|
/// to the specified <see cref="Bytes"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class RequestSizeLimitResourceFilter : IResourceFilter, IRequestSizePolicy
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="RequestSizeLimitResourceFilter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public RequestSizeLimitResourceFilter(ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
_logger = loggerFactory.CreateLogger<RequestSizeLimitResourceFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Bytes { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the <see cref="IHttpMaxRequestBodySizeFeature.MaxRequestBodySize"/> to <see cref="Bytes"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="ResourceExecutingContext"/>.</param>
|
||||||
|
/// <remarks>If <see cref="IHttpMaxRequestBodySizeFeature"/> is not enabled or is read-only,
|
||||||
|
/// the <see cref="RequestSizeLimitAttribute"/> is not applied.</remarks>
|
||||||
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
|
{
|
||||||
|
if (context == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsClosestRequestSizePolicy(context.Filters))
|
||||||
|
{
|
||||||
|
var maxRequestBodySizeFeature = context.HttpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
|
||||||
|
|
||||||
|
if (maxRequestBodySizeFeature == null)
|
||||||
|
{
|
||||||
|
_logger.FeatureNotFound();
|
||||||
|
}
|
||||||
|
else if (maxRequestBodySizeFeature.IsReadOnly)
|
||||||
|
{
|
||||||
|
_logger.FeatureIsReadOnly();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxRequestBodySizeFeature.MaxRequestBodySize = Bytes;
|
||||||
|
_logger.MaxRequestBodySizeSet(Bytes.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsClosestRequestSizePolicy(IList<IFilterMetadata> filters)
|
||||||
|
{
|
||||||
|
// Determine if this instance is the 'effective' request size policy.
|
||||||
|
for (var i = filters.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var filter = filters[i];
|
||||||
|
if (filter is IRequestSizePolicy)
|
||||||
|
{
|
||||||
|
return ReferenceEquals(this, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Fail("The current instance should be in the list of filters.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Internal;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the request body size limit to the specified size.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
public class RequestSizeLimitAttribute : Attribute, IFilterFactory, IOrderedFilter
|
||||||
|
{
|
||||||
|
private readonly long _bytes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="RequestSizeLimitAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bytes">The request body size limit.</param>
|
||||||
|
public RequestSizeLimitAttribute(long bytes)
|
||||||
|
{
|
||||||
|
_bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsReusable => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var filter = serviceProvider.GetRequiredService<RequestSizeLimitResourceFilter>();
|
||||||
|
filter.Bytes = _bytes;
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
{
|
||||||
|
public class DisableRequestSizeLimitResourceFilterTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SetsMaxRequestBodySizeToNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SkipsWhenOverridden()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
||||||
|
var disableRequestSizeLimitResourceFilterFinal = new DisableRequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter, disableRequestSizeLimitResourceFilterFinal });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
disableRequestSizeLimitResourceFilterFinal.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
Assert.Equal(1, httpMaxRequestBodySize.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LogsFeatureNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(loggerFactory);
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var write = Assert.Single(sink.Writes);
|
||||||
|
Assert.Equal($"A request body size limit could not be applied. This server does not support the IHttpRequestBodySizeFeature.",
|
||||||
|
write.State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LogsFeatureIsReadOnly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(loggerFactory);
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
httpMaxRequestBodySize.IsReadOnly = true;
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var write = Assert.Single(sink.Writes);
|
||||||
|
Assert.Equal($"A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only.", write.State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LogsMaxRequestBodySizeSetToNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitResourceFilter(loggerFactory);
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
disableRequestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var write = Assert.Single(sink.Writes);
|
||||||
|
Assert.Equal($"The request body size limit has been disabled.", write.State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResourceExecutingContext CreateResourceExecutingContext(IFilterMetadata[] filters)
|
||||||
|
{
|
||||||
|
return new ResourceExecutingContext(
|
||||||
|
CreateActionContext(),
|
||||||
|
filters,
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ActionContext CreateActionContext()
|
||||||
|
{
|
||||||
|
return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHttpMaxRequestBodySizeFeature : IHttpMaxRequestBodySizeFeature
|
||||||
|
{
|
||||||
|
private long? _maxRequestBodySize;
|
||||||
|
|
||||||
|
public bool IsReadOnly { get; set; }
|
||||||
|
|
||||||
|
public long? MaxRequestBodySize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _maxRequestBodySize;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_maxRequestBodySize = value;
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
{
|
||||||
|
public class RequestSizeLimitResourceFilterTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SetsMaxRequestBodySize()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
||||||
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(12345, httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SkipsWhenOverridden()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
||||||
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
|
var requestSizeLimitResourceFilterFinal = new RequestSizeLimitResourceFilter(NullLoggerFactory.Instance);
|
||||||
|
requestSizeLimitResourceFilterFinal.Bytes = 0;
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter, requestSizeLimitResourceFilterFinal });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
requestSizeLimitResourceFilterFinal.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0, httpMaxRequestBodySize.MaxRequestBodySize);
|
||||||
|
Assert.Equal(1, httpMaxRequestBodySize.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LogsFeatureNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(loggerFactory);
|
||||||
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var write = Assert.Single(sink.Writes);
|
||||||
|
Assert.Equal($"A request body size limit could not be applied. This server does not support the IHttpRequestBodySizeFeature.",
|
||||||
|
write.State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LogsFeatureIsReadOnly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(loggerFactory);
|
||||||
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
httpMaxRequestBodySize.IsReadOnly = true;
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var write = Assert.Single(sink.Writes);
|
||||||
|
Assert.Equal($"A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only.", write.State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void LogsMaxRequestBodySizeSet()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sink = new TestSink();
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
var requestSizeLimitResourceFilter = new RequestSizeLimitResourceFilter(loggerFactory);
|
||||||
|
requestSizeLimitResourceFilter.Bytes = 12345;
|
||||||
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilterMetadata[] { requestSizeLimitResourceFilter });
|
||||||
|
|
||||||
|
var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature();
|
||||||
|
resourceExecutingContext.HttpContext.Features.Set<IHttpMaxRequestBodySizeFeature>(httpMaxRequestBodySize);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
requestSizeLimitResourceFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var write = Assert.Single(sink.Writes);
|
||||||
|
Assert.Equal($"The maximum request body size has been set to 12345.", write.State.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResourceExecutingContext CreateResourceExecutingContext(IFilterMetadata[] filters)
|
||||||
|
{
|
||||||
|
return new ResourceExecutingContext(
|
||||||
|
CreateActionContext(),
|
||||||
|
filters,
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ActionContext CreateActionContext()
|
||||||
|
{
|
||||||
|
return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHttpMaxRequestBodySizeFeature : IHttpMaxRequestBodySizeFeature
|
||||||
|
{
|
||||||
|
private long? _maxRequestBodySize;
|
||||||
|
|
||||||
|
public bool IsReadOnly { get; set; }
|
||||||
|
|
||||||
|
public long? MaxRequestBodySize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _maxRequestBodySize;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_maxRequestBodySize = value;
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,8 @@
|
||||||
// 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;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
|
||||||
|
|
||||||
namespace FiltersWebSite
|
namespace FiltersWebSite
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue