Merge branch 'rel/2.0.0-preview2' into dev

This commit is contained in:
Cesar Blum Silveira 2017-06-19 16:39:00 -07:00
commit 892de7d4b8
3 changed files with 112 additions and 2 deletions

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
@ -92,14 +93,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
// Backpressure, stop controlling incoming data rate until data is read.
backpressure = true;
_context.TimeoutControl.PauseTimingReads();
TryPauseTimingReads();
}
await writeAwaitable;
if (backpressure)
{
_context.TimeoutControl.ResumeTimingReads();
TryResumeTimingReads();
}
if (done)
@ -266,6 +267,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
}
private void TryPauseTimingReads()
{
if (!RequestUpgrade)
{
_context.TimeoutControl.PauseTimingReads();
}
}
private void TryResumeTimingReads()
{
if (!RequestUpgrade)
{
_context.TimeoutControl.ResumeTimingReads();
}
}
private void TryStopTimingReads()
{
if (!RequestUpgrade)

View File

@ -647,6 +647,29 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
}
[Fact]
public async Task PausesAndResumesRequestBodyTimeoutOnBackpressure()
{
using (var input = new TestInput())
{
var mockTimeoutControl = new Mock<ITimeoutControl>();
input.FrameContext.TimeoutControl = mockTimeoutControl.Object;
var body = MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders { HeaderContentLength = "12" }, input.Frame);
// Add some input and read it to start PumpAsync
input.Add("hello,");
Assert.Equal(6, await body.ReadAsync(new ArraySegment<byte>(new byte[6])));
input.Add(" world");
Assert.Equal(6, await body.ReadAsync(new ArraySegment<byte>(new byte[6])));
// Due to the limits set on Frame.RequestBodyPipe, backpressure should be triggered on every write to that pipe.
mockTimeoutControl.Verify(timeoutControl => timeoutControl.PauseTimingReads(), Times.Exactly(2));
mockTimeoutControl.Verify(timeoutControl => timeoutControl.ResumeTimingReads(), Times.Exactly(2));
}
}
[Fact]
public async Task OnlyEnforcesRequestBodyTimeoutAfterSending100Continue()
{
@ -700,6 +723,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
mockTimeoutControl.Verify(timeoutControl => timeoutControl.StartTimingReads(), Times.Never);
mockTimeoutControl.Verify(timeoutControl => timeoutControl.StopTimingReads(), Times.Never);
// Due to the limits set on Frame.RequestBodyPipe, backpressure should be triggered on every
// write to that pipe. Verify that read timing pause and resume are not called on upgrade
// requests.
mockTimeoutControl.Verify(timeoutControl => timeoutControl.PauseTimingReads(), Times.Never);
mockTimeoutControl.Verify(timeoutControl => timeoutControl.ResumeTimingReads(), Times.Never);
}
}

View File

@ -17,7 +17,9 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
@ -1415,6 +1417,68 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
}
}
[Fact]
public async Task DoesNotEnforceRequestBodyMinimumDataRateOnUpgradedRequest()
{
var appEvent = new ManualResetEventSlim();
var delayEvent = new ManualResetEventSlim();
var serviceContext = new TestServiceContext
{
SystemClock = new SystemClock()
};
using (var server = new TestServer(async context =>
{
context.Features.Get<IHttpRequestBodyMinimumDataRateFeature>().MinimumDataRate = new MinimumDataRate(rate: double.MaxValue, gracePeriod: TimeSpan.Zero);
using (var stream = await context.Features.Get<IHttpUpgradeFeature>().UpgradeAsync())
{
appEvent.Set();
// Read once to go through one set of TryPauseTimingReads()/TryResumeTimingReads() calls
await stream.ReadAsync(new byte[1], 0, 1);
delayEvent.Wait();
// Read again to check that the connection is still alive
await stream.ReadAsync(new byte[1], 0, 1);
// Send a response to distinguish from the timeout case where the 101 is still received, but without any content
var response = Encoding.ASCII.GetBytes("hello");
await stream.WriteAsync(response, 0, response.Length);
}
}, serviceContext))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"Host:",
"Connection: upgrade",
"",
"a");
Assert.True(appEvent.Wait(TimeSpan.FromSeconds(10)));
await Task.Delay(TimeSpan.FromSeconds(5));
delayEvent.Set();
await connection.Send("b");
await connection.Receive(
"HTTP/1.1 101 Switching Protocols",
"Connection: Upgrade",
"");
await connection.ReceiveStartsWith(
$"Date: ");
await connection.ReceiveForcedEnd(
"",
"hello");
}
}
}
private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress)
{
var builder = new WebHostBuilder()