@@ -46,8 +46,13 @@ public class HPackDecoderTests
46
46
47
47
private const string _headerNameString = "new-header" ;
48
48
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
+
49
52
private static readonly byte [ ] _headerNameBytes = Encoding . ASCII . GetBytes ( _headerNameString ) ;
50
53
54
+ private static readonly byte [ ] _literalHeaderNameBytes = Encoding . ASCII . GetBytes ( _literalHeaderNameString ) ;
55
+
51
56
// n e w - h e a d e r *
52
57
// 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111
53
58
private static readonly byte [ ] _headerNameHuffmanBytes = new byte [ ] { 0xa8 , 0xbe , 0x16 , 0x9c , 0xa3 , 0x90 , 0xb6 , 0x7f } ;
@@ -64,6 +69,12 @@ public class HPackDecoderTests
64
69
. Concat ( _headerNameBytes )
65
70
. ToArray ( ) ;
66
71
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
+
67
78
private static readonly byte [ ] _headerNameHuffman = new byte [ ] { ( byte ) ( 0x80 | _headerNameHuffmanBytes . Length ) }
68
79
. Concat ( _headerNameHuffmanBytes )
69
80
. ToArray ( ) ;
@@ -392,6 +403,101 @@ public void DecodesLiteralHeaderFieldNeverIndexed_IndexedName_OutOfRange_Error()
392
403
Assert . Empty ( _handler . DecodedHeaders ) ;
393
404
}
394
405
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 . Single ( _handler . DecodedHeaders ) ;
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 . Single ( _handler . DecodedHeaders ) ;
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 . Single ( _handler . DecodedHeaders ) ;
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 . Single ( _handler . DecodedHeaders ) ;
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 . Single ( _handler . DecodedHeaders ) ;
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 . Single ( _handler . DecodedHeaders ) ;
497
+ Assert . True ( _handler . DecodedHeaders . ContainsKey ( _literalHeaderNameString ) ) ;
498
+ Assert . Equal ( _headerValueString , _handler . DecodedHeaders [ _literalHeaderNameString ] ) ;
499
+ }
500
+
395
501
[ Fact ]
396
502
public void DecodesDynamicTableSizeUpdate ( )
397
503
{
@@ -500,10 +606,8 @@ public void DecodesStringLength_ExceedsLimit_Throws()
500
606
string string8191 = new string ( 'a' , MaxHeaderFieldSize - 1 ) ;
501
607
string string8193 = new string ( 'a' , MaxHeaderFieldSize + 1 ) ;
502
608
string string8194 = new string ( 'a' , MaxHeaderFieldSize + 2 ) ;
503
-
504
609
var bytes = new byte [ 3 ] ;
505
610
var success = IntegerEncoder . Encode ( 8194 , 7 , bytes , out var written ) ;
506
-
507
611
byte [ ] encoded = _literalHeaderFieldWithoutIndexingNewName
508
612
. Concat ( new byte [ ] { 0x7f , 0x80 , 0x3f } ) // 8191 encoded with 7-bit prefix, no Huffman encoding
509
613
. Concat ( Encoding . ASCII . GetBytes ( string8191 ) )
@@ -520,14 +624,12 @@ public void DecodesStringLength_ExceedsLimit_Throws()
520
624
. Concat ( new byte [ ] { 0x7f , 0x83 , 0x3f } ) // 8194 encoded with 7-bit prefix, no Huffman encoding
521
625
. Concat ( Encoding . ASCII . GetBytes ( string8194 ) )
522
626
. ToArray ( ) ;
523
-
524
627
var ex = Assert . Throws < HPackDecodingException > ( ( ) => decoder . Decode ( encoded , endHeaders : true , handler : _handler ) ) ;
525
628
Assert . Equal ( SR . Format ( SR . net_http_headers_exceeded_length , MaxHeaderFieldSize + 1 ) , ex . Message ) ;
526
629
Assert . Equal ( string8191 , _handler . DecodedHeaders [ string8191 ] ) ;
527
630
Assert . Equal ( string8193 , _handler . DecodedHeaders [ string8193 ] ) ;
528
631
Assert . False ( _handler . DecodedHeaders . ContainsKey ( string8194 ) ) ;
529
632
}
530
-
531
633
[ Fact ]
532
634
public void DecodesStringLength_IndividualBytes ( )
533
635
{
0 commit comments