From 9f728e254511b6cb68817b1de983c729d8125931 Mon Sep 17 00:00:00 2001 From: Bruno Blanes Date: Fri, 25 Nov 2022 22:37:26 -0300 Subject: [PATCH 1/7] Add test for literal field without name reference --- .../tests/UnitTests/QPack/QPackDecoderTest.cs | 56 +++++++++++++++++++ .../System.Net.Http.Unit.Tests.csproj | 5 ++ 2 files changed, 61 insertions(+) create mode 100644 src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs diff --git a/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs new file mode 100644 index 0000000000000..c4479092ebfd7 --- /dev/null +++ b/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using System.Net.Http.QPack; +using System.Net.Http.Unit.Tests.HPack; +using System.Text; + +using Xunit; + +namespace System.Net.Http.Unit.Tests.QPack +{ + public class QPackDecoderTest + { + private const int MaxHeaderFieldSize = 8190; + + // 4.5.6 - Literal Field Without Name Reference - (literal-header-field) + private static readonly byte[] _literalFieldWithoutNameReference = new byte[] { 0x37, 0x0d, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x66, 0x69, 0x65, 0x6c, 0x64 }; + + private const string _headerNameString = "literal-header-field"; + private const string _headerValueString = "should-not-break"; + + private static readonly byte[] _headerValueBytes = Encoding.ASCII.GetBytes(_headerValueString); + + private static readonly byte[] _headerValue = new byte[] { (byte)_headerValueBytes.Length } + .Concat(_headerValueBytes) + .ToArray(); + + private readonly QPackDecoder _decoder; + private readonly TestHttpHeadersHandler _handler = new TestHttpHeadersHandler(); + + public QPackDecoderTest() + { + _decoder = new QPackDecoder(MaxHeaderFieldSize); + } + + [Fact] + public void DecodesLiteralField_WithoutNameReferece() + { + // The key take away here is that the header name length should be bigger than 16 bytes + // and the header value length less than or equal to 16 bytes and they cannot all be + // read at once, they must be broken into separate buffers + byte[] encoded = _literalFieldWithoutNameReference + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^7], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^7..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); + Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index 85139c5391ff8..171e13d583b1c 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -325,6 +325,7 @@ + @@ -393,8 +394,12 @@ Link="Common\System\Net\Http\aspnetcore\Http3\QPack\HeaderField.cs" /> + + Date: Fri, 25 Nov 2022 22:38:17 -0300 Subject: [PATCH 2/7] Fix header name buffer allocation --- .../System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs index 47fc89aaa5d9d..ea575da49391f 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs @@ -243,12 +243,11 @@ private void DecodeInternal(ReadOnlySpan data, IHttpStreamHeadersHandler h // will no longer be valid. if (_headerNameRange != null) { - EnsureStringCapacity(ref _headerNameOctets, _stringLength, existingLength: 0); + EnsureStringCapacity(ref _headerNameOctets, _headerNameLength, existingLength: 0); _headerName = _headerNameOctets; ReadOnlySpan headerBytes = data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length); headerBytes.CopyTo(_headerName); - _headerNameLength = headerBytes.Length; _headerNameRange = null; } } @@ -294,6 +293,7 @@ private void ParseHeaderName(ReadOnlySpan data, ref int currentIndex, IHtt { // Fast path. Store the range rather than copying. _headerNameRange = (start: currentIndex, count); + _headerNameLength = _stringLength; currentIndex += count; _state = State.HeaderValueLength; From c456ff590176c2da83a5e23ea58f0212ead207a6 Mon Sep 17 00:00:00 2001 From: Bruno Blanes Date: Sat, 26 Nov 2022 22:05:06 -0300 Subject: [PATCH 3/7] Add more tests --- .../tests/UnitTests/QPack/QPackDecoderTest.cs | 82 ++++++++++++++++--- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs index c4479092ebfd7..6a8a5c4b1848a 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs @@ -17,8 +17,8 @@ public class QPackDecoderTest // 4.5.6 - Literal Field Without Name Reference - (literal-header-field) private static readonly byte[] _literalFieldWithoutNameReference = new byte[] { 0x37, 0x0d, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x66, 0x69, 0x65, 0x6c, 0x64 }; - private const string _headerNameString = "literal-header-field"; - private const string _headerValueString = "should-not-break"; + private const string _headerNameString = "literal-header-field"; // 20 bytes + private const string _headerValueString = "should-not-break"; // 16 bytes private static readonly byte[] _headerValueBytes = Encoding.ASCII.GetBytes(_headerValueString); @@ -26,6 +26,13 @@ public class QPackDecoderTest .Concat(_headerValueBytes) .ToArray(); + // The key take away here is that the header name length should be + // at least 2^n + 1 and the header value length less than or equal to 2^n. + // This is due to how System.Buffer buckets the arrays to be used by the decoder. + private static readonly byte[] _encodedLiteralField = _literalFieldWithoutNameReference + .Concat(_headerValue) + .ToArray(); + private readonly QPackDecoder _decoder; private readonly TestHttpHeadersHandler _handler = new TestHttpHeadersHandler(); @@ -35,18 +42,71 @@ public QPackDecoderTest() } [Fact] - public void DecodesLiteralField_WithoutNameReferece() + public void LiteralFieldWithoutNameReferece_SingleBuffer() + { + _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField, endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); + Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_NameLengthBrokenIntoSeparateBuffers() + { + _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[..1], endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[1..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); + Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_NameBrokenIntoSeparateBuffers() + { + _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[..(_headerNameString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[(_headerNameString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); + Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_NameAndValueBrokenIntoSeparateBuffers() { - // The key take away here is that the header name length should be bigger than 16 bytes - // and the header value length less than or equal to 16 bytes and they cannot all be - // read at once, they must be broken into separate buffers - byte[] encoded = _literalFieldWithoutNameReference - .Concat(_headerValue) - .ToArray(); + _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[..^_headerValue.Length], endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[^_headerValue.Length..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); + Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); + } + [Fact] + // Ideally should be ran with a value length of or bigger than 2 bytes + public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers() + { + _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[..^(_headerValue.Length - 1)], endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); + Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_ValueBrokenIntoSeparateBuffers() + { _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(encoded[..^7], endHeaders: false, handler: _handler); - _decoder.Decode(encoded[^7..], endHeaders: true, handler: _handler); + _decoder.Decode(_encodedLiteralField[..^(_headerValueString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(_encodedLiteralField[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); From 2838c304ca957a31d1763d0babc42948ab96fb7f Mon Sep 17 00:00:00 2001 From: Bruno Blanes Date: Wed, 14 Dec 2022 20:36:16 -0300 Subject: [PATCH 4/7] Unified QPackDecoderTest test files --- .../Net/aspnetcore/Http3/QPackDecoderTest.cs | 102 ++++++++++++++- .../tests/UnitTests/QPack/QPackDecoderTest.cs | 116 ------------------ .../System.Net.Http.Unit.Tests.csproj | 3 +- 3 files changed, 101 insertions(+), 120 deletions(-) delete mode 100644 src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs index 475fddeab09bd..26452531a1814 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs @@ -25,11 +25,11 @@ public class QPackDecoderTests // 4.5.4 - Literal Header Field With Name Reference - Static Table - Index 44 (content-type) private static readonly byte[] _literalHeaderFieldWithNameReferenceStatic = new byte[] { 0x5f, 0x1d }; - // 4.5.6 - Literal Field Line With Literal Name - (translate) - private static readonly byte[] _literalFieldLineWithLiteralName = new byte[] { 0x37, 0x02, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65 }; + // 4.5.6 - Literal Field Line With Literal Name - (literal-header-field) + private static readonly byte[] _literalFieldLineWithLiteralName = new byte[] { 0x37, 0x0d, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x66, 0x69, 0x65, 0x6c, 0x64 }; private const string _contentTypeString = "content-type"; - private const string _translateString = "translate"; + private const string _translateString = "literal-header-field"; // n e w - h e a d e r * // 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111 @@ -173,6 +173,102 @@ public void DecodesLiteralFieldLineWithLiteralName_LargeValues() }); } + [Fact] + public void LiteralFieldWithoutNameReferece_SingleBuffer() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded, endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_NameLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..1], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_NameBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..(_headerNameString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[(_headerNameString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_NameAndValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^_headerValue.Length], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^_headerValue.Length..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + } + + [Fact] + // Ideally should be ran with a value length of or bigger than 2 bytes + public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^(_headerValue.Length - 1)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + } + + [Fact] + public void LiteralFieldWithoutNameReferece_ValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^(_headerValueString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + } + public static readonly TheoryData _incompleteHeaderBlockData = new TheoryData { // Incomplete header diff --git a/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs deleted file mode 100644 index 6a8a5c4b1848a..0000000000000 --- a/src/libraries/System.Net.Http/tests/UnitTests/QPack/QPackDecoderTest.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Linq; -using System.Net.Http.QPack; -using System.Net.Http.Unit.Tests.HPack; -using System.Text; - -using Xunit; - -namespace System.Net.Http.Unit.Tests.QPack -{ - public class QPackDecoderTest - { - private const int MaxHeaderFieldSize = 8190; - - // 4.5.6 - Literal Field Without Name Reference - (literal-header-field) - private static readonly byte[] _literalFieldWithoutNameReference = new byte[] { 0x37, 0x0d, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x66, 0x69, 0x65, 0x6c, 0x64 }; - - private const string _headerNameString = "literal-header-field"; // 20 bytes - private const string _headerValueString = "should-not-break"; // 16 bytes - - private static readonly byte[] _headerValueBytes = Encoding.ASCII.GetBytes(_headerValueString); - - private static readonly byte[] _headerValue = new byte[] { (byte)_headerValueBytes.Length } - .Concat(_headerValueBytes) - .ToArray(); - - // The key take away here is that the header name length should be - // at least 2^n + 1 and the header value length less than or equal to 2^n. - // This is due to how System.Buffer buckets the arrays to be used by the decoder. - private static readonly byte[] _encodedLiteralField = _literalFieldWithoutNameReference - .Concat(_headerValue) - .ToArray(); - - private readonly QPackDecoder _decoder; - private readonly TestHttpHeadersHandler _handler = new TestHttpHeadersHandler(); - - public QPackDecoderTest() - { - _decoder = new QPackDecoder(MaxHeaderFieldSize); - } - - [Fact] - public void LiteralFieldWithoutNameReferece_SingleBuffer() - { - _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField, endHeaders: true, handler: _handler); - - Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); - Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); - } - - [Fact] - public void LiteralFieldWithoutNameReferece_NameLengthBrokenIntoSeparateBuffers() - { - _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[..1], endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[1..], endHeaders: true, handler: _handler); - - Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); - Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); - } - - [Fact] - public void LiteralFieldWithoutNameReferece_NameBrokenIntoSeparateBuffers() - { - _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[..(_headerNameString.Length / 2)], endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[(_headerNameString.Length / 2)..], endHeaders: true, handler: _handler); - - Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); - Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); - } - - [Fact] - public void LiteralFieldWithoutNameReferece_NameAndValueBrokenIntoSeparateBuffers() - { - _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[..^_headerValue.Length], endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[^_headerValue.Length..], endHeaders: true, handler: _handler); - - Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); - Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); - } - - [Fact] - // Ideally should be ran with a value length of or bigger than 2 bytes - public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers() - { - _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[..^(_headerValue.Length - 1)], endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); - - Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); - Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); - } - - [Fact] - public void LiteralFieldWithoutNameReferece_ValueBrokenIntoSeparateBuffers() - { - _decoder.Decode(new byte[] { 0, 0 }, endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[..^(_headerValueString.Length / 2)], endHeaders: false, handler: _handler); - _decoder.Decode(_encodedLiteralField[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); - - Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.Equal(_headerNameString, _handler.DecodedHeaders.Keys.First()); - Assert.Equal(_headerValueString, _handler.DecodedHeaders.Values.First()); - } - } -} diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index 171e13d583b1c..0c06f6eb21f19 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -322,10 +322,11 @@ Link="HPack\HPackIntegerTest.cs" /> + - From 7f0239a3dbb4322d9bde1725d30cb8b551271546 Mon Sep 17 00:00:00 2001 From: Bruno Blanes Date: Thu, 15 Dec 2022 01:02:28 -0300 Subject: [PATCH 5/7] Fix variable name --- .../Net/aspnetcore/Http3/QPackDecoderTest.cs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs index 26452531a1814..2b67db07458a9 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs @@ -29,7 +29,7 @@ public class QPackDecoderTests private static readonly byte[] _literalFieldLineWithLiteralName = new byte[] { 0x37, 0x0d, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x66, 0x69, 0x65, 0x6c, 0x64 }; private const string _contentTypeString = "content-type"; - private const string _translateString = "literal-header-field"; + private const string _literalHeaderFieldString = "literal-header-field"; // n e w - h e a d e r * // 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111 @@ -97,7 +97,7 @@ public void DecodesLiteralFieldLineWithLiteralName_Value() .Concat(_headerValue) .ToArray(); - TestDecodeWithoutIndexing(encoded, _translateString, _headerValueString); + TestDecodeWithoutIndexing(encoded, _literalHeaderFieldString, _headerValueString); } [Fact] @@ -140,7 +140,7 @@ public void DecodesLiteralFieldLineWithLiteralName_HuffmanEncodedValue() .Concat(_headerValueHuffman) .ToArray(); - TestDecodeWithoutIndexing(encoded, _translateString, _headerValueString); + TestDecodeWithoutIndexing(encoded, _literalHeaderFieldString, _headerValueString); } [Fact] @@ -184,8 +184,8 @@ public void LiteralFieldWithoutNameReferece_SingleBuffer() _decoder.Decode(encoded, endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); - Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } [Fact] @@ -200,8 +200,8 @@ public void LiteralFieldWithoutNameReferece_NameLengthBrokenIntoSeparateBuffers( _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); - Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } [Fact] @@ -212,12 +212,12 @@ public void LiteralFieldWithoutNameReferece_NameBrokenIntoSeparateBuffers() .ToArray(); _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); - _decoder.Decode(encoded[..(_headerNameString.Length / 2)], endHeaders: false, handler: _handler); - _decoder.Decode(encoded[(_headerNameString.Length / 2)..], endHeaders: true, handler: _handler); + _decoder.Decode(encoded[..(_literalHeaderFieldString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[(_literalHeaderFieldString.Length / 2)..], endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); - Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } [Fact] @@ -232,12 +232,11 @@ public void LiteralFieldWithoutNameReferece_NameAndValueBrokenIntoSeparateBuffer _decoder.Decode(encoded[^_headerValue.Length..], endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); - Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } [Fact] - // Ideally should be ran with a value length of or bigger than 2 bytes public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers() { byte[] encoded = _literalFieldLineWithLiteralName @@ -249,8 +248,8 @@ public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers _decoder.Decode(encoded[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); - Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } [Fact] @@ -265,8 +264,8 @@ public void LiteralFieldWithoutNameReferece_ValueBrokenIntoSeparateBuffers() _decoder.Decode(encoded[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); Assert.Equal(1, _handler.DecodedHeaders.Count); - Assert.True(_handler.DecodedHeaders.ContainsKey(_translateString)); - Assert.Equal(_headerValueString, _handler.DecodedHeaders[_translateString]); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } public static readonly TheoryData _incompleteHeaderBlockData = new TheoryData From 4c4413cc0d701df86b340a93df005321229f8074 Mon Sep 17 00:00:00 2001 From: ManickaP Date: Thu, 13 Apr 2023 15:24:56 +0200 Subject: [PATCH 6/7] Fixed HPackDecoder and ported QPack tests --- .../aspnetcore/Http2/Hpack/HPackDecoder.cs | 11 +- .../Net/aspnetcore/Http2/HPackDecoderTest.cs | 106 ++++++++++++++++++ .../Net/aspnetcore/Http3/QPackDecoderTest.cs | 14 +-- 3 files changed, 119 insertions(+), 12 deletions(-) diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs index fb8739999a57f..1f9083e296459 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs @@ -187,12 +187,11 @@ private void DecodeInternal(ReadOnlySpan data, IHttpStreamHeadersHandler h // will no longer be valid. if (_headerNameRange != null) { - EnsureStringCapacity(ref _headerNameOctets); + EnsureStringCapacity(ref _headerNameOctets, _headerNameLength); _headerName = _headerNameOctets; ReadOnlySpan headerBytes = data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length); headerBytes.CopyTo(_headerName); - _headerNameLength = headerBytes.Length; _headerNameRange = null; } } @@ -427,6 +426,7 @@ private void ParseHeaderName(ReadOnlySpan data, ref int currentIndex, IHtt { // Fast path. Store the range rather than copying. _headerNameRange = (start: currentIndex, count); + _headerNameLength = _stringLength; currentIndex += count; _state = State.HeaderValueLength; @@ -621,11 +621,12 @@ int Decode(ref byte[] dst) _state = nextState; } - private void EnsureStringCapacity(ref byte[] dst) + private void EnsureStringCapacity(ref byte[] dst, int stringLength = -1) { - if (dst.Length < _stringLength) + stringLength = stringLength >= 0 ? stringLength : _stringLength; + if (dst.Length < stringLength) { - dst = new byte[Math.Max(_stringLength, Math.Min(dst.Length * 2, _maxHeadersLength))]; + dst = new byte[Math.Max(stringLength, Math.Min(dst.Length * 2, _maxHeadersLength))]; } } diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs index b7f4c19072a65..e35f04d3e22ea 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs @@ -46,8 +46,13 @@ public class HPackDecoderTests private const string _headerNameString = "new-header"; + // On purpose longer than 4096 (DefaultStringOctetsSize from HPackDecoder) to trigger https://github.com/dotnet/runtime/issues/78516 + private const string _literalHeaderNameString = "maxbomsahbxpcyggvaewnvxlddobkmxztwvrxzqksgxgqtozjlwepmpeidrqzmnuvenayslamvnepyibqtstxdtytirkuqqywyaabjgwkbrzftzoumgnjaksbwhkmoanlmtdftvbxbzojvgyfougzvqddqyzmufynhmbsbbwpldjtnyrislsnggqsyycrngnrihmuatgeplsdnnfquqiemuajryhtotmehcpqhgbzqcrfjozhysqeilzwvvzindrhcpujjsbovxbamhueacvogemoiffhbilzjjvwgxiqvaxlrrjmhervnxlqzmticyyjslxtlataicbchsyhidgqhqmvyrupxrwtuwylztpoajsrkzckjsvkoiloyzoijmtyaucckqtrybujqepsrcvukciahpaodfqafedfrzmreudbnpbhmsdplluxnsiuhqymidnrxxxlkxgibfyiymvqsmajxgytfyisjmokgncbzudkwrgdpzrwuddwabvriitdxhzypeujuewdapnxnnqiggxmjyfprdfohystyxayntnhhcltmyciabbpcnrokotuelbduiykcfqbbpfhibwjjoesfyjgbysktqexdivxfhshermjrsnbmizvxdzhvtczqifeczlivnpojhozqjacktxdielarunhvnvklthoywwowvpfiummgfxfsfxzjhojcnxijyvbhcrqirnxmizjkbirgnbrmehkcmqnkcscofhrarqsydqstsdwhbuqspjwhpkfgckeeeyegpbvhfzficzasrjsoviruxzzebddvfjfetolylwxqcoidbmdszmqmkcwwtxmdkjuonsjoktwoupxqgxorgvvnbjrfgbpbitaimpiznmjxnutvjopgpobzuhzkbtbhgyhqhzzjzdnutatnkhuqofwdkwscpmdhgcpchupgijamhbncztidtmdxyggefktbxgdxbryycytypcdywshlowceosdedduxmcjnkynohakhtwmjjbzrvijvadkwrylhdjlbtvzechjwnqpxrriotofnadqmcellqeddeoruldneomyomawanbbriqhntzvzucrjylajcflgrobkimcetoswbhksjqzhxchommkiymvlypejakdesheityoemvclzmxgrzdbezhzvgbkzmxvdoggnqxpumsskbnsfsadbyvecnnrwqcjvkttfucpaigumlbwqdunaguxcgojwuarrkflyqeytqvbooqimmibcroirufqlauaitseeyiymusvdyfgmwnwnakuphodxhuouwelluyeaaxhwsusvgctpcdbmszupumqnlixunfbtlhbugalhqcowzpqrysnrwmiavamqcrllifhzhjuqljtxynwsyjhxefkyognkzzdowoorpazajujvwjzonwkpsjqqtodpjkfodbiuulkhzjfeuijohnprouwxomiyqrcvzmfasrazukyrfjzwirfgzwqtztitrckoomoovlejdgdvsppdjcdvwtvjmorvyretbcmehlcpknyyyqfvhjxcsxjwpdbjbzytvfsaqjhsdolspqcwapvfircvmkvetkngsjzxqgpavfsxenrquocbiticvhssvaijlplbcjbblzjldzqfmvoylaqfcvphunhxtjedslxrvfputxaynwvsixagbeklwifxuucnxsdhokxhwbipkgdnuumkiiesmhgcgexoomtipiivkpmyeigxrkwovuxjtpjgjatatlvzgxqvmbxxfhngoyankjzdckuqeifysmxusihegqopgeyyrfclagpakehiovydzhdziloeklspsgbcyodtubqpinlqbkzievzjypzzikdllnofnbxngcokdkcfebjukzipyviesrbbfbnajwplesahinsxpqjpkjcoefgcpqnoxfwfvlfoebthzkehwktwlemrddflflrqfokewcozbtodzxymilklrfmrtfoooamqdytjdprmnuzeypwsclgbwihjdlgnthvidxsditcbidrswgbkrktpprwhdtjhknvwqwqzphzszbdnzgyezoroabgwmqrqhpgfmqtgwucakgbfivblnytwngwrqsfygltvhtwutrkqzjykslgrfuxnliqqgubkafiivykskslypvtopwqobjhqazzqjbojglacqwwcqurlnqlkwipqmimrmogqxpznrevgdgfgoahrvngqwhsdptsbxrytalpkdogmogcbqxayqhzxmuftsghipqkbzjiooyjvhlpmqzdmsieofluclkqnxqnsrhzzkhlyjwwbbzrtweezzsxxrexbjlqkvfptybmukljhrrpmtrxcvmmahhehtvdlilkuxpvgwpvmiycoffodlomzeyimupsrsyowgrqxynsyeiqorhejfdqzxrcilflqrcfftojglxaskdupctkqgorwuzwpxynvufajjarisbpxgyudqyjugenlqmcqagluwcmlgnqmrscpnifledaxhxbnjzclmzzolidklaqwhyxtyrpixgpgmiciqllcayvnlwfxiwjxyxxigkntflrxovywbdlofszuoumvyxtorwdhfkprwaxkmirmgrjzgmppjolxvpckchqzloatsryufrkohjqmysvkkyhpduagxeculifhleulzanaiauritfdeniiduphzpllaiiqivmvocrlwosobnyngeoyhjfyjplmlldsoxonrfivmuelfjqiuvckqlyaoemqtkmsdharktwwbsfzteplljqxbimimbuaxprytnvvlywdvfkyluektusgfdaldqtirvmjgbyssmxgrbpegsudejihvxztxyrpdjbezzlzdtdfwzwnlplsobnyguduodulezdfsoyrkmufyrgynjqhlddvwbcljscchamyasvzvjbxfxwkvqywtcpqehnswsiiqtsspwudbhbaqlyerjxyupsurvxhhbolfsxckikclytbltywqkzcoeviaqrjobceyssgfciztpaffbmdqgkwilqnytgjipmgejadrkrabqywipuujvpbjvlsdlezjftzcksvzstifjappdbibiemdceorvxwkgkhnzlmirkazcolmmnvijdxjaicxcidpkempwqwcimbwvwghikutmsbtwwbkbksidjxujqcerftrhmlllkqfuxhbxcvegfrxuvvelsfndazyjdfocovypryvjsfnqkfsebtfppvkouvhvqeobwjacjbqjxqekpfisojfmpyzyuxwksotplqwgajsskxtflomwdrrssvkbfmtdthxjridumzdubjdrcxnjmpokjxvtxelxmxyjrlnaqusgzbwqsrgkmdyzxrmxkkrnxmbyhgjzuqyckqgnpxtiavcbhagqmephgzpjbrrizknmqtijgqmlkaclzatznipopzcltrsuyvpqeuooyxyedmbqwituobjxtucsxcdqijyfwqrahdoppejtckzpqilxmgbwkfuktxkezlcklpalvmxwajxyictwvxitqhlgzkilzlscvxudruzfeuffefbkkmouqvbkcluozrktxdlxwpdrhsiuuhnkrwanofuahqzcimujqhajtvmlvbuclwfgcmizcnaapjvydkcroesqxtmjvzswdrnsywyjkwbpycsfsltpfcvgnauldkehrpbyewbuvvemucdlrbfchetcywcnpppcxjkmldrnnozmlmnetinhjfdturwkchedzyvgtjdkdghoxrhztqvwrxfjtkenzxujefalvsbnlatxtbuuzwilrhszuodabuqopouytanabhhfbdqhsbdbcuujhpurttnkfpbzhbjazkynbjnlmmofzinrqdxhlhvclzlelryyvtmcqfnkqiaqcghvddmzejcwmqwfpxyglkmtropfcfbuksvxobsnmblvnezvkclidgaoeqtlgvdoyxwncotbetvarjhbfonkfxzqntygcfshwaqropcxefvgflbmsycgdapqehpmymxtbtwaaaqyvecsislwccpiedkunbiblybhksiliiwidxzipis"; + private static readonly byte[] _headerNameBytes = Encoding.ASCII.GetBytes(_headerNameString); + private static readonly byte[] _literalHeaderNameBytes = Encoding.ASCII.GetBytes(_literalHeaderNameString); + // n e w - h e a d e r * // 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111 private static readonly byte[] _headerNameHuffmanBytes = new byte[] { 0xa8, 0xbe, 0x16, 0x9c, 0xa3, 0x90, 0xb6, 0x7f }; @@ -64,6 +69,12 @@ public class HPackDecoderTests .Concat(_headerNameBytes) .ToArray(); + // size = 4096 ==> 0x7f, 0x81, 0x1f (7+) prefixed integer + // size = 4100 ==> 0x7f, 0x85, 0x1f (7+) prefixed integer + private static readonly byte[] _literalHeaderName = new byte[] { 0x7f, 0x85, 0x1f } // 4100 + .Concat(_literalHeaderNameBytes) + .ToArray(); + private static readonly byte[] _headerNameHuffman = new byte[] { (byte)(0x80 | _headerNameHuffmanBytes.Length) } .Concat(_headerNameHuffmanBytes) .ToArray(); @@ -392,6 +403,101 @@ public void DecodesLiteralHeaderFieldNeverIndexed_IndexedName_OutOfRange_Error() Assert.Empty(_handler.DecodedHeaders); } + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_SingleBuffer() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded, endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..1], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..(_literalHeaderNameString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[(_literalHeaderNameString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameAndValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..^_headerValue.Length], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^_headerValue.Length..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..^(_headerValue.Length - 1)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..^(_headerValueString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + [Fact] public void DecodesDynamicTableSizeUpdate() { diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs index 2b67db07458a9..8db70d84ee05e 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs @@ -174,7 +174,7 @@ public void DecodesLiteralFieldLineWithLiteralName_LargeValues() } [Fact] - public void LiteralFieldWithoutNameReferece_SingleBuffer() + public void LiteralFieldWithoutNameReference_SingleBuffer() { byte[] encoded = _literalFieldLineWithLiteralName .Concat(_headerValue) @@ -189,7 +189,7 @@ public void LiteralFieldWithoutNameReferece_SingleBuffer() } [Fact] - public void LiteralFieldWithoutNameReferece_NameLengthBrokenIntoSeparateBuffers() + public void LiteralFieldWithoutNameReference_NameLengthBrokenIntoSeparateBuffers() { byte[] encoded = _literalFieldLineWithLiteralName .Concat(_headerValue) @@ -205,7 +205,7 @@ public void LiteralFieldWithoutNameReferece_NameLengthBrokenIntoSeparateBuffers( } [Fact] - public void LiteralFieldWithoutNameReferece_NameBrokenIntoSeparateBuffers() + public void LiteralFieldWithoutNameReference_NameBrokenIntoSeparateBuffers() { byte[] encoded = _literalFieldLineWithLiteralName .Concat(_headerValue) @@ -221,7 +221,7 @@ public void LiteralFieldWithoutNameReferece_NameBrokenIntoSeparateBuffers() } [Fact] - public void LiteralFieldWithoutNameReferece_NameAndValueBrokenIntoSeparateBuffers() + public void LiteralFieldWithoutNameReference_NameAndValueBrokenIntoSeparateBuffers() { byte[] encoded = _literalFieldLineWithLiteralName .Concat(_headerValue) @@ -237,7 +237,7 @@ public void LiteralFieldWithoutNameReferece_NameAndValueBrokenIntoSeparateBuffer } [Fact] - public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers() + public void LiteralFieldWithoutNameReference_ValueLengthBrokenIntoSeparateBuffers() { byte[] encoded = _literalFieldLineWithLiteralName .Concat(_headerValue) @@ -253,7 +253,7 @@ public void LiteralFieldWithoutNameReferece_ValueLengthBrokenIntoSeparateBuffers } [Fact] - public void LiteralFieldWithoutNameReferece_ValueBrokenIntoSeparateBuffers() + public void LiteralFieldWithoutNameReference_ValueBrokenIntoSeparateBuffers() { byte[] encoded = _literalFieldLineWithLiteralName .Concat(_headerValue) @@ -267,7 +267,7 @@ public void LiteralFieldWithoutNameReferece_ValueBrokenIntoSeparateBuffers() Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } - + public static readonly TheoryData _incompleteHeaderBlockData = new TheoryData { // Incomplete header From 8fc8fdc1ae3ad949f896511d0e61a28db213e8a9 Mon Sep 17 00:00:00 2001 From: ManickaP Date: Thu, 13 Apr 2023 16:04:26 +0200 Subject: [PATCH 7/7] Feedback --- .../tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs index e35f04d3e22ea..0e94e8c7c6d6e 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs @@ -47,7 +47,7 @@ public class HPackDecoderTests private const string _headerNameString = "new-header"; // On purpose longer than 4096 (DefaultStringOctetsSize from HPackDecoder) to trigger https://github.com/dotnet/runtime/issues/78516 - private const string _literalHeaderNameString = "maxbomsahbxpcyggvaewnvxlddobkmxztwvrxzqksgxgqtozjlwepmpeidrqzmnuvenayslamvnepyibqtstxdtytirkuqqywyaabjgwkbrzftzoumgnjaksbwhkmoanlmtdftvbxbzojvgyfougzvqddqyzmufynhmbsbbwpldjtnyrislsnggqsyycrngnrihmuatgeplsdnnfquqiemuajryhtotmehcpqhgbzqcrfjozhysqeilzwvvzindrhcpujjsbovxbamhueacvogemoiffhbilzjjvwgxiqvaxlrrjmhervnxlqzmticyyjslxtlataicbchsyhidgqhqmvyrupxrwtuwylztpoajsrkzckjsvkoiloyzoijmtyaucckqtrybujqepsrcvukciahpaodfqafedfrzmreudbnpbhmsdplluxnsiuhqymidnrxxxlkxgibfyiymvqsmajxgytfyisjmokgncbzudkwrgdpzrwuddwabvriitdxhzypeujuewdapnxnnqiggxmjyfprdfohystyxayntnhhcltmyciabbpcnrokotuelbduiykcfqbbpfhibwjjoesfyjgbysktqexdivxfhshermjrsnbmizvxdzhvtczqifeczlivnpojhozqjacktxdielarunhvnvklthoywwowvpfiummgfxfsfxzjhojcnxijyvbhcrqirnxmizjkbirgnbrmehkcmqnkcscofhrarqsydqstsdwhbuqspjwhpkfgckeeeyegpbvhfzficzasrjsoviruxzzebddvfjfetolylwxqcoidbmdszmqmkcwwtxmdkjuonsjoktwoupxqgxorgvvnbjrfgbpbitaimpiznmjxnutvjopgpobzuhzkbtbhgyhqhzzjzdnutatnkhuqofwdkwscpmdhgcpchupgijamhbncztidtmdxyggefktbxgdxbryycytypcdywshlowceosdedduxmcjnkynohakhtwmjjbzrvijvadkwrylhdjlbtvzechjwnqpxrriotofnadqmcellqeddeoruldneomyomawanbbriqhntzvzucrjylajcflgrobkimcetoswbhksjqzhxchommkiymvlypejakdesheityoemvclzmxgrzdbezhzvgbkzmxvdoggnqxpumsskbnsfsadbyvecnnrwqcjvkttfucpaigumlbwqdunaguxcgojwuarrkflyqeytqvbooqimmibcroirufqlauaitseeyiymusvdyfgmwnwnakuphodxhuouwelluyeaaxhwsusvgctpcdbmszupumqnlixunfbtlhbugalhqcowzpqrysnrwmiavamqcrllifhzhjuqljtxynwsyjhxefkyognkzzdowoorpazajujvwjzonwkpsjqqtodpjkfodbiuulkhzjfeuijohnprouwxomiyqrcvzmfasrazukyrfjzwirfgzwqtztitrckoomoovlejdgdvsppdjcdvwtvjmorvyretbcmehlcpknyyyqfvhjxcsxjwpdbjbzytvfsaqjhsdolspqcwapvfircvmkvetkngsjzxqgpavfsxenrquocbiticvhssvaijlplbcjbblzjldzqfmvoylaqfcvphunhxtjedslxrvfputxaynwvsixagbeklwifxuucnxsdhokxhwbipkgdnuumkiiesmhgcgexoomtipiivkpmyeigxrkwovuxjtpjgjatatlvzgxqvmbxxfhngoyankjzdckuqeifysmxusihegqopgeyyrfclagpakehiovydzhdziloeklspsgbcyodtubqpinlqbkzievzjypzzikdllnofnbxngcokdkcfebjukzipyviesrbbfbnajwplesahinsxpqjpkjcoefgcpqnoxfwfvlfoebthzkehwktwlemrddflflrqfokewcozbtodzxymilklrfmrtfoooamqdytjdprmnuzeypwsclgbwihjdlgnthvidxsditcbidrswgbkrktpprwhdtjhknvwqwqzphzszbdnzgyezoroabgwmqrqhpgfmqtgwucakgbfivblnytwngwrqsfygltvhtwutrkqzjykslgrfuxnliqqgubkafiivykskslypvtopwqobjhqazzqjbojglacqwwcqurlnqlkwipqmimrmogqxpznrevgdgfgoahrvngqwhsdptsbxrytalpkdogmogcbqxayqhzxmuftsghipqkbzjiooyjvhlpmqzdmsieofluclkqnxqnsrhzzkhlyjwwbbzrtweezzsxxrexbjlqkvfptybmukljhrrpmtrxcvmmahhehtvdlilkuxpvgwpvmiycoffodlomzeyimupsrsyowgrqxynsyeiqorhejfdqzxrcilflqrcfftojglxaskdupctkqgorwuzwpxynvufajjarisbpxgyudqyjugenlqmcqagluwcmlgnqmrscpnifledaxhxbnjzclmzzolidklaqwhyxtyrpixgpgmiciqllcayvnlwfxiwjxyxxigkntflrxovywbdlofszuoumvyxtorwdhfkprwaxkmirmgrjzgmppjolxvpckchqzloatsryufrkohjqmysvkkyhpduagxeculifhleulzanaiauritfdeniiduphzpllaiiqivmvocrlwosobnyngeoyhjfyjplmlldsoxonrfivmuelfjqiuvckqlyaoemqtkmsdharktwwbsfzteplljqxbimimbuaxprytnvvlywdvfkyluektusgfdaldqtirvmjgbyssmxgrbpegsudejihvxztxyrpdjbezzlzdtdfwzwnlplsobnyguduodulezdfsoyrkmufyrgynjqhlddvwbcljscchamyasvzvjbxfxwkvqywtcpqehnswsiiqtsspwudbhbaqlyerjxyupsurvxhhbolfsxckikclytbltywqkzcoeviaqrjobceyssgfciztpaffbmdqgkwilqnytgjipmgejadrkrabqywipuujvpbjvlsdlezjftzcksvzstifjappdbibiemdceorvxwkgkhnzlmirkazcolmmnvijdxjaicxcidpkempwqwcimbwvwghikutmsbtwwbkbksidjxujqcerftrhmlllkqfuxhbxcvegfrxuvvelsfndazyjdfocovypryvjsfnqkfsebtfppvkouvhvqeobwjacjbqjxqekpfisojfmpyzyuxwksotplqwgajsskxtflomwdrrssvkbfmtdthxjridumzdubjdrcxnjmpokjxvtxelxmxyjrlnaqusgzbwqsrgkmdyzxrmxkkrnxmbyhgjzuqyckqgnpxtiavcbhagqmephgzpjbrrizknmqtijgqmlkaclzatznipopzcltrsuyvpqeuooyxyedmbqwituobjxtucsxcdqijyfwqrahdoppejtckzpqilxmgbwkfuktxkezlcklpalvmxwajxyictwvxitqhlgzkilzlscvxudruzfeuffefbkkmouqvbkcluozrktxdlxwpdrhsiuuhnkrwanofuahqzcimujqhajtvmlvbuclwfgcmizcnaapjvydkcroesqxtmjvzswdrnsywyjkwbpycsfsltpfcvgnauldkehrpbyewbuvvemucdlrbfchetcywcnpppcxjkmldrnnozmlmnetinhjfdturwkchedzyvgtjdkdghoxrhztqvwrxfjtkenzxujefalvsbnlatxtbuuzwilrhszuodabuqopouytanabhhfbdqhsbdbcuujhpurttnkfpbzhbjazkynbjnlmmofzinrqdxhlhvclzlelryyvtmcqfnkqiaqcghvddmzejcwmqwfpxyglkmtropfcfbuksvxobsnmblvnezvkclidgaoeqtlgvdoyxwncotbetvarjhbfonkfxzqntygcfshwaqropcxefvgflbmsycgdapqehpmymxtbtwaaaqyvecsislwccpiedkunbiblybhksiliiwidxzipis"; + private static readonly string _literalHeaderNameString = string.Concat(Enumerable.Range(0, 4100).Select(c => (char)('a' + (c % 26)))); private static readonly byte[] _headerNameBytes = Encoding.ASCII.GetBytes(_headerNameString);