4
4
#nullable enable
5
5
using System . Collections . Generic ;
6
6
using System . Diagnostics ;
7
+ using System . Text ;
7
8
8
9
namespace System . Net . Http . HPack
9
10
{
@@ -96,7 +97,7 @@ public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, string val
96
97
if ( IntegerEncoder . Encode ( index , 4 , destination , out int indexLength ) )
97
98
{
98
99
Debug . Assert ( indexLength >= 1 ) ;
99
- if ( EncodeStringLiteral ( value , destination . Slice ( indexLength ) , out int nameLength ) )
100
+ if ( EncodeStringLiteral ( value , valueEncoding : null , destination . Slice ( indexLength ) , out int nameLength ) )
100
101
{
101
102
bytesWritten = indexLength + nameLength ;
102
103
return true ;
@@ -128,7 +129,7 @@ public static bool EncodeLiteralHeaderFieldNeverIndexing(int index, string value
128
129
if ( IntegerEncoder . Encode ( index , 4 , destination , out int indexLength ) )
129
130
{
130
131
Debug . Assert ( indexLength >= 1 ) ;
131
- if ( EncodeStringLiteral ( value , destination . Slice ( indexLength ) , out int nameLength ) )
132
+ if ( EncodeStringLiteral ( value , valueEncoding : null , destination . Slice ( indexLength ) , out int nameLength ) )
132
133
{
133
134
bytesWritten = indexLength + nameLength ;
134
135
return true ;
@@ -160,7 +161,7 @@ public static bool EncodeLiteralHeaderFieldIndexing(int index, string value, Spa
160
161
if ( IntegerEncoder . Encode ( index , 6 , destination , out int indexLength ) )
161
162
{
162
163
Debug . Assert ( indexLength >= 1 ) ;
163
- if ( EncodeStringLiteral ( value , destination . Slice ( indexLength ) , out int nameLength ) )
164
+ if ( EncodeStringLiteral ( value , valueEncoding : null , destination . Slice ( indexLength ) , out int nameLength ) )
164
165
{
165
166
bytesWritten = indexLength + nameLength ;
166
167
return true ;
@@ -276,7 +277,7 @@ private static bool EncodeLiteralHeaderNewNameCore(byte mask, string name, strin
276
277
{
277
278
destination [ 0 ] = mask ;
278
279
if ( EncodeLiteralHeaderName ( name , destination . Slice ( 1 ) , out int nameLength ) &&
279
- EncodeStringLiteral ( value , destination . Slice ( 1 + nameLength ) , out int valueLength ) )
280
+ EncodeStringLiteral ( value , valueEncoding : null , destination . Slice ( 1 + nameLength ) , out int valueLength ) )
280
281
{
281
282
bytesWritten = 1 + nameLength + valueLength ;
282
283
return true ;
@@ -289,6 +290,11 @@ private static bool EncodeLiteralHeaderNewNameCore(byte mask, string name, strin
289
290
290
291
/// <summary>Encodes a "Literal Header Field without Indexing - New Name".</summary>
291
292
public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName ( string name , ReadOnlySpan < string > values , string separator , Span < byte > destination , out int bytesWritten )
293
+ {
294
+ return EncodeLiteralHeaderFieldWithoutIndexingNewName ( name , values , separator , valueEncoding : null , destination , out bytesWritten ) ;
295
+ }
296
+
297
+ public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName ( string name , ReadOnlySpan < string > values , string separator , Encoding ? valueEncoding , Span < byte > destination , out int bytesWritten )
292
298
{
293
299
// From https://tools.ietf.org/html/rfc7541#section-6.2.2
294
300
// ------------------------------------------------------
@@ -309,7 +315,7 @@ public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, R
309
315
{
310
316
destination [ 0 ] = 0 ;
311
317
if ( EncodeLiteralHeaderName ( name , destination . Slice ( 1 ) , out int nameLength ) &&
312
- EncodeStringLiterals ( values , separator , destination . Slice ( 1 + nameLength ) , out int valueLength ) )
318
+ EncodeStringLiterals ( values , separator , valueEncoding , destination . Slice ( 1 + nameLength ) , out int valueLength ) )
313
319
{
314
320
bytesWritten = 1 + nameLength + valueLength ;
315
321
return true ;
@@ -395,27 +401,20 @@ private static bool EncodeLiteralHeaderName(string value, Span<byte> destination
395
401
return false ;
396
402
}
397
403
398
- private static bool EncodeStringLiteralValue ( string value , Span < byte > destination , out int bytesWritten )
404
+ private static void EncodeValueStringPart ( string value , Span < byte > destination )
399
405
{
400
- if ( value . Length <= destination . Length )
406
+ Debug . Assert ( destination . Length >= value . Length ) ;
407
+
408
+ for ( int i = 0 ; i < value . Length ; i ++ )
401
409
{
402
- for ( int i = 0 ; i < value . Length ; i ++ )
410
+ char c = value [ i ] ;
411
+ if ( ( c & 0xFF80 ) != 0 )
403
412
{
404
- char c = value [ i ] ;
405
- if ( ( c & 0xFF80 ) != 0 )
406
- {
407
- throw new HttpRequestException ( SR . net_http_request_invalid_char_encoding ) ;
408
- }
409
-
410
- destination [ i ] = ( byte ) c ;
413
+ throw new HttpRequestException ( SR . net_http_request_invalid_char_encoding ) ;
411
414
}
412
415
413
- bytesWritten = value . Length ;
414
- return true ;
416
+ destination [ i ] = ( byte ) c ;
415
417
}
416
-
417
- bytesWritten = 0 ;
418
- return false ;
419
418
}
420
419
421
420
public static bool EncodeStringLiteral ( ReadOnlySpan < byte > value , Span < byte > destination , out int bytesWritten )
@@ -453,6 +452,11 @@ public static bool EncodeStringLiteral(ReadOnlySpan<byte> value, Span<byte> dest
453
452
}
454
453
455
454
public static bool EncodeStringLiteral ( string value , Span < byte > destination , out int bytesWritten )
455
+ {
456
+ return EncodeStringLiteral ( value , valueEncoding : null , destination , out bytesWritten ) ;
457
+ }
458
+
459
+ public static bool EncodeStringLiteral ( string value , Encoding ? valueEncoding , Span < byte > destination , out int bytesWritten )
456
460
{
457
461
// From https://tools.ietf.org/html/rfc7541#section-5.2
458
462
// ------------------------------------------------------
@@ -466,13 +470,28 @@ public static bool EncodeStringLiteral(string value, Span<byte> destination, out
466
470
if ( destination . Length != 0 )
467
471
{
468
472
destination [ 0 ] = 0 ; // TODO: Use Huffman encoding
469
- if ( IntegerEncoder . Encode ( value . Length , 7 , destination , out int integerLength ) )
473
+
474
+ int encodedStringLength = valueEncoding is null || ReferenceEquals ( valueEncoding , Encoding . Latin1 )
475
+ ? value . Length
476
+ : valueEncoding . GetByteCount ( value ) ;
477
+
478
+ if ( IntegerEncoder . Encode ( encodedStringLength , 7 , destination , out int integerLength ) )
470
479
{
471
480
Debug . Assert ( integerLength >= 1 ) ;
472
-
473
- if ( EncodeStringLiteralValue ( value , destination . Slice ( integerLength ) , out int valueLength ) )
481
+ destination = destination . Slice ( integerLength ) ;
482
+ if ( encodedStringLength <= destination . Length )
474
483
{
475
- bytesWritten = integerLength + valueLength ;
484
+ if ( valueEncoding is null )
485
+ {
486
+ EncodeValueStringPart ( value , destination ) ;
487
+ }
488
+ else
489
+ {
490
+ int written = valueEncoding . GetBytes ( value , destination ) ;
491
+ Debug . Assert ( written == encodedStringLength ) ;
492
+ }
493
+
494
+ bytesWritten = integerLength + encodedStringLength ;
476
495
return true ;
477
496
}
478
497
}
@@ -502,56 +521,87 @@ public static bool EncodeDynamicTableSizeUpdate(int value, Span<byte> destinatio
502
521
}
503
522
504
523
public static bool EncodeStringLiterals ( ReadOnlySpan < string > values , string ? separator , Span < byte > destination , out int bytesWritten )
524
+ {
525
+ return EncodeStringLiterals ( values , separator , valueEncoding : null , destination , out bytesWritten ) ;
526
+ }
527
+
528
+ public static bool EncodeStringLiterals ( ReadOnlySpan < string > values , string ? separator , Encoding ? valueEncoding , Span < byte > destination , out int bytesWritten )
505
529
{
506
530
bytesWritten = 0 ;
507
531
508
532
if ( values . Length == 0 )
509
533
{
510
- return EncodeStringLiteral ( "" , destination , out bytesWritten ) ;
534
+ return EncodeStringLiteral ( "" , valueEncoding : null , destination , out bytesWritten ) ;
511
535
}
512
536
else if ( values . Length == 1 )
513
537
{
514
- return EncodeStringLiteral ( values [ 0 ] , destination , out bytesWritten ) ;
538
+ return EncodeStringLiteral ( values [ 0 ] , valueEncoding , destination , out bytesWritten ) ;
515
539
}
516
540
517
541
if ( destination . Length != 0 )
518
542
{
519
- int valueLength = 0 ;
543
+ Debug . Assert ( separator != null ) ;
544
+ int valueLength ;
520
545
521
546
// Calculate length of all parts and separators.
522
- foreach ( string part in values )
547
+ if ( valueEncoding is null || ReferenceEquals ( valueEncoding , Encoding . Latin1 ) )
523
548
{
524
- valueLength = checked ( ( int ) ( valueLength + part . Length ) ) ;
549
+ valueLength = checked ( ( int ) ( values . Length - 1 ) * separator . Length ) ;
550
+ foreach ( string part in values )
551
+ {
552
+ valueLength = checked ( ( int ) ( valueLength + part . Length ) ) ;
553
+ }
554
+ }
555
+ else
556
+ {
557
+ valueLength = checked ( ( int ) ( values . Length - 1 ) * valueEncoding . GetByteCount ( separator ) ) ;
558
+ foreach ( string part in values )
559
+ {
560
+ valueLength = checked ( ( int ) ( valueLength + valueEncoding . GetByteCount ( part ) ) ) ;
561
+ }
525
562
}
526
-
527
- Debug . Assert ( separator != null ) ;
528
- valueLength = checked ( ( int ) ( valueLength + ( values . Length - 1 ) * separator . Length ) ) ;
529
563
530
564
destination [ 0 ] = 0 ;
531
565
if ( IntegerEncoder . Encode ( valueLength , 7 , destination , out int integerLength ) )
532
566
{
533
567
Debug . Assert ( integerLength >= 1 ) ;
534
-
535
- int encodedLength = 0 ;
536
- for ( int j = 0 ; j < values . Length ; j ++ )
568
+ destination = destination . Slice ( integerLength ) ;
569
+ if ( destination . Length >= valueLength )
537
570
{
538
- if ( j != 0 && ! EncodeStringLiteralValue ( separator , destination . Slice ( integerLength ) , out encodedLength ) )
571
+ if ( valueEncoding is null )
539
572
{
540
- return false ;
573
+ string value = values [ 0 ] ;
574
+ EncodeValueStringPart ( value , destination ) ;
575
+ destination = destination . Slice ( value . Length ) ;
576
+
577
+ for ( int i = 1 ; i < values . Length ; i ++ )
578
+ {
579
+ EncodeValueStringPart ( separator , destination ) ;
580
+ destination = destination . Slice ( separator . Length ) ;
581
+
582
+ value = values [ i ] ;
583
+ EncodeValueStringPart ( value , destination ) ;
584
+ destination = destination . Slice ( value . Length ) ;
585
+ }
541
586
}
587
+ else
588
+ {
589
+ int written = valueEncoding . GetBytes ( values [ 0 ] , destination ) ;
590
+ destination = destination . Slice ( written ) ;
542
591
543
- integerLength += encodedLength ;
592
+ for ( int i = 1 ; i < values . Length ; i ++ )
593
+ {
594
+ written = valueEncoding . GetBytes ( separator , destination ) ;
595
+ destination = destination . Slice ( written ) ;
544
596
545
- if ( ! EncodeStringLiteralValue ( values [ j ] , destination . Slice ( integerLength ) , out encodedLength ) )
546
- {
547
- return false ;
597
+ written = valueEncoding . GetBytes ( values [ i ] , destination ) ;
598
+ destination = destination . Slice ( written ) ;
599
+ }
548
600
}
549
601
550
- integerLength += encodedLength ;
602
+ bytesWritten = integerLength + valueLength ;
603
+ return true ;
551
604
}
552
-
553
- bytesWritten = integerLength ;
554
- return true ;
555
605
}
556
606
}
557
607
0 commit comments