Rename request body min rate APIs (#1901).

This commit is contained in:
Cesar Blum Silveira 2017-06-29 17:16:34 -07:00 committed by GitHub
parent 3ba8c2d3f0
commit f2061ed716
21 changed files with 206 additions and 170 deletions

View File

@ -333,4 +333,7 @@
<data name="NonNegativeTimeSpanRequired" xml:space="preserve"> <data name="NonNegativeTimeSpanRequired" xml:space="preserve">
<value>Value must be a non-negative TimeSpan.</value> <value>Value must be a non-negative TimeSpan.</value>
</data> </data>
<data name="MinimumGracePeriodRequired" xml:space="preserve">
<value>The request body rate enforcement grace period must be greater than {heartbeatInterval} second.</value>
</data>
</root> </root>

View File

@ -6,13 +6,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
/// <summary> /// <summary>
/// Represents a minimum data rate for the request body of an HTTP request. /// Represents a minimum data rate for the request body of an HTTP request.
/// </summary> /// </summary>
public interface IHttpRequestBodyMinimumDataRateFeature public interface IHttpMinRequestBodyDataRateFeature
{ {
/// <summary> /// <summary>
/// The minimum data rate in bytes/second at which the request body should be received. /// The minimum data rate in bytes/second at which the request body should be received.
/// Setting this property to null indicates no minimum data rate should be enforced. /// Setting this property to null indicates no minimum data rate should be enforced.
/// This limit has no effect on upgraded connections which are always unlimited. /// This limit has no effect on upgraded connections which are always unlimited.
/// </summary> /// </summary>
MinimumDataRate MinimumDataRate { get; set; } MinDataRate MinDataRate { get; set; }
} }
} }

View File

@ -1,41 +0,0 @@
// 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;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
{
public class MinimumDataRate
{
/// <summary>
/// Creates a new instance of <see cref="MinimumDataRate"/>.
/// </summary>
/// <param name="rate">The minimum rate in bytes/second at which data should be processed.</param>
/// <param name="gracePeriod">The amount of time to delay enforcement of <paramref name="rate"/>.</param>
public MinimumDataRate(double rate, TimeSpan gracePeriod)
{
if (rate <= 0)
{
throw new ArgumentOutOfRangeException(nameof(rate), CoreStrings.PositiveNumberRequired);
}
if (gracePeriod < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(gracePeriod), CoreStrings.NonNegativeTimeSpanRequired);
}
Rate = rate;
GracePeriod = gracePeriod;
}
/// <summary>
/// The minimum rate in bytes/second at which data should be processed.
/// </summary>
public double Rate { get; }
/// <summary>
/// The amount of time to delay enforcement of <see cref="MinimumDataRate" />.
/// </summary>
public TimeSpan GracePeriod { get; }
}
}

View File

@ -285,14 +285,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
{ {
_readTimingElapsedTicks += timestamp - _lastTimestamp; _readTimingElapsedTicks += timestamp - _lastTimestamp;
if (_frame.RequestBodyMinimumDataRate?.Rate > 0 && _readTimingElapsedTicks > _frame.RequestBodyMinimumDataRate.GracePeriod.Ticks) if (_frame.MinRequestBodyDataRate?.BytesPerSecond > 0 && _readTimingElapsedTicks > _frame.MinRequestBodyDataRate.GracePeriod.Ticks)
{ {
var elapsedSeconds = (double)_readTimingElapsedTicks / TimeSpan.TicksPerSecond; var elapsedSeconds = (double)_readTimingElapsedTicks / TimeSpan.TicksPerSecond;
var rate = Interlocked.Read(ref _readTimingBytesRead) / elapsedSeconds; var rate = Interlocked.Read(ref _readTimingBytesRead) / elapsedSeconds;
if (rate < _frame.RequestBodyMinimumDataRate.Rate && !Debugger.IsAttached) if (rate < _frame.MinRequestBodyDataRate.BytesPerSecond && !Debugger.IsAttached)
{ {
Log.RequestBodyMininumDataRateNotSatisfied(_context.ConnectionId, _frame.TraceIdentifier, _frame.RequestBodyMinimumDataRate.Rate); Log.RequestBodyMininumDataRateNotSatisfied(_context.ConnectionId, _frame.TraceIdentifier, _frame.MinRequestBodyDataRate.BytesPerSecond);
Timeout(); Timeout();
} }
} }

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
IHttpRequestLifetimeFeature, IHttpRequestLifetimeFeature,
IHttpRequestIdentifierFeature, IHttpRequestIdentifierFeature,
IHttpMaxRequestBodySizeFeature, IHttpMaxRequestBodySizeFeature,
IHttpRequestBodyMinimumDataRateFeature IHttpMinRequestBodyDataRateFeature
{ {
// NOTE: When feature interfaces are added to or removed from this Frame class implementation, // NOTE: When feature interfaces are added to or removed from this Frame class implementation,
// then the list of `implementedFeatures` in the generated code project MUST also be updated. // then the list of `implementedFeatures` in the generated code project MUST also be updated.
@ -229,10 +229,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
} }
} }
MinimumDataRate IHttpRequestBodyMinimumDataRateFeature.MinimumDataRate MinDataRate IHttpMinRequestBodyDataRateFeature.MinDataRate
{ {
get => RequestBodyMinimumDataRate; get => MinRequestBodyDataRate;
set => RequestBodyMinimumDataRate = value; set => MinRequestBodyDataRate = value;
} }
object IFeatureCollection.this[Type key] object IFeatureCollection.this[Type key]

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature); private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature);
private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ISessionFeature); private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ISessionFeature);
private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature); private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature);
private static readonly Type IHttpRequestBodyMinimumDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpRequestBodyMinimumDataRateFeature); private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature);
private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature); private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
private object _currentIHttpRequestFeature; private object _currentIHttpRequestFeature;
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private object _currentIHttpWebSocketFeature; private object _currentIHttpWebSocketFeature;
private object _currentISessionFeature; private object _currentISessionFeature;
private object _currentIHttpMaxRequestBodySizeFeature; private object _currentIHttpMaxRequestBodySizeFeature;
private object _currentIHttpRequestBodyMinimumDataRateFeature; private object _currentIHttpMinRequestBodyDataRateFeature;
private object _currentIHttpSendFileFeature; private object _currentIHttpSendFileFeature;
private void FastReset() private void FastReset()
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_currentIHttpRequestLifetimeFeature = this; _currentIHttpRequestLifetimeFeature = this;
_currentIHttpConnectionFeature = this; _currentIHttpConnectionFeature = this;
_currentIHttpMaxRequestBodySizeFeature = this; _currentIHttpMaxRequestBodySizeFeature = this;
_currentIHttpRequestBodyMinimumDataRateFeature = this; _currentIHttpMinRequestBodyDataRateFeature = this;
_currentIServiceProvidersFeature = null; _currentIServiceProvidersFeature = null;
_currentIHttpAuthenticationFeature = null; _currentIHttpAuthenticationFeature = null;
@ -135,9 +135,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
return _currentIHttpMaxRequestBodySizeFeature; return _currentIHttpMaxRequestBodySizeFeature;
} }
if (key == IHttpRequestBodyMinimumDataRateFeatureType) if (key == IHttpMinRequestBodyDataRateFeatureType)
{ {
return _currentIHttpRequestBodyMinimumDataRateFeature; return _currentIHttpMinRequestBodyDataRateFeature;
} }
if (key == IHttpSendFileFeatureType) if (key == IHttpSendFileFeatureType)
{ {
@ -230,9 +230,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_currentIHttpMaxRequestBodySizeFeature = feature; _currentIHttpMaxRequestBodySizeFeature = feature;
return; return;
} }
if (key == IHttpRequestBodyMinimumDataRateFeatureType) if (key == IHttpMinRequestBodyDataRateFeatureType)
{ {
_currentIHttpRequestBodyMinimumDataRateFeature = feature; _currentIHttpMinRequestBodyDataRateFeature = feature;
return; return;
} }
if (key == IHttpSendFileFeatureType) if (key == IHttpSendFileFeatureType)
@ -309,9 +309,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{ {
yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature); yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature as global::Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature);
} }
if (_currentIHttpRequestBodyMinimumDataRateFeature != null) if (_currentIHttpMinRequestBodyDataRateFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpRequestBodyMinimumDataRateFeatureType, _currentIHttpRequestBodyMinimumDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpRequestBodyMinimumDataRateFeature); yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature as global::Microsoft.AspNetCore.Server.Kestrel.Core.Features.IHttpMinRequestBodyDataRateFeature);
} }
if (_currentIHttpSendFileFeature != null) if (_currentIHttpSendFileFeature != null)
{ {

View File

@ -13,7 +13,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System; using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines; using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
@ -300,7 +299,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
protected FrameResponseHeaders FrameResponseHeaders { get; } = new FrameResponseHeaders(); protected FrameResponseHeaders FrameResponseHeaders { get; } = new FrameResponseHeaders();
public MinimumDataRate RequestBodyMinimumDataRate { get; set; } public MinDataRate MinRequestBodyDataRate { get; set; }
public void InitializeStreams(MessageBody messageBody) public void InitializeStreams(MessageBody messageBody)
{ {
@ -379,7 +378,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_responseBytesWritten = 0; _responseBytesWritten = 0;
_requestCount++; _requestCount++;
RequestBodyMinimumDataRate = ServerOptions.Limits.RequestBodyMinimumDataRate; MinRequestBodyDataRate = ServerOptions.Limits.MinRequestBodyDataRate;
} }
/// <summary> /// <summary>

View File

@ -255,11 +255,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
/// Gets or sets the request body minimum data rate in bytes/second. /// Gets or sets the request body minimum data rate in bytes/second.
/// Setting this property to null indicates no minimum data rate should be enforced. /// Setting this property to null indicates no minimum data rate should be enforced.
/// This limit has no effect on upgraded connections which are always unlimited. /// This limit has no effect on upgraded connections which are always unlimited.
/// This can be overridden per-request via <see cref="IHttpRequestBodyMinimumDataRateFeature"/>. /// This can be overridden per-request via <see cref="IHttpMinRequestBodyDataRateFeature"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Defaults to 1 byte/second with a 5 second grace period. /// Defaults to 1 byte/second with a 5 second grace period.
/// </remarks> /// </remarks>
public MinimumDataRate RequestBodyMinimumDataRate { get; set; } = new MinimumDataRate(rate: 1, gracePeriod: TimeSpan.FromSeconds(5)); public MinDataRate MinRequestBodyDataRate { get; set; } = new MinDataRate(bytesPerSecond: 1, gracePeriod: TimeSpan.FromSeconds(5));
} }
} }

View File

@ -0,0 +1,44 @@
// 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.Server.Kestrel.Core.Internal.Infrastructure;
namespace Microsoft.AspNetCore.Server.Kestrel.Core
{
public class MinDataRate
{
/// <summary>
/// Creates a new instance of <see cref="MinDataRate"/>.
/// </summary>
/// <param name="bytesPerSecond">The minimum rate in bytes/second at which data should be processed.</param>
/// <param name="gracePeriod">The amount of time to delay enforcement of <paramref name="bytesPerSecond"/>,
/// starting at the time data is first read or written.</param>
public MinDataRate(double bytesPerSecond, TimeSpan gracePeriod)
{
if (bytesPerSecond < 0)
{
throw new ArgumentOutOfRangeException(nameof(bytesPerSecond), CoreStrings.NonNegativeNumberRequired);
}
if (gracePeriod <= Heartbeat.Interval)
{
throw new ArgumentOutOfRangeException(nameof(gracePeriod), CoreStrings.FormatMinimumGracePeriodRequired(Heartbeat.Interval.TotalSeconds));
}
BytesPerSecond = bytesPerSecond;
GracePeriod = gracePeriod;
}
/// <summary>
/// The minimum rate in bytes/second at which data should be processed.
/// </summary>
public double BytesPerSecond { get; }
/// <summary>
/// The amount of time to delay enforcement of <see cref="MinDataRate" />,
/// starting at the time data is first read or written.
/// </summary>
public TimeSpan GracePeriod { get; }
}
}

View File

@ -1018,6 +1018,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
internal static string FormatNonNegativeTimeSpanRequired() internal static string FormatNonNegativeTimeSpanRequired()
=> GetString("NonNegativeTimeSpanRequired"); => GetString("NonNegativeTimeSpanRequired");
/// <summary>
/// The request body rate enforcement grace period must be greater than {heartbeatInterval} seconds.
/// </summary>
internal static string MinimumGracePeriodRequired
{
get => GetString("MinimumGracePeriodRequired");
}
/// <summary>
/// The request body rate enforcement grace period must be greater than {heartbeatInterval} seconds.
/// </summary>
internal static string FormatMinimumGracePeriodRequired(object heartbeatInterval)
=> string.Format(CultureInfo.CurrentCulture, GetString("MinimumGracePeriodRequired", "heartbeatInterval"), heartbeatInterval);
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines; using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
@ -72,11 +71,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var mockDebugger = new Mock<IDebugger>(); var mockDebugger = new Mock<IDebugger>();
mockDebugger.SetupGet(g => g.IsAttached).Returns(true); mockDebugger.SetupGet(g => g.IsAttached).Returns(true);
_frameConnection.Debugger = mockDebugger.Object; _frameConnection.Debugger = mockDebugger.Object;
var requestBodyMinimumDataRate = 100; var bytesPerSecond = 100;
var mockLogger = new Mock<IKestrelTrace>(); var mockLogger = new Mock<IKestrelTrace>();
mockLogger.Setup(l => l.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>())).Throws(new InvalidOperationException("Should not log")); mockLogger.Setup(l => l.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>())).Throws(new InvalidOperationException("Should not log"));
TickBodyWithMinimumDataRate(mockLogger.Object, requestBodyMinimumDataRate); TickBodyWithMinimumDataRate(mockLogger.Object, bytesPerSecond);
Assert.False(_frameConnection.TimedOut); Assert.False(_frameConnection.TimedOut);
} }
@ -84,22 +83,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[Fact] [Fact]
public void TimesOutWhenRequestBodyDoesNotSatisfyMinimumDataRate() public void TimesOutWhenRequestBodyDoesNotSatisfyMinimumDataRate()
{ {
var requestBodyMinimumDataRate = 100; var bytesPerSecond = 100;
var mockLogger = new Mock<IKestrelTrace>(); var mockLogger = new Mock<IKestrelTrace>();
TickBodyWithMinimumDataRate(mockLogger.Object, requestBodyMinimumDataRate); TickBodyWithMinimumDataRate(mockLogger.Object, bytesPerSecond);
// Timed out // Timed out
Assert.True(_frameConnection.TimedOut); Assert.True(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Once); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
} }
private void TickBodyWithMinimumDataRate(IKestrelTrace logger, int requestBodyMinimumDataRate) private void TickBodyWithMinimumDataRate(IKestrelTrace logger, int bytesPerSecond)
{ {
var requestBodyGracePeriod = TimeSpan.FromSeconds(5); var gracePeriod = TimeSpan.FromSeconds(5);
_frameConnectionContext.ServiceContext.ServerOptions.Limits.RequestBodyMinimumDataRate = _frameConnectionContext.ServiceContext.ServerOptions.Limits.MinRequestBodyDataRate =
new MinimumDataRate(rate: requestBodyMinimumDataRate, gracePeriod: requestBodyGracePeriod); new MinDataRate(bytesPerSecond: bytesPerSecond, gracePeriod: gracePeriod);
_frameConnectionContext.ServiceContext.Log = logger; _frameConnectionContext.ServiceContext.Log = logger;
@ -113,19 +112,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_frameConnection.StartTimingReads(); _frameConnection.StartTimingReads();
// Tick after grace period w/ low data rate // Tick after grace period w/ low data rate
now += requestBodyGracePeriod + TimeSpan.FromSeconds(1); now += gracePeriod + TimeSpan.FromSeconds(1);
_frameConnection.BytesRead(1); _frameConnection.BytesRead(1);
_frameConnection.Tick(now); _frameConnection.Tick(now);
} }
[Fact] [Fact]
public void MinimumDataRateNotEnforcedDuringGracePeriod() public void RequestBodyMinimumDataRateNotEnforcedDuringGracePeriod()
{ {
var requestBodyMinimumDataRate = 100; var bytesPerSecond = 100;
var requestBodyGracePeriod = TimeSpan.FromSeconds(2); var gracePeriod = TimeSpan.FromSeconds(2);
_frameConnectionContext.ServiceContext.ServerOptions.Limits.RequestBodyMinimumDataRate = _frameConnectionContext.ServiceContext.ServerOptions.Limits.MinRequestBodyDataRate =
new MinimumDataRate(rate: requestBodyMinimumDataRate, gracePeriod: requestBodyGracePeriod); new MinDataRate(bytesPerSecond: bytesPerSecond, gracePeriod: gracePeriod);
var mockLogger = new Mock<IKestrelTrace>(); var mockLogger = new Mock<IKestrelTrace>();
_frameConnectionContext.ServiceContext.Log = mockLogger.Object; _frameConnectionContext.ServiceContext.Log = mockLogger.Object;
@ -147,7 +146,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
// Not timed out // Not timed out
Assert.False(_frameConnection.TimedOut); Assert.False(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Never); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
// Tick after grace period w/ low data rate // Tick after grace period w/ low data rate
now += TimeSpan.FromSeconds(2); now += TimeSpan.FromSeconds(2);
@ -157,17 +156,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
// Timed out // Timed out
Assert.True(_frameConnection.TimedOut); Assert.True(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Once); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
} }
[Fact] [Fact]
public void DataRateIsAveragedOverTimeSpentReadingRequestBody() public void RequestBodyDataRateIsAveragedOverTimeSpentReadingRequestBody()
{ {
var requestBodyMinimumDataRate = 100; var bytesPerSecond = 100;
var requestBodyGracePeriod = TimeSpan.FromSeconds(1); var gracePeriod = TimeSpan.FromSeconds(2);
_frameConnectionContext.ServiceContext.ServerOptions.Limits.RequestBodyMinimumDataRate = _frameConnectionContext.ServiceContext.ServerOptions.Limits.MinRequestBodyDataRate =
new MinimumDataRate(rate: requestBodyMinimumDataRate, gracePeriod: requestBodyGracePeriod); new MinDataRate(bytesPerSecond: bytesPerSecond, gracePeriod: gracePeriod);
var mockLogger = new Mock<IKestrelTrace>(); var mockLogger = new Mock<IKestrelTrace>();
_frameConnectionContext.ServiceContext.Log = mockLogger.Object; _frameConnectionContext.ServiceContext.Log = mockLogger.Object;
@ -181,60 +180,69 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_frameConnection.StartTimingReads(); _frameConnection.StartTimingReads();
// Tick after grace period to start enforcing minimum data rate // Set base data rate to 200 bytes/second
now += requestBodyGracePeriod; now += gracePeriod;
_frameConnection.BytesRead(100); _frameConnection.BytesRead(400);
_frameConnection.Tick(now); _frameConnection.Tick(now);
// Data rate: 200 bytes/second // Data rate: 200 bytes/second
now += TimeSpan.FromSeconds(1); now += TimeSpan.FromSeconds(1);
_frameConnection.BytesRead(300); _frameConnection.BytesRead(200);
_frameConnection.Tick(now); _frameConnection.Tick(now);
// Not timed out // Not timed out
Assert.False(_frameConnection.TimedOut); Assert.False(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Never); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
// Data rate: 150 bytes/second // Data rate: 150 bytes/second
now += TimeSpan.FromSeconds(1); now += TimeSpan.FromSeconds(1);
_frameConnection.BytesRead(50); _frameConnection.BytesRead(0);
_frameConnection.Tick(now); _frameConnection.Tick(now);
// Not timed out // Not timed out
Assert.False(_frameConnection.TimedOut); Assert.False(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Never); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
// Data rate: 115 bytes/second // Data rate: 120 bytes/second
now += TimeSpan.FromSeconds(1); now += TimeSpan.FromSeconds(1);
_frameConnection.BytesRead(10); _frameConnection.BytesRead(0);
_frameConnection.Tick(now); _frameConnection.Tick(now);
// Not timed out // Not timed out
Assert.False(_frameConnection.TimedOut); Assert.False(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Never); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
// Data rate: 50 bytes/second // Data rate: 100 bytes/second
now += TimeSpan.FromSeconds(6); now += TimeSpan.FromSeconds(1);
_frameConnection.BytesRead(40); _frameConnection.BytesRead(0);
_frameConnection.Tick(now);
// Not timed out
Assert.False(_frameConnection.TimedOut);
mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Never);
// Data rate: ~85 bytes/second
now += TimeSpan.FromSeconds(1);
_frameConnection.BytesRead(0);
_frameConnection.Tick(now); _frameConnection.Tick(now);
// Timed out // Timed out
Assert.True(_frameConnection.TimedOut); Assert.True(_frameConnection.TimedOut);
mockLogger.Verify(logger => mockLogger.Verify(logger =>
logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), requestBodyMinimumDataRate), Times.Once); logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), bytesPerSecond), Times.Once);
} }
[Fact] [Fact]
public void PausedTimeDoesNotCountAgainstRequestBodyTimeout() public void RequestBodyDataRateNotComputedOnPausedTime()
{ {
var requestBodyTimeout = TimeSpan.FromSeconds(5);
var systemClock = new MockSystemClock(); var systemClock = new MockSystemClock();
_frameConnectionContext.ServiceContext.ServerOptions.Limits.RequestBodyMinimumDataRate = _frameConnectionContext.ServiceContext.ServerOptions.Limits.MinRequestBodyDataRate =
new MinimumDataRate(rate: 100, gracePeriod: TimeSpan.Zero); new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(2));
_frameConnectionContext.ServiceContext.SystemClock = systemClock; _frameConnectionContext.ServiceContext.SystemClock = systemClock;
var mockLogger = new Mock<IKestrelTrace>(); var mockLogger = new Mock<IKestrelTrace>();
@ -248,21 +256,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_frameConnection.StartTimingReads(); _frameConnection.StartTimingReads();
// Tick at 1s, expected counted time is 1s, expected data rate is 400 bytes/second // Tick at 3s, expected counted time is 3s, expected data rate is 200 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(1); systemClock.UtcNow += TimeSpan.FromSeconds(3);
_frameConnection.BytesRead(400); _frameConnection.BytesRead(600);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
// Pause at 1.5s // Pause at 3.5s
systemClock.UtcNow += TimeSpan.FromSeconds(0.5); systemClock.UtcNow += TimeSpan.FromSeconds(0.5);
_frameConnection.PauseTimingReads(); _frameConnection.PauseTimingReads();
// Tick at 2s, expected counted time is 2s, expected data rate is 400 bytes/second // Tick at 4s, expected counted time is 4s (first tick after pause goes through), expected data rate is 150 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(0.5); systemClock.UtcNow += TimeSpan.FromSeconds(0.5);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
// Tick at 6s, expected counted time is 2s, expected data rate is 400 bytes/second // Tick at 6s, expected counted time is 4s, expected data rate is 150 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(4); systemClock.UtcNow += TimeSpan.FromSeconds(2);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
// Not timed out // Not timed out
@ -275,7 +283,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
systemClock.UtcNow += TimeSpan.FromSeconds(0.5); systemClock.UtcNow += TimeSpan.FromSeconds(0.5);
_frameConnection.ResumeTimingReads(); _frameConnection.ResumeTimingReads();
// Tick at 8s, expected counted time is 4s, expected data rate is 100 bytes/second // Tick at 9s, expected counted time is 6s, expected data rate is 100 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(1.5); systemClock.UtcNow += TimeSpan.FromSeconds(1.5);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
@ -285,7 +293,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()), logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
Times.Never); Times.Never);
// Tick at 9s, expected counted time is 9s, expected data rate drops below 100 bytes/second // Tick at 10s, expected counted time is 7s, expected data rate drops below 100 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(1); systemClock.UtcNow += TimeSpan.FromSeconds(1);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
@ -297,12 +305,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
[Fact] [Fact]
public void NotPausedWhenResumeCalledBeforeNextTick() public void ReadTimingNotPausedWhenResumeCalledBeforeNextTick()
{ {
var systemClock = new MockSystemClock(); var systemClock = new MockSystemClock();
_frameConnectionContext.ServiceContext.ServerOptions.Limits.RequestBodyMinimumDataRate = _frameConnectionContext.ServiceContext.ServerOptions.Limits.MinRequestBodyDataRate =
new MinimumDataRate(rate: 100, gracePeriod: TimeSpan.Zero); new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(2));
_frameConnectionContext.ServiceContext.SystemClock = systemClock; _frameConnectionContext.ServiceContext.SystemClock = systemClock;
var mockLogger = new Mock<IKestrelTrace>(); var mockLogger = new Mock<IKestrelTrace>();
@ -316,9 +324,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_frameConnection.StartTimingReads(); _frameConnection.StartTimingReads();
// Tick at 1s, expected counted time is 1s, expected data rate is 100 bytes/second // Tick at 2s, expected counted time is 2s, expected data rate is 100 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(1); systemClock.UtcNow += TimeSpan.FromSeconds(2);
_frameConnection.BytesRead(100); _frameConnection.BytesRead(200);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
// Not timed out // Not timed out
@ -327,15 +335,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()), logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
Times.Never); Times.Never);
// Pause at 1.25s // Pause at 2.25s
systemClock.UtcNow += TimeSpan.FromSeconds(0.25); systemClock.UtcNow += TimeSpan.FromSeconds(0.25);
_frameConnection.PauseTimingReads(); _frameConnection.PauseTimingReads();
// Resume at 1.5s // Resume at 2.5s
systemClock.UtcNow += TimeSpan.FromSeconds(0.25); systemClock.UtcNow += TimeSpan.FromSeconds(0.25);
_frameConnection.ResumeTimingReads(); _frameConnection.ResumeTimingReads();
// Tick at 2s, expected counted time is 2s, expected data rate is 100 bytes/second // Tick at 3s, expected counted time is 3s, expected data rate is 100 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(0.5); systemClock.UtcNow += TimeSpan.FromSeconds(0.5);
_frameConnection.BytesRead(100); _frameConnection.BytesRead(100);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);
@ -346,7 +354,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()), logger => logger.RequestBodyMininumDataRateNotSatisfied(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<double>()),
Times.Never); Times.Never);
// Tick at 3s, expected counted time is 3s, expected data rate drops below 100 bytes/second // Tick at 4s, expected counted time is 4s, expected data rate drops below 100 bytes/second
systemClock.UtcNow += TimeSpan.FromSeconds(1); systemClock.UtcNow += TimeSpan.FromSeconds(1);
_frameConnection.Tick(systemClock.UtcNow); _frameConnection.Tick(systemClock.UtcNow);

View File

@ -141,13 +141,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
[Fact] [Fact]
public void ResetResetsRequestBodyMinimumDataRate() public void ResetResetsMinRequestBodyDataRate()
{ {
_frame.RequestBodyMinimumDataRate = new MinimumDataRate(rate: 1, gracePeriod: TimeSpan.Zero); _frame.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: 1, gracePeriod: TimeSpan.MaxValue);
_frame.Reset(); _frame.Reset();
Assert.Equal(_serviceContext.ServerOptions.Limits.RequestBodyMinimumDataRate, _frame.RequestBodyMinimumDataRate); Assert.Equal(_serviceContext.ServerOptions.Limits.MinRequestBodyDataRate, _frame.MinRequestBodyDataRate);
} }
[Fact] [Fact]
@ -254,12 +254,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
[Theory] [Theory]
[MemberData(nameof(RequestBodyMinimumDataRateData))] [MemberData(nameof(MinRequestBodyDataRateData))]
public void ConfiguringRequestBodyMinimumDataRateFeatureSetsRequestBodyMinimumDateRate(MinimumDataRate minimumDataRate) public void ConfiguringIHttpMinRequestBodyDataRateFeatureSetsMinRequestBodyDataRate(MinDataRate minDataRate)
{ {
((IFeatureCollection)_frame).Get<IHttpRequestBodyMinimumDataRateFeature>().MinimumDataRate = minimumDataRate; ((IFeatureCollection)_frame).Get<IHttpMinRequestBodyDataRateFeature>().MinDataRate = minDataRate;
Assert.Same(minimumDataRate, _frame.RequestBodyMinimumDataRate); Assert.Same(minDataRate, _frame.MinRequestBodyDataRate);
} }
[Fact] [Fact]
@ -878,10 +878,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
TimeSpan.Zero TimeSpan.Zero
}; };
public static TheoryData<MinimumDataRate> RequestBodyMinimumDataRateData => new TheoryData<MinimumDataRate> public static TheoryData<MinDataRate> MinRequestBodyDataRateData => new TheoryData<MinDataRate>
{ {
null, null,
new MinimumDataRate(rate: 1, gracePeriod: TimeSpan.Zero) new MinDataRate(bytesPerSecond: 1, gracePeriod: TimeSpan.MaxValue)
}; };
private class RequestHeadersWrapper : IHeaderDictionary private class RequestHeadersWrapper : IHeaderDictionary

View File

@ -15,6 +15,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
public class HeartbeatTests public class HeartbeatTests
{ {
[Fact]
public void HeartbeatIntervalIsOneSecond()
{
Assert.Equal(TimeSpan.FromSeconds(1), Heartbeat.Interval);
}
[Fact] [Fact]
public void BlockedHeartbeatDoesntCauseOverlapsAndIsLoggedAsError() public void BlockedHeartbeatDoesntCauseOverlapsAndIsLoggedAsError()
{ {

View File

@ -293,11 +293,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
} }
[Fact] [Fact]
public void RequestBodyMinimumDataRateDefault() public void MinRequestBodyDataRateDefault()
{ {
Assert.NotNull(new KestrelServerLimits().RequestBodyMinimumDataRate); Assert.NotNull(new KestrelServerLimits().MinRequestBodyDataRate);
Assert.Equal(1, new KestrelServerLimits().RequestBodyMinimumDataRate.Rate); Assert.Equal(1, new KestrelServerLimits().MinRequestBodyDataRate.BytesPerSecond);
Assert.Equal(TimeSpan.FromSeconds(5), new KestrelServerLimits().RequestBodyMinimumDataRate.GracePeriod); Assert.Equal(TimeSpan.FromSeconds(5), new KestrelServerLimits().MinRequestBodyDataRate.GracePeriod);
} }
public static TheoryData<TimeSpan> TimeoutValidData => new TheoryData<TimeSpan> public static TheoryData<TimeSpan> TimeoutValidData => new TheoryData<TimeSpan>

View File

@ -2,60 +2,62 @@
// 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;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{ {
public class MinimumDataRateTests public class MinDataRateTests
{ {
[Theory] [Theory]
[InlineData(0)]
[InlineData(double.Epsilon)] [InlineData(double.Epsilon)]
[InlineData(double.MaxValue)] [InlineData(double.MaxValue)]
public void RateValid(double value) public void BytesPerSecondValid(double value)
{ {
Assert.Equal(value, new MinimumDataRate(rate: value, gracePeriod: TimeSpan.Zero).Rate); Assert.Equal(value, new MinDataRate(bytesPerSecond: value, gracePeriod: TimeSpan.MaxValue).BytesPerSecond);
} }
[Theory] [Theory]
[InlineData(double.MinValue)] [InlineData(double.MinValue)]
[InlineData(0)] [InlineData(-double.Epsilon)]
public void RateInvalid(double value) public void BytesPerSecondInvalid(double value)
{ {
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => new MinimumDataRate(rate: value, gracePeriod: TimeSpan.Zero)); var exception = Assert.Throws<ArgumentOutOfRangeException>(() => new MinDataRate(bytesPerSecond: value, gracePeriod: TimeSpan.MaxValue));
Assert.Equal("rate", exception.ParamName); Assert.Equal("bytesPerSecond", exception.ParamName);
Assert.StartsWith(CoreStrings.PositiveNumberRequired, exception.Message); Assert.StartsWith(CoreStrings.NonNegativeNumberRequired, exception.Message);
} }
[Theory] [Theory]
[MemberData(nameof(GracePeriodValidData))] [MemberData(nameof(GracePeriodValidData))]
public void GracePeriodValid(TimeSpan value) public void GracePeriodValid(TimeSpan value)
{ {
Assert.Equal(value, new MinimumDataRate(rate: 1, gracePeriod: value).GracePeriod); Assert.Equal(value, new MinDataRate(bytesPerSecond: 1, gracePeriod: value).GracePeriod);
} }
[Theory] [Theory]
[MemberData(nameof(GracePeriodInvalidData))] [MemberData(nameof(GracePeriodInvalidData))]
public void GracePeriodInvalid(TimeSpan value) public void GracePeriodInvalid(TimeSpan value)
{ {
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => new MinimumDataRate(rate: 1, gracePeriod: value)); var exception = Assert.Throws<ArgumentOutOfRangeException>(() => new MinDataRate(bytesPerSecond: 1, gracePeriod: value));
Assert.Equal("gracePeriod", exception.ParamName); Assert.Equal("gracePeriod", exception.ParamName);
Assert.StartsWith(CoreStrings.NonNegativeTimeSpanRequired, exception.Message); Assert.StartsWith(CoreStrings.FormatMinimumGracePeriodRequired(Heartbeat.Interval.TotalSeconds), exception.Message);
} }
public static TheoryData<TimeSpan> GracePeriodValidData => new TheoryData<TimeSpan> public static TheoryData<TimeSpan> GracePeriodValidData => new TheoryData<TimeSpan>
{ {
TimeSpan.Zero, Heartbeat.Interval + TimeSpan.FromTicks(1),
TimeSpan.FromTicks(1),
TimeSpan.MaxValue TimeSpan.MaxValue
}; };
public static TheoryData<TimeSpan> GracePeriodInvalidData => new TheoryData<TimeSpan> public static TheoryData<TimeSpan> GracePeriodInvalidData => new TheoryData<TimeSpan>
{ {
TimeSpan.MinValue, TimeSpan.MinValue,
TimeSpan.FromTicks(-1) TimeSpan.FromTicks(-1),
TimeSpan.Zero,
Heartbeat.Interval
}; };
} }
} }

View File

@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
Limits = Limits =
{ {
KeepAliveTimeout = KeepAliveTimeout, KeepAliveTimeout = KeepAliveTimeout,
RequestBodyMinimumDataRate = null MinRequestBodyDataRate = null
} }
} }
}); });

View File

@ -274,7 +274,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
options.Limits.MaxRequestHeadersTotalSize = (int)maxRequestBufferSize; options.Limits.MaxRequestHeadersTotalSize = (int)maxRequestBufferSize;
} }
options.Limits.RequestBodyMinimumDataRate = null; options.Limits.MinRequestBodyDataRate = null;
}) })
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.Configure(app => app.Run(async context => .Configure(app => app.Run(async context =>

View File

@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public class RequestBodyTimeoutTests public class RequestBodyTimeoutTests
{ {
[Fact] [Fact]
public async Task RequestTimesOutWhenRequestBodyNotReceivedAtDesiredMinimumRate() public async Task RequestTimesOutWhenRequestBodyNotReceivedAtSpecifiedMinimumRate()
{ {
var minimumDataRateGracePeriod = TimeSpan.FromSeconds(5); var gracePeriod = TimeSpan.FromSeconds(5);
var systemClock = new MockSystemClock(); var systemClock = new MockSystemClock();
var serviceContext = new TestServiceContext var serviceContext = new TestServiceContext
{ {
@ -31,8 +31,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var server = new TestServer(context => using (var server = new TestServer(context =>
{ {
context.Features.Get<IHttpRequestBodyMinimumDataRateFeature>().MinimumDataRate = context.Features.Get<IHttpMinRequestBodyDataRateFeature>().MinDataRate =
new MinimumDataRate(rate: 1, gracePeriod: minimumDataRateGracePeriod); new MinDataRate(bytesPerSecond: 1, gracePeriod: gracePeriod);
appRunningEvent.Set(); appRunningEvent.Set();
return context.Request.Body.ReadAsync(new byte[1], 0, 1); return context.Request.Body.ReadAsync(new byte[1], 0, 1);
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
""); "");
Assert.True(appRunningEvent.Wait(TimeSpan.FromSeconds(10))); Assert.True(appRunningEvent.Wait(TimeSpan.FromSeconds(10)));
systemClock.UtcNow += minimumDataRateGracePeriod + TimeSpan.FromSeconds(1); systemClock.UtcNow += gracePeriod + TimeSpan.FromSeconds(1);
await connection.Receive( await connection.Receive(
"HTTP/1.1 408 Request Timeout", "HTTP/1.1 408 Request Timeout",
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
[Fact] [Fact]
public async Task RequestTimesWhenNotDrainedWithinDrainTimeoutPeriod() public async Task RequestTimesOutWhenNotDrainedWithinDrainTimeoutPeriod()
{ {
// This test requires a real clock since we can't control when the drain timeout is set // This test requires a real clock since we can't control when the drain timeout is set
var systemClock = new SystemClock(); var systemClock = new SystemClock();
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var server = new TestServer(context => using (var server = new TestServer(context =>
{ {
context.Features.Get<IHttpRequestBodyMinimumDataRateFeature>().MinimumDataRate = null; context.Features.Get<IHttpMinRequestBodyDataRateFeature>().MinDataRate = null;
appRunningEvent.Set(); appRunningEvent.Set();
return Task.CompletedTask; return Task.CompletedTask;
@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task ConnectionClosedEvenIfAppSwallowsException() public async Task ConnectionClosedEvenIfAppSwallowsException()
{ {
var minimumDataRateGracePeriod = TimeSpan.FromSeconds(5); var gracePeriod = TimeSpan.FromSeconds(5);
var systemClock = new MockSystemClock(); var systemClock = new MockSystemClock();
var serviceContext = new TestServiceContext var serviceContext = new TestServiceContext
{ {
@ -125,8 +125,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var server = new TestServer(async context => using (var server = new TestServer(async context =>
{ {
context.Features.Get<IHttpRequestBodyMinimumDataRateFeature>().MinimumDataRate = context.Features.Get<IHttpMinRequestBodyDataRateFeature>().MinDataRate =
new MinimumDataRate(rate: 1, gracePeriod: minimumDataRateGracePeriod); new MinDataRate(bytesPerSecond: 1, gracePeriod: gracePeriod);
appRunningEvent.Set(); appRunningEvent.Set();
@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
""); "");
Assert.True(appRunningEvent.Wait(TimeSpan.FromSeconds(10))); Assert.True(appRunningEvent.Wait(TimeSpan.FromSeconds(10)));
systemClock.UtcNow += minimumDataRateGracePeriod + TimeSpan.FromSeconds(1); systemClock.UtcNow += gracePeriod + TimeSpan.FromSeconds(1);
Assert.True(exceptionSwallowedEvent.Wait(TimeSpan.FromSeconds(10))); Assert.True(exceptionSwallowedEvent.Wait(TimeSpan.FromSeconds(10)));
await connection.Receive( await connection.Receive(

View File

@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
Limits = Limits =
{ {
RequestHeadersTimeout = RequestHeadersTimeout, RequestHeadersTimeout = RequestHeadersTimeout,
RequestBodyMinimumDataRate = null MinRequestBodyDataRate = null
} }
} }
}); });

View File

@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Limits.MaxRequestBodySize = contentLength; options.Limits.MaxRequestBodySize = contentLength;
options.Limits.RequestBodyMinimumDataRate = null; options.Limits.MinRequestBodyDataRate = null;
}) })
.UseUrls("http://127.0.0.1:0/") .UseUrls("http://127.0.0.1:0/")
.Configure(app => .Configure(app =>
@ -1429,7 +1429,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var server = new TestServer(async context => using (var server = new TestServer(async context =>
{ {
context.Features.Get<IHttpRequestBodyMinimumDataRateFeature>().MinimumDataRate = new MinimumDataRate(rate: double.MaxValue, gracePeriod: TimeSpan.Zero); context.Features.Get<IHttpMinRequestBodyDataRateFeature>().MinDataRate =
new MinDataRate(bytesPerSecond: double.MaxValue, gracePeriod: Heartbeat.Interval + TimeSpan.FromTicks(1));
using (var stream = await context.Features.Get<IHttpUpgradeFeature>().UpgradeAsync()) using (var stream = await context.Features.Get<IHttpUpgradeFeature>().UpgradeAsync())
{ {

View File

@ -47,7 +47,7 @@ namespace CodeGenerator
typeof(IHttpWebSocketFeature), typeof(IHttpWebSocketFeature),
typeof(ISessionFeature), typeof(ISessionFeature),
typeof(IHttpMaxRequestBodySizeFeature), typeof(IHttpMaxRequestBodySizeFeature),
typeof(IHttpRequestBodyMinimumDataRateFeature), typeof(IHttpMinRequestBodyDataRateFeature),
}; };
var rareFeatures = new[] var rareFeatures = new[]
@ -68,7 +68,7 @@ namespace CodeGenerator
typeof(IHttpRequestLifetimeFeature), typeof(IHttpRequestLifetimeFeature),
typeof(IHttpConnectionFeature), typeof(IHttpConnectionFeature),
typeof(IHttpMaxRequestBodySizeFeature), typeof(IHttpMaxRequestBodySizeFeature),
typeof(IHttpRequestBodyMinimumDataRateFeature), typeof(IHttpMinRequestBodyDataRateFeature),
}; };
return $@"// Copyright (c) .NET Foundation. All rights reserved. return $@"// Copyright (c) .NET Foundation. All rights reserved.