From e1f11dc3135edf927a600ff25737d9e70ac221f9 Mon Sep 17 00:00:00 2001 From: ManickaP Date: Fri, 28 Apr 2023 11:39:40 +0200 Subject: [PATCH 1/4] Fix HTTP/3 and HTTTP/2 header decoder buffer allocation --- .../runtime/Http2/Hpack/HPackDecoder.cs | 11 +- .../runtime/Http3/QPack/QPackDecoder.cs | 4 +- .../runtime/Http2/HPackDecoderTest.cs | 110 +++++++++++++++++- .../runtime/Http3/QPackDecoderTest.cs | 105 ++++++++++++++++- 4 files changed, 214 insertions(+), 16 deletions(-) diff --git a/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs b/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs index fb8739999a57..1f9083e29645 100644 --- a/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs +++ b/src/Shared/runtime/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/Shared/runtime/Http3/QPack/QPackDecoder.cs b/src/Shared/runtime/Http3/QPack/QPackDecoder.cs index 394cc1aee72a..608a2ae73acf 100644 --- a/src/Shared/runtime/Http3/QPack/QPackDecoder.cs +++ b/src/Shared/runtime/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; diff --git a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs index b7f4c19072a6..28a815f2d80e 100644 --- a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs +++ b/src/Shared/test/Shared.Tests/runtime/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 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); + 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() { @@ -500,10 +606,8 @@ public void DecodesStringLength_ExceedsLimit_Throws() string string8191 = new string('a', MaxHeaderFieldSize - 1); string string8193 = new string('a', MaxHeaderFieldSize + 1); string string8194 = new string('a', MaxHeaderFieldSize + 2); - var bytes = new byte[3]; var success = IntegerEncoder.Encode(8194, 7, bytes, out var written); - byte[] encoded = _literalHeaderFieldWithoutIndexingNewName .Concat(new byte[] { 0x7f, 0x80, 0x3f }) // 8191 encoded with 7-bit prefix, no Huffman encoding .Concat(Encoding.ASCII.GetBytes(string8191)) @@ -520,14 +624,12 @@ public void DecodesStringLength_ExceedsLimit_Throws() .Concat(new byte[] { 0x7f, 0x83, 0x3f }) // 8194 encoded with 7-bit prefix, no Huffman encoding .Concat(Encoding.ASCII.GetBytes(string8194)) .ToArray(); - var ex = Assert.Throws(() => decoder.Decode(encoded, endHeaders: true, handler: _handler)); Assert.Equal(SR.Format(SR.net_http_headers_exceeded_length, MaxHeaderFieldSize + 1), ex.Message); Assert.Equal(string8191, _handler.DecodedHeaders[string8191]); Assert.Equal(string8193, _handler.DecodedHeaders[string8193]); Assert.False(_handler.DecodedHeaders.ContainsKey(string8194)); } - [Fact] public void DecodesStringLength_IndividualBytes() { diff --git a/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs index 475fddeab09b..8db70d84ee05 100644 --- a/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs +++ b/src/Shared/test/Shared.Tests/runtime/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 _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] @@ -173,6 +173,101 @@ public void DecodesLiteralFieldLineWithLiteralName_LargeValues() }); } + [Fact] + public void LiteralFieldWithoutNameReference_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(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_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(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_NameBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, 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(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_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(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_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(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_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(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + public static readonly TheoryData _incompleteHeaderBlockData = new TheoryData { // Incomplete header From 011a87d4e3c60503dc24b64e8d2f7fb0ebdc86e3 Mon Sep 17 00:00:00 2001 From: Aditya Mandaleeka Date: Fri, 5 May 2023 16:34:22 -0700 Subject: [PATCH 2/4] Fix warnings in H/QPack tests. --- .editorconfig | 12 ++++++++++-- .../Shared.Tests/runtime/Http2/HPackDecoderTest.cs | 10 +++++----- .../Shared.Tests/runtime/Http3/QPackDecoderTest.cs | 12 ++++++------ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/.editorconfig b/.editorconfig index c532bc0d1f63..4ecd69ca10c0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -133,10 +133,12 @@ dotnet_diagnostic.CA1829.severity = warning dotnet_diagnostic.CA1830.severity = warning # CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate -# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate -# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate dotnet_diagnostic.CA1831.severity = warning + +# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate dotnet_diagnostic.CA1832.severity = warning + +# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate dotnet_diagnostic.CA1833.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable @@ -290,6 +292,12 @@ dotnet_diagnostic.CA1826.severity = suggestion dotnet_diagnostic.CA1827.severity = suggestion # CA1829: Use Length/Count property instead of Count() when available dotnet_diagnostic.CA1829.severity = suggestion +# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1831.severity = suggestion +# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1832.severity = suggestion +# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1833.severity = suggestion # CA1834: Consider using 'StringBuilder.Append(char)' when applicable dotnet_diagnostic.CA1834.severity = suggestion # CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' diff --git a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs index 28a815f2d80e..18e7b85d4995 100644 --- a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs +++ b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs @@ -413,7 +413,7 @@ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_SingleBuffer() _decoder.Decode(encoded, endHeaders: true, handler: _handler); - Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); } @@ -429,7 +429,7 @@ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameLengthBrokenIntoSe _decoder.Decode(encoded[..1], endHeaders: false, handler: _handler); _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); - Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); } @@ -445,7 +445,7 @@ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameBrokenIntoSeparate _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); } @@ -461,7 +461,7 @@ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameAndValueBrokenInto _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); } @@ -477,7 +477,7 @@ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueLengthBrokenIntoS _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); } diff --git a/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs index 8db70d84ee05..931ecbcd9bd2 100644 --- a/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs +++ b/src/Shared/test/Shared.Tests/runtime/Http3/QPackDecoderTest.cs @@ -183,7 +183,7 @@ public void LiteralFieldWithoutNameReference_SingleBuffer() _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); _decoder.Decode(encoded, endHeaders: true, handler: _handler); - Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } @@ -199,7 +199,7 @@ public void LiteralFieldWithoutNameReference_NameLengthBrokenIntoSeparateBuffers _decoder.Decode(encoded[..1], endHeaders: false, handler: _handler); _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); - Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } @@ -215,7 +215,7 @@ public void LiteralFieldWithoutNameReference_NameBrokenIntoSeparateBuffers() _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } @@ -231,7 +231,7 @@ public void LiteralFieldWithoutNameReference_NameAndValueBrokenIntoSeparateBuffe _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } @@ -247,7 +247,7 @@ public void LiteralFieldWithoutNameReference_ValueLengthBrokenIntoSeparateBuffer _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } @@ -263,7 +263,7 @@ public void LiteralFieldWithoutNameReference_ValueBrokenIntoSeparateBuffers() _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); } From 70e70283eeac527648984104216ada51a454d48f Mon Sep 17 00:00:00 2001 From: ManickaP Date: Thu, 11 May 2023 10:58:27 +0200 Subject: [PATCH 3/4] Fix Asserts --- .../test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs index 18e7b85d4995..fc29dcba436d 100644 --- a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs +++ b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs @@ -493,7 +493,7 @@ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueBrokenIntoSeparat _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.Single(_handler.DecodedHeaders); Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); } @@ -843,7 +843,7 @@ private static void TestDecode(byte[] encoded, string expectedHeaderName, string if (expectDynamicTableEntry) { - Assert.Equal(1, dynamicTable.Count); + Assert.Single(dynamicTable); Assert.Equal(expectedHeaderName, Encoding.ASCII.GetString(dynamicTable[0].Name)); Assert.Equal(expectedHeaderValue, Encoding.ASCII.GetString(dynamicTable[0].Value)); Assert.Equal(expectedHeaderName.Length + expectedHeaderValue.Length + 32, dynamicTable.Size); From 64df8d483fd2e02eec9e22e7ca021e994c17c994 Mon Sep 17 00:00:00 2001 From: ManickaP Date: Fri, 12 May 2023 08:56:45 +0200 Subject: [PATCH 4/4] Fix test --- src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs index fc29dcba436d..d070c179aa4c 100644 --- a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs +++ b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs @@ -843,7 +843,7 @@ private static void TestDecode(byte[] encoded, string expectedHeaderName, string if (expectDynamicTableEntry) { - Assert.Single(dynamicTable); + Assert.Equal(1, dynamicTable.Count); Assert.Equal(expectedHeaderName, Encoding.ASCII.GetString(dynamicTable[0].Name)); Assert.Equal(expectedHeaderValue, Encoding.ASCII.GetString(dynamicTable[0].Value)); Assert.Equal(expectedHeaderName.Length + expectedHeaderValue.Length + 32, dynamicTable.Size);