From 343ce0f01bd26055af174e3eab88ef609ddecf95 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Thu, 21 Sep 2017 10:05:56 -0700 Subject: [PATCH] HTTP/2: close connection with PROTOCOL_ERROR when a stream depends on itself. --- .../Internal/Http2/Http2Connection.cs | 12 ++++++++-- .../Http2ConnectionTests.cs | 24 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs index 70ca7a28c4..3622686dfd 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.IO.Pipelines; using System.Text; using System.Threading.Tasks; @@ -13,7 +12,6 @@ using Microsoft.AspNetCore.Protocols; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; -using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 @@ -275,6 +273,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR); } + if (_incomingFrame.HeadersHasPriority && _incomingFrame.HeadersStreamDependency == _incomingFrame.StreamId) + { + throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR); + } + _currentHeadersStream = new Http2Stream(application, new Http2StreamContext { ConnectionId = ConnectionId, @@ -316,6 +319,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR); } + if (_incomingFrame.PriorityStreamDependency == _incomingFrame.StreamId) + { + throw new Http2ConnectionErrorException(Http2ErrorCode.PROTOCOL_ERROR); + } + if (_incomingFrame.Length != 5) { throw new Http2ConnectionErrorException(Http2ErrorCode.FRAME_SIZE_ERROR); diff --git a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs index 93515b1267..7b3a96221a 100644 --- a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs @@ -692,6 +692,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false); } + [Fact] + public async Task HEADERS_Received_WithPriority_StreamDependencyOnSelf_ConnectionError() + { + await InitializeConnectionAsync(_readHeadersApplication); + + await SendHeadersWithPriorityAsync(1, _browserRequestHeaders, priority: 42, streamDependency: 1, endStream: true); + + await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false); + } + [Fact] public async Task PRIORITY_Received_StreamIdZero_ConnectionError() { @@ -735,6 +745,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false); } + [Fact] + public async Task PRIORITY_Received_StreamDependencyOnSelf_ConnectionError() + { + await InitializeConnectionAsync(_readHeadersApplication); + + await SendPriorityAsync(1, streamDependency: 1); + + await WaitForConnectionErrorAsync(expectedLastStreamId: 0, expectedErrorCode: Http2ErrorCode.PROTOCOL_ERROR, ignoreNonGoAwayFrames: false); + } + [Fact] public async Task RST_STREAM_Received_AbortsStream() { @@ -1507,10 +1527,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests return SendAsync(pingFrame.Raw); } - private Task SendPriorityAsync(int streamId) + private Task SendPriorityAsync(int streamId, int streamDependency = 0) { var priorityFrame = new Http2Frame(); - priorityFrame.PreparePriority(streamId, streamDependency: 0, exclusive: false, weight: 0); + priorityFrame.PreparePriority(streamId, streamDependency: streamDependency, exclusive: false, weight: 0); return SendAsync(priorityFrame.Raw); }