Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/libraries/System.Private.Uri/src/System/IriHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ internal static unsafe string EscapeUnescapeIri(char* pInput, int start, int end
{
// possibly utf8 encoded sequence of unicode
int charactersRead = PercentEncodingHelper.UnescapePercentEncodedUTF8Sequence(
pInput + i,
end - i,
new ReadOnlySpan<char>(pInput + i, end - i),
ref dest,
isQuery,
iriParsing: true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

using System.Buffers;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace System
{
internal static class PercentEncodingHelper
{
public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int length, ref ValueStringBuilder dest, bool isQuery, bool iriParsing)
public static int UnescapePercentEncodedUTF8Sequence(ReadOnlySpan<char> input, ref ValueStringBuilder dest, bool isQuery, bool iriParsing)
{
int length = input.Length;

// The following assertions rely on the input not mutating mid-operation, as is the case currently since callers are working with strings
// If we start accepting input such as spans, this method must be audited to ensure no buffer overruns/infinite loops could occur

Expand Down Expand Up @@ -85,15 +88,16 @@ public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int len
Debug.Assert(bytesLeftInBuffer < 4 || (fourByteBuffer & (BitConverter.IsLittleEndian ? 0x80000000 : 0x00000080)) != 0);

uint temp = fourByteBuffer; // make a copy so that the *copy* (not the original) is marked address-taken
if (Rune.DecodeFromUtf8(new ReadOnlySpan<byte>(&temp, bytesLeftInBuffer), out Rune rune, out bytesConsumed) == OperationStatus.Done)

if (Rune.DecodeFromUtf8(MemoryMarshal.AsBytes(new ReadOnlySpan<uint>(ref temp))[..bytesLeftInBuffer], out Rune rune, out bytesConsumed) == OperationStatus.Done)
{
Debug.Assert(bytesConsumed >= 2, $"Rune.DecodeFromUtf8 consumed {bytesConsumed} bytes, likely indicating input was modified concurrently during UnescapePercentEncodedUTF8Sequence's execution");

if (!iriParsing || IriHelper.CheckIriUnicodeRange((uint)rune.Value, isQuery))
{
if (charsToCopy != 0)
{
dest.Append(new ReadOnlySpan<char>(input + totalCharsConsumed - charsToCopy, charsToCopy));
dest.Append(input.Slice(totalCharsConsumed - charsToCopy, charsToCopy));
charsToCopy = 0;
}

Expand Down Expand Up @@ -167,7 +171,8 @@ public static unsafe int UnescapePercentEncodedUTF8Sequence(char* input, int len
return totalCharsConsumed;

bytesLeftInBuffer *= 3;
dest.Append(new ReadOnlySpan<char>(input + totalCharsConsumed - charsToCopy, charsToCopy + bytesLeftInBuffer));

dest.Append(input.Slice(totalCharsConsumed - charsToCopy, charsToCopy + bytesLeftInBuffer));
return totalCharsConsumed + bytesLeftInBuffer;
}
}
Expand Down
12 changes: 1 addition & 11 deletions src/libraries/System.Private.Uri/src/System/UriExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,17 +1027,7 @@ internal bool IsBaseOfHelper(Uri uriLink)
string self = GetParts(ComponentsToCompare, UriFormat.SafeUnescaped);
string other = uriLink.GetParts(ComponentsToCompare, UriFormat.SafeUnescaped);

unsafe
{
fixed (char* selfPtr = self)
{
fixed (char* otherPtr = other)
{
return UriHelper.TestForSubPath(selfPtr, self.Length, otherPtr, other.Length,
IsUncOrDosPath || uriLink.IsUncOrDosPath);
}
}
}
return UriHelper.TestForSubPath(self, other, IsUncOrDosPath || uriLink.IsUncOrDosPath);
}

//
Expand Down
16 changes: 7 additions & 9 deletions src/libraries/System.Private.Uri/src/System/UriHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,18 @@ public static string NormalizeAndConcat(string? start, ReadOnlySpan<char> toNorm
// ASSUMES that strings like http://host/Path/Path/MoreDir/../../ have been canonicalized before going to this method.
// ASSUMES that back slashes already have been converted if applicable.
//
internal static unsafe bool TestForSubPath(char* selfPtr, int selfLength, char* otherPtr, int otherLength,
bool ignoreCase)
internal static bool TestForSubPath(ReadOnlySpan<char> self, ReadOnlySpan<char> other, bool ignoreCase)
{
int i = 0;
char chSelf;
char chOther;

bool AllSameBeforeSlash = true;

for (; i < selfLength && i < otherLength; ++i)
for (; i < self.Length && i < other.Length; ++i)
{
chSelf = *(selfPtr + i);
chOther = *(otherPtr + i);
chSelf = self[i];
chOther = other[i];

if (chSelf == '?' || chSelf == '#')
{
Expand Down Expand Up @@ -118,9 +117,9 @@ internal static unsafe bool TestForSubPath(char* selfPtr, int selfLength, char*
}

// If self is longer then it must not have any more path segments
for (; i < selfLength; ++i)
for (; i < self.Length; ++i)
{
if ((chSelf = *(selfPtr + i)) == '?' || chSelf == '#')
if ((chSelf = self[i]) == '?' || chSelf == '#')
{
return true;
}
Expand Down Expand Up @@ -507,8 +506,7 @@ internal static unsafe void UnescapeString(char* pStr, int start, int end, ref V
{
// Unicode
int charactersRead = PercentEncodingHelper.UnescapePercentEncodedUTF8Sequence(
pStr + next,
end - next,
new ReadOnlySpan<char>(pStr + next, end - next),
ref dest,
isQuery,
iriParsing);
Expand Down
Loading