Fix PipeReader consumption pattern [2.1]

This commit is contained in:
Stephen Halter 2018-05-31 11:27:38 -07:00 committed by GitHub
parent 65336fe9cb
commit 9e15b2bca4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 21 deletions

View File

@ -107,10 +107,6 @@ namespace PlatformBenchmarks
ThrowUnexpectedEndOfData(); ThrowUnexpectedEndOfData();
} }
} }
else if (result.IsCompleted)
{
break;
}
Reader.AdvanceTo(consumed, examined); Reader.AdvanceTo(consumed, examined);
@ -120,6 +116,10 @@ namespace PlatformBenchmarks
_state = State.StartLine; _state = State.StartLine;
} }
else if (result.IsCompleted)
{
break;
}
} }
} }

View File

@ -125,7 +125,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
readableBuffer.CopyTo(destination.Span); readableBuffer.CopyTo(destination.Span);
return count; return count;
} }
else if (result.IsCompleted)
if (result.IsCompleted)
{ {
return 0; return 0;
} }

View File

@ -87,7 +87,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
break; break;
} }
} }
else if (result.IsCompleted)
// Read() will have already have greedily consumed the entire request body if able.
if (result.IsCompleted)
{ {
// Treat any FIN from an upgraded request as expected. // Treat any FIN from an upgraded request as expected.
// It's up to higher-level consumer (i.e. WebSocket middleware) to determine // It's up to higher-level consumer (i.e. WebSocket middleware) to determine

View File

@ -57,7 +57,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
slice.CopyTo(buffer.Span); slice.CopyTo(buffer.Span);
return actual; return actual;
} }
else if (result.IsCompleted)
if (result.IsCompleted)
{ {
return 0; return 0;
} }
@ -96,7 +97,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
#endif #endif
} }
} }
else if (result.IsCompleted)
if (result.IsCompleted)
{ {
return; return;
} }

View File

@ -117,14 +117,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
try try
{ {
if (!readableBuffer.IsEmpty) if (!readableBuffer.IsEmpty && ParsePreface(readableBuffer, out consumed, out examined))
{ {
if (ParsePreface(readableBuffer, out consumed, out examined)) break;
{
break;
}
} }
else if (result.IsCompleted)
if (result.IsCompleted)
{ {
return; return;
} }
@ -149,13 +147,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
try try
{ {
if (!readableBuffer.IsEmpty) if (!readableBuffer.IsEmpty && Http2FrameReader.ReadFrame(readableBuffer, _incomingFrame, out consumed, out examined))
{ {
if (Http2FrameReader.ReadFrame(readableBuffer, _incomingFrame, out consumed, out examined)) Log.LogTrace($"Connection id {ConnectionId} received {_incomingFrame.Type} frame with flags 0x{_incomingFrame.Flags:x} and length {_incomingFrame.Length} for stream ID {_incomingFrame.StreamId}");
{ await ProcessFrameAsync<TContext>(application);
Log.LogTrace($"Connection id {ConnectionId} received {_incomingFrame.Type} frame with flags 0x{_incomingFrame.Flags:x} and length {_incomingFrame.Length} for stream ID {_incomingFrame.StreamId}");
await ProcessFrameAsync<TContext>(application);
}
} }
else if (result.IsCompleted) else if (result.IsCompleted)
{ {

View File

@ -99,7 +99,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal
writeReq = null; writeReq = null;
} }
} }
else if (result.IsCompleted)
if (result.IsCompleted)
{ {
break; break;
} }

View File

@ -1,14 +1,17 @@
// 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.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
using Xunit; using Xunit;
@ -634,6 +637,54 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
} }
} }
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ClosingConnectionMidChunkPrefixThrows(ListenOptions listenOptions)
{
var testContext = new TestServiceContext(LoggerFactory);
var readStartedTcs = new TaskCompletionSource<object>();
var exTcs = new TaskCompletionSource<BadHttpRequestException>();
using (var server = new TestServer(async httpContext =>
{
var readTask = httpContext.Request.Body.CopyToAsync(Stream.Null);
readStartedTcs.SetResult(null);
try
{
await readTask;
}
catch (BadHttpRequestException badRequestEx)
{
exTcs.TrySetResult(badRequestEx);
}
catch (Exception ex)
{
exTcs.SetException(ex);
}
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.SendAll(
"POST / HTTP/1.1",
"Host:",
"Transfer-Encoding: chunked",
"",
"1");
await readStartedTcs.Task.TimeoutAfter(TestConstants.DefaultTimeout);
connection.Socket.Shutdown(SocketShutdown.Send);
await connection.ReceiveEnd();
var badReqEx = await exTcs.Task.TimeoutAfter(TestConstants.DefaultTimeout);
Assert.Equal(RequestRejectionReason.UnexpectedEndOfRequestContent, badReqEx.Reason);
}
}
}
} }
} }