@@ -426,28 +426,61 @@ public void ValueReuseNeverWhenNotAscii(bool reuseValue, KnownHeader header)
426
426
[ MemberData ( nameof ( KnownRequestHeaders ) ) ]
427
427
public void ValueReuseLatin1NotConfusedForUtf16AndStillRejected ( bool reuseValue , KnownHeader header )
428
428
{
429
- const string HeaderValueUtf16Latin1CrossOver = "Hello \u00a3 " ;
430
-
431
429
var headers = new HttpRequestHeaders ( reuseHeaderValues : reuseValue ) ;
432
- headers . Reset ( ) ;
433
430
434
- var headerName = Encoding . ASCII . GetBytes ( header . Name ) . AsSpan ( ) ;
435
- var prevSpan = Encoding . UTF8 . GetBytes ( HeaderValueUtf16Latin1CrossOver ) . AsSpan ( ) ;
431
+ var headerValue = new char [ 127 ] ; // 64 + 32 + 16 + 8 + 4 + 2 + 1
432
+ for ( var i = 0 ; i < headerValue . Length ; i ++ )
433
+ {
434
+ headerValue [ i ] = 'a' ;
435
+ }
436
436
437
- headers . Append ( headerName , prevSpan ) ;
438
- headers . OnHeadersComplete ( ) ;
439
- var prevHeaderValue = ( ( IHeaderDictionary ) headers ) [ header . Name ] . ToString ( ) ;
437
+ for ( var i = 0 ; i < headerValue . Length ; i ++ )
438
+ {
439
+ // Set non-ascii Latin char that is valid Utf16 when widened; but not a valid utf8 -> utf16 conversion.
440
+ headerValue [ i ] = '\u00a3 ' ;
440
441
441
- Assert . Equal ( HeaderValueUtf16Latin1CrossOver , prevHeaderValue ) ;
442
- Assert . NotSame ( HeaderValueUtf16Latin1CrossOver , prevHeaderValue ) ;
442
+ for ( var mode = 0 ; mode <= 1 ; mode ++ )
443
+ {
444
+ string headerValueUtf16Latin1CrossOver ;
445
+ if ( mode == 0 )
446
+ {
447
+ // Full length
448
+ headerValueUtf16Latin1CrossOver = new string ( headerValue ) ;
449
+ }
450
+ else
451
+ {
452
+ // Truncated length (to ensure different paths from changing lengths in matching)
453
+ headerValueUtf16Latin1CrossOver = new string ( headerValue . AsSpan ( ) . Slice ( 0 , i + 1 ) ) ;
454
+ }
443
455
444
- headers . Reset ( ) ;
456
+ headers . Reset ( ) ;
445
457
446
- Assert . Throws < InvalidOperationException > ( ( ) => {
447
- var headerName = Encoding . ASCII . GetBytes ( header . Name ) . AsSpan ( ) ;
448
- var nextSpan = Encoding . GetEncoding ( "iso-8859-1" ) . GetBytes ( HeaderValueUtf16Latin1CrossOver ) . AsSpan ( ) ;
449
- headers . Append ( headerName , nextSpan ) ;
450
- } ) ;
458
+ var headerName = Encoding . ASCII . GetBytes ( header . Name ) . AsSpan ( ) ;
459
+ var prevSpan = Encoding . UTF8 . GetBytes ( headerValueUtf16Latin1CrossOver ) . AsSpan ( ) ;
460
+
461
+ headers . Append ( headerName , prevSpan ) ;
462
+ headers . OnHeadersComplete ( ) ;
463
+ var prevHeaderValue = ( ( IHeaderDictionary ) headers ) [ header . Name ] . ToString ( ) ;
464
+
465
+ Assert . Equal ( headerValueUtf16Latin1CrossOver , prevHeaderValue ) ;
466
+ Assert . NotSame ( headerValueUtf16Latin1CrossOver , prevHeaderValue ) ;
467
+
468
+ headers . Reset ( ) ;
469
+
470
+ Assert . Throws < InvalidOperationException > ( ( ) =>
471
+ {
472
+ var headerName = Encoding . ASCII . GetBytes ( header . Name ) . AsSpan ( ) ;
473
+ var nextSpan = Encoding . GetEncoding ( "iso-8859-1" ) . GetBytes ( headerValueUtf16Latin1CrossOver ) . AsSpan ( ) ;
474
+
475
+ Assert . False ( nextSpan . SequenceEqual ( Encoding . ASCII . GetBytes ( headerValueUtf16Latin1CrossOver ) ) ) ;
476
+
477
+ headers . Append ( headerName , nextSpan ) ;
478
+ } ) ;
479
+ }
480
+
481
+ // Reset back to Ascii
482
+ headerValue [ i ] = 'a' ;
483
+ }
451
484
}
452
485
453
486
[ Fact ]
0 commit comments