@@ -46,8 +46,13 @@ public class HPackDecoderTests
4646
4747 private const string _headerNameString = "new-header" ;
4848
49+ // On purpose longer than 4096 (DefaultStringOctetsSize from HPackDecoder) to trigger https://github.com/dotnet/runtime/issues/78516
50+ private static readonly string _literalHeaderNameString = string . Concat ( Enumerable . Range ( 0 , 4100 ) . Select ( c => ( char ) ( 'a' + ( c % 26 ) ) ) ) ;
51+
4952 private static readonly byte [ ] _headerNameBytes = Encoding . ASCII . GetBytes ( _headerNameString ) ;
5053
54+ private static readonly byte [ ] _literalHeaderNameBytes = Encoding . ASCII . GetBytes ( _literalHeaderNameString ) ;
55+
5156 // n e w - h e a d e r *
5257 // 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111
5358 private static readonly byte [ ] _headerNameHuffmanBytes = new byte [ ] { 0xa8 , 0xbe , 0x16 , 0x9c , 0xa3 , 0x90 , 0xb6 , 0x7f } ;
@@ -64,6 +69,12 @@ public class HPackDecoderTests
6469 . Concat ( _headerNameBytes )
6570 . ToArray ( ) ;
6671
72+ // size = 4096 ==> 0x7f, 0x81, 0x1f (7+) prefixed integer
73+ // size = 4100 ==> 0x7f, 0x85, 0x1f (7+) prefixed integer
74+ private static readonly byte [ ] _literalHeaderName = new byte [ ] { 0x7f , 0x85 , 0x1f } // 4100
75+ . Concat ( _literalHeaderNameBytes )
76+ . ToArray ( ) ;
77+
6778 private static readonly byte [ ] _headerNameHuffman = new byte [ ] { ( byte ) ( 0x80 | _headerNameHuffmanBytes . Length ) }
6879 . Concat ( _headerNameHuffmanBytes )
6980 . ToArray ( ) ;
@@ -392,6 +403,101 @@ public void DecodesLiteralHeaderFieldNeverIndexed_IndexedName_OutOfRange_Error()
392403 Assert . Empty ( _handler . DecodedHeaders ) ;
393404 }
394405
406+ [ Fact ]
407+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_SingleBuffer ( )
408+ {
409+ byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
410+ . Concat ( _literalHeaderName )
411+ . Concat ( _headerValue )
412+ . ToArray ( ) ;
413+
414+ _decoder . Decode ( encoded , endHeaders : true , handler : _handler ) ;
415+
416+ Assert . Equal ( 1 , _handler . DecodedHeaders . Count ) ;
417+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
418+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
419+ }
420+
421+ [ Fact ]
422+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameLengthBrokenIntoSeparateBuffers ( )
423+ {
424+ byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
425+ . Concat ( _literalHeaderName )
426+ . Concat ( _headerValue )
427+ . ToArray ( ) ;
428+
429+ _decoder . Decode ( encoded [ ..1 ] , endHeaders : false , handler : _handler ) ;
430+ _decoder . Decode ( encoded [ 1 ..] , endHeaders : true , handler : _handler ) ;
431+
432+ Assert . Equal ( 1 , _handler . DecodedHeaders . Count ) ;
433+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
434+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
435+ }
436+
437+ [ Fact ]
438+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameBrokenIntoSeparateBuffers ( )
439+ {
440+ byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
441+ . Concat ( _literalHeaderName )
442+ . Concat ( _headerValue )
443+ . ToArray ( ) ;
444+
445+ _decoder . Decode ( encoded [ ..( _literalHeaderNameString . Length / 2 ) ] , endHeaders : false , handler : _handler ) ;
446+ _decoder . Decode ( encoded [ ( _literalHeaderNameString . Length / 2 ) ..] , endHeaders : true , handler : _handler ) ;
447+
448+ Assert . Equal ( 1 , _handler . DecodedHeaders . Count ) ;
449+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
450+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
451+ }
452+
453+ [ Fact ]
454+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameAndValueBrokenIntoSeparateBuffers ( )
455+ {
456+ byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
457+ . Concat ( _literalHeaderName )
458+ . Concat ( _headerValue )
459+ . ToArray ( ) ;
460+
461+ _decoder . Decode ( encoded [ ..^ _headerValue . Length ] , endHeaders : false , handler : _handler ) ;
462+ _decoder . Decode ( encoded [ ^ _headerValue . Length ..] , endHeaders : true , handler : _handler ) ;
463+
464+ Assert . Equal ( 1 , _handler . DecodedHeaders . Count ) ;
465+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
466+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
467+ }
468+
469+ [ Fact ]
470+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueLengthBrokenIntoSeparateBuffers ( )
471+ {
472+ byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
473+ . Concat ( _literalHeaderName )
474+ . Concat ( _headerValue )
475+ . ToArray ( ) ;
476+
477+ _decoder . Decode ( encoded [ ..^ ( _headerValue . Length - 1 ) ] , endHeaders : false , handler : _handler ) ;
478+ _decoder . Decode ( encoded [ ^ ( _headerValue . Length - 1 ) ..] , endHeaders : true , handler : _handler ) ;
479+
480+ Assert . Equal ( 1 , _handler . DecodedHeaders . Count ) ;
481+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
482+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
483+ }
484+
485+ [ Fact ]
486+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueBrokenIntoSeparateBuffers ( )
487+ {
488+ byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
489+ . Concat ( _literalHeaderName )
490+ . Concat ( _headerValue )
491+ . ToArray ( ) ;
492+
493+ _decoder . Decode ( encoded [ ..^ ( _headerValueString . Length / 2 ) ] , endHeaders : false , handler : _handler ) ;
494+ _decoder . Decode ( encoded [ ^ ( _headerValueString . Length / 2 ) ..] , endHeaders : true , handler : _handler ) ;
495+
496+ Assert . Equal ( 1 , _handler . DecodedHeaders . Count ) ;
497+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
498+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
499+ }
500+
395501 [ Fact ]
396502 public void DecodesDynamicTableSizeUpdate ( )
397503 {
0 commit comments