diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/HPack/DynamicTable.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/HPack/DynamicTable.cs index a2181711a0..7183589021 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/HPack/DynamicTable.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/HPack/DynamicTable.cs @@ -5,6 +5,8 @@ using System; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack { + // The dynamic table is defined as a queue where items are inserted at the front and removed from the back. + // It's implemented as a circular buffer that appends to the end and trims from the front. Thus index are reversed. internal class DynamicTable { private HeaderField[] _buffer; @@ -35,7 +37,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.HPack throw new IndexOutOfRangeException(); } - return _buffer[_insertIndex == 0 ? _buffer.Length - 1 : _insertIndex - index - 1]; + var modIndex = _insertIndex - index - 1; + if (modIndex < 0) + { + modIndex += _buffer.Length; + } + + return _buffer[modIndex]; } } diff --git a/src/Servers/Kestrel/Core/test/DynamicTableTests.cs b/src/Servers/Kestrel/Core/test/DynamicTableTests.cs index 0943272c72..a7fb8520c6 100644 --- a/src/Servers/Kestrel/Core/test/DynamicTableTests.cs +++ b/src/Servers/Kestrel/Core/test/DynamicTableTests.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -58,6 +58,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests VerifyTableEntries(dynamicTable, _header2, _header1); } + [Fact] + public void WrapsAroundBuffer() + { + var header3 = new HeaderField(Encoding.ASCII.GetBytes("header-3"), Encoding.ASCII.GetBytes("value3")); + var header4 = new HeaderField(Encoding.ASCII.GetBytes("header-4"), Encoding.ASCII.GetBytes("value4")); + + // Make the table small enough that the circular buffer kicks in. + var dynamicTable = new DynamicTable(HeaderField.RfcOverhead * 3); + dynamicTable.Insert(header4.Name, header4.Value); + dynamicTable.Insert(header3.Name, header3.Value); + dynamicTable.Insert(_header2.Name, _header2.Value); + dynamicTable.Insert(_header1.Name, _header1.Value); + + VerifyTableEntries(dynamicTable, _header1, _header2); + } + [Fact] public void ThrowsIndexOutOfRangeException() {