Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49c10ed

Browse files
Use stackalloc char&byte arrays for decoding Url values in HttpUtiliy.ParseQueryString (#102745)
1 parent 81adb34 commit 49c10ed

File tree

2 files changed

+30
-19
lines changed

2 files changed

+30
-19
lines changed

src/libraries/System.Web.HttpUtility/src/System/Web/HttpUtility.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public static NameValueCollection ParseQueryString(string query, Encoding encodi
117117
}
118118
else
119119
{
120-
name = UrlDecode(query.Substring(namePos, valuePos - namePos - 1), encoding);
120+
name = UrlDecode(query.AsSpan(namePos, valuePos - namePos - 1), encoding);
121121
}
122122

123123
if (valueEnd < 0)
@@ -126,7 +126,7 @@ public static NameValueCollection ParseQueryString(string query, Encoding encodi
126126
}
127127

128128
namePos = valueEnd + 1;
129-
string value = UrlDecode(query.Substring(valuePos, valueEnd - valuePos), encoding);
129+
string value = UrlDecode(query.AsSpan(valuePos, valueEnd - valuePos), encoding);
130130
result.Add(name, value);
131131
}
132132

@@ -237,6 +237,8 @@ public static NameValueCollection ParseQueryString(string query, Encoding encodi
237237
[return: NotNullIfNotNull(nameof(str))]
238238
public static string? UrlDecode(string? str, Encoding e) => HttpEncoder.UrlDecode(str, e);
239239

240+
private static string UrlDecode(ReadOnlySpan<char> str, Encoding e) => HttpEncoder.UrlDecode(str, e);
241+
240242
[return: NotNullIfNotNull(nameof(bytes))]
241243
public static string? UrlDecode(byte[]? bytes, int offset, int count, Encoding e) =>
242244
HttpEncoder.UrlDecode(bytes, offset, count, e);

src/libraries/System.Web.HttpUtility/src/System/Web/Util/HttpEncoder.cs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace System.Web.Util
1212
{
1313
internal static class HttpEncoder
1414
{
15+
private const int MaxStackAllocUrlLength = 256;
1516
private static void AppendCharAsUnicodeJavaScript(StringBuilder builder, char c)
1617
{
1718
builder.Append($"\\u{(int)c:x4}");
@@ -258,7 +259,9 @@ internal static byte[] UrlDecode(ReadOnlySpan<byte> bytes)
258259
return null;
259260
}
260261

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);
262265

263266
// go through the bytes collapsing %XX and %uXXXX and appending
264267
// each byte as byte, with exception of %uXXXX constructs that
@@ -321,8 +324,20 @@ internal static byte[] UrlDecode(ReadOnlySpan<byte> bytes)
321324
return null;
322325
}
323326

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+
324337
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);
326341

327342
// go through the string's chars collapsing %XX and %uXXXX and
328343
// appending each char as char, with exception of %XX constructs
@@ -626,17 +641,15 @@ private static bool ValidateUrlEncodingParameters([NotNullWhen(true)] byte[]? by
626641
}
627642

628643
// 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
630645
{
631-
private readonly int _bufferSize;
632-
633646
// Accumulate characters in a special array
634647
private int _numChars;
635-
private readonly char[] _charBuffer;
648+
private readonly Span<char> _charBuffer;
636649

637650
// Accumulate bytes for decoding into characters in a special array
638651
private int _numBytes;
639-
private byte[]? _byteBuffer;
652+
private readonly Span<byte> _byteBuffer;
640653

641654
// Encoding to convert chars to bytes
642655
private readonly Encoding _encoding;
@@ -645,19 +658,17 @@ private void FlushBytes()
645658
{
646659
if (_numBytes > 0)
647660
{
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));
650663
_numBytes = 0;
651664
}
652665
}
653666

654-
internal UrlDecoder(int bufferSize, Encoding encoding)
667+
internal UrlDecoder(Span<char> charBuffer, Span<byte> byteBuffer, Encoding encoding)
655668
{
656-
_bufferSize = bufferSize;
669+
_charBuffer = charBuffer;
670+
_byteBuffer = byteBuffer;
657671
_encoding = encoding;
658-
659-
_charBuffer = new char[bufferSize];
660-
// byte buffer created on demand
661672
}
662673

663674
internal void AddChar(char ch)
@@ -681,8 +692,6 @@ internal void AddByte(byte b)
681692
else
682693
*/
683694
{
684-
_byteBuffer ??= new byte[_bufferSize];
685-
686695
_byteBuffer[_numBytes++] = b;
687696
}
688697
}
@@ -694,7 +703,7 @@ internal string GetString()
694703
FlushBytes();
695704
}
696705

697-
return _numChars > 0 ? new string(_charBuffer, 0, _numChars) : "";
706+
return _charBuffer.Slice(0, _numChars).ToString();
698707
}
699708
}
700709
}

0 commit comments

Comments
 (0)