@@ -12,6 +12,7 @@ namespace System.Web.Util
12
12
{
13
13
internal static class HttpEncoder
14
14
{
15
+ private const int MaxStackAllocUrlLength = 256 ;
15
16
private static void AppendCharAsUnicodeJavaScript ( StringBuilder builder , char c )
16
17
{
17
18
builder . Append ( $ "\\ u{ ( int ) c : x4} ") ;
@@ -258,7 +259,9 @@ internal static byte[] UrlDecode(ReadOnlySpan<byte> bytes)
258
259
return null ;
259
260
}
260
261
261
- UrlDecoder helper = new UrlDecoder ( count , encoding ) ;
262
+ UrlDecoder helper = count <= MaxStackAllocUrlLength
263
+ ? new UrlDecoder ( stackalloc char [ MaxStackAllocUrlLength ] , stackalloc byte [ MaxStackAllocUrlLength ] , encoding )
264
+ : new UrlDecoder ( new char [ count ] , new byte [ count ] , encoding ) ;
262
265
263
266
// go through the bytes collapsing %XX and %uXXXX and appending
264
267
// each byte as byte, with exception of %uXXXX constructs that
@@ -321,8 +324,20 @@ internal static byte[] UrlDecode(ReadOnlySpan<byte> bytes)
321
324
return null ;
322
325
}
323
326
327
+ return UrlDecode ( value . AsSpan ( ) , encoding ) ;
328
+ }
329
+
330
+ internal static string UrlDecode ( ReadOnlySpan < char > value , Encoding encoding )
331
+ {
332
+ if ( value . IsEmpty )
333
+ {
334
+ return string . Empty ;
335
+ }
336
+
324
337
int count = value . Length ;
325
- UrlDecoder helper = new UrlDecoder ( count , encoding ) ;
338
+ UrlDecoder helper = count <= MaxStackAllocUrlLength
339
+ ? new UrlDecoder ( stackalloc char [ MaxStackAllocUrlLength ] , stackalloc byte [ MaxStackAllocUrlLength ] , encoding )
340
+ : new UrlDecoder ( new char [ count ] , new byte [ count ] , encoding ) ;
326
341
327
342
// go through the string's chars collapsing %XX and %uXXXX and
328
343
// appending each char as char, with exception of %XX constructs
@@ -626,17 +641,15 @@ private static bool ValidateUrlEncodingParameters([NotNullWhen(true)] byte[]? by
626
641
}
627
642
628
643
// Internal class to facilitate URL decoding -- keeps char buffer and byte buffer, allows appending of either chars or bytes
629
- private sealed class UrlDecoder
644
+ private ref struct UrlDecoder
630
645
{
631
- private readonly int _bufferSize ;
632
-
633
646
// Accumulate characters in a special array
634
647
private int _numChars ;
635
- private readonly char [ ] _charBuffer ;
648
+ private readonly Span < char > _charBuffer ;
636
649
637
650
// Accumulate bytes for decoding into characters in a special array
638
651
private int _numBytes ;
639
- private byte [ ] ? _byteBuffer ;
652
+ private readonly Span < byte > _byteBuffer ;
640
653
641
654
// Encoding to convert chars to bytes
642
655
private readonly Encoding _encoding ;
@@ -645,19 +658,17 @@ private void FlushBytes()
645
658
{
646
659
if ( _numBytes > 0 )
647
660
{
648
- Debug . Assert ( _byteBuffer != null ) ;
649
- _numChars += _encoding . GetChars ( _byteBuffer , 0 , _numBytes , _charBuffer , _numChars ) ;
661
+ Debug . Assert ( ! _byteBuffer . IsEmpty ) ;
662
+ _numChars += _encoding . GetChars ( _byteBuffer . Slice ( 0 , _numBytes ) , _charBuffer . Slice ( _numChars ) ) ;
650
663
_numBytes = 0 ;
651
664
}
652
665
}
653
666
654
- internal UrlDecoder ( int bufferSize , Encoding encoding )
667
+ internal UrlDecoder ( Span < char > charBuffer , Span < byte > byteBuffer , Encoding encoding )
655
668
{
656
- _bufferSize = bufferSize ;
669
+ _charBuffer = charBuffer ;
670
+ _byteBuffer = byteBuffer ;
657
671
_encoding = encoding ;
658
-
659
- _charBuffer = new char [ bufferSize ] ;
660
- // byte buffer created on demand
661
672
}
662
673
663
674
internal void AddChar ( char ch )
@@ -681,8 +692,6 @@ internal void AddByte(byte b)
681
692
else
682
693
*/
683
694
{
684
- _byteBuffer ??= new byte [ _bufferSize ] ;
685
-
686
695
_byteBuffer [ _numBytes ++ ] = b ;
687
696
}
688
697
}
@@ -694,7 +703,7 @@ internal string GetString()
694
703
FlushBytes ( ) ;
695
704
}
696
705
697
- return _numChars > 0 ? new string ( _charBuffer , 0 , _numChars ) : "" ;
706
+ return _charBuffer . Slice ( 0 , _numChars ) . ToString ( ) ;
698
707
}
699
708
}
700
709
}
0 commit comments