@@ -401,64 +401,37 @@ internal static string UrlDecode(ReadOnlySpan<char> value, Encoding encoding)
401
401
}
402
402
403
403
[ return : NotNullIfNotNull ( nameof ( bytes ) ) ]
404
- internal static byte [ ] ? UrlEncode ( byte [ ] ? bytes , int offset , int count , bool alwaysCreateNewReturnValue )
405
- {
406
- byte [ ] ? encoded = UrlEncode ( bytes , offset , count ) ;
407
-
408
- return ( alwaysCreateNewReturnValue && ( encoded != null ) && ( encoded == bytes ) )
409
- ? ( byte [ ] ) encoded . Clone ( )
410
- : encoded ;
411
- }
412
-
413
- [ return : NotNullIfNotNull ( nameof ( bytes ) ) ]
414
- private static byte [ ] ? UrlEncode ( byte [ ] ? bytes , int offset , int count )
404
+ internal static byte [ ] ? UrlEncode ( byte [ ] ? bytes , int offset , int count )
415
405
{
416
406
if ( ! ValidateUrlEncodingParameters ( bytes , offset , count ) )
417
407
{
418
408
return null ;
419
409
}
420
410
421
- int cSpaces = 0 ;
422
- int cUnsafe = 0 ;
423
-
424
- // count them first
425
- for ( int i = 0 ; i < count ; i ++ )
426
- {
427
- char ch = ( char ) bytes [ offset + i ] ;
428
-
429
- if ( ch == ' ' )
430
- {
431
- cSpaces ++ ;
432
- }
433
- else if ( ! HttpEncoderUtility . IsUrlSafeChar ( ch ) )
434
- {
435
- cUnsafe ++ ;
436
- }
437
- }
411
+ return UrlEncode ( bytes . AsSpan ( offset , count ) ) ;
412
+ }
438
413
414
+ private static byte [ ] UrlEncode ( ReadOnlySpan < byte > bytes )
415
+ {
439
416
// nothing to expand?
440
- if ( cSpaces == 0 && cUnsafe == 0 )
417
+ if ( ! IsExpandingNeeded ( bytes , out int cUnsafe ) )
441
418
{
442
- // DevDiv 912606: respect "offset" and "count"
443
- if ( 0 == offset && bytes . Length == count )
444
- {
445
- return bytes ;
446
- }
447
- else
448
- {
449
- byte [ ] subarray = new byte [ count ] ;
450
- Buffer . BlockCopy ( bytes , offset , subarray , 0 , count ) ;
451
- return subarray ;
452
- }
419
+ return bytes . ToArray ( ) ;
453
420
}
454
421
422
+ return UrlEncode ( bytes , cUnsafe ) ;
423
+ }
424
+
425
+ private static byte [ ] UrlEncode ( ReadOnlySpan < byte > bytes , int cUnsafe )
426
+ {
427
+ int count = bytes . Length ;
455
428
// expand not 'safe' characters into %XX, spaces to +s
456
429
byte [ ] expandedBytes = new byte [ count + cUnsafe * 2 ] ;
457
430
int pos = 0 ;
458
431
459
432
for ( int i = 0 ; i < count ; i ++ )
460
433
{
461
- byte b = bytes [ offset + i ] ;
434
+ byte b = bytes [ i ] ;
462
435
char ch = ( char ) b ;
463
436
464
437
if ( HttpEncoderUtility . IsUrlSafeChar ( ch ) )
@@ -480,6 +453,51 @@ internal static string UrlDecode(ReadOnlySpan<char> value, Encoding encoding)
480
453
return expandedBytes ;
481
454
}
482
455
456
+ private static bool IsExpandingNeeded ( ReadOnlySpan < byte > bytes , out int cUnsafe )
457
+ {
458
+ cUnsafe = 0 ;
459
+
460
+ int cSpaces = 0 ;
461
+ int count = bytes . Length ;
462
+ for ( int i = 0 ; i < count ; i ++ )
463
+ {
464
+ char ch = ( char ) bytes [ i ] ;
465
+
466
+ if ( ch == ' ' )
467
+ {
468
+ cSpaces ++ ;
469
+ }
470
+ else if ( ! HttpEncoderUtility . IsUrlSafeChar ( ch ) )
471
+ {
472
+ cUnsafe ++ ;
473
+ }
474
+ }
475
+
476
+ return cSpaces != 0 || cUnsafe != 0 ;
477
+ }
478
+
479
+ internal static byte [ ] UrlEncode ( string str , Encoding e )
480
+ {
481
+ const int StackallocThreshold = 512 ;
482
+
483
+ if ( e . GetMaxByteCount ( str . Length ) <= StackallocThreshold )
484
+ {
485
+ Span < byte > byteSpan = stackalloc byte [ StackallocThreshold ] ;
486
+ int encodedBytes = e . GetBytes ( str , byteSpan ) ;
487
+
488
+ return UrlEncode ( byteSpan . Slice ( 0 , encodedBytes ) ) ;
489
+ }
490
+
491
+ byte [ ] bytes = e . GetBytes ( str ) ;
492
+ if ( ! IsExpandingNeeded ( bytes , out int cUnsafe ) )
493
+ {
494
+ // return encoded byte[] if nothing to expand
495
+ return bytes ;
496
+ }
497
+
498
+ return UrlEncode ( bytes . AsSpan ( 0 , bytes . Length ) , cUnsafe ) ;
499
+ }
500
+
483
501
// Helper to encode the non-ASCII url characters only
484
502
private static string UrlEncodeNonAscii ( string str , Encoding e )
485
503
{
0 commit comments