Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add UriCreationOptions
Includes DangerousDisablePathAndQueryCanonicalization
  • Loading branch information
MihaZupan authored and github-actions committed Sep 17, 2021
commit 8fe32da6732b8df0e0ada13b84f889a7abf486cf
3 changes: 3 additions & 0 deletions src/libraries/System.Private.Uri/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,7 @@
<data name="net_uri_InitializeCalledAlreadyOrTooLate" xml:space="preserve">
<value>UriParser's base InitializeAndValidate may only be called once on a single Uri instance and only from an override of InitializeAndValidate.</value>
</data>
<data name="net_uri_GetComponentsCalledWhenCanonicalizationDisabled" xml:space="preserve">
<value>GetComponents() may not be used for Path/Query on a Uri instance created with UriCreationOptions.DangerousDisablePathAndQueryCanonicalization.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<Compile Include="System\UncNameHelper.cs" />
<Compile Include="System\Uri.cs" />
<Compile Include="System\UriBuilder.cs" />
<Compile Include="System\UriCreationOptions.cs" />
<Compile Include="System\UriEnumTypes.cs" />
<Compile Include="System\UriExt.cs" />
<Compile Include="System\UriFormatException.cs" />
Expand Down
63 changes: 59 additions & 4 deletions src/libraries/System.Private.Uri/src/System/Uri.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ internal enum Flags : ulong
IriCanonical = 0x78000000000,
UnixPath = 0x100000000000,

DisablePathAndQueryCanonicalization = 0x200000000000,

/// <summary>
/// Used to ensure that InitializeAndValidate is only called once per Uri instance and only from an override of InitializeAndValidate
/// </summary>
Expand Down Expand Up @@ -267,6 +269,8 @@ internal static bool IriParsingStatic(UriParser? syntax)
return syntax is null || syntax.InFact(UriSyntaxFlags.AllowIriParsing);
}

internal bool DisablePathAndQueryCanonicalization => (_flags & Flags.DisablePathAndQueryCanonicalization) != 0;

internal bool UserDrivenParsing
{
get
Expand Down Expand Up @@ -410,6 +414,15 @@ public Uri(string uriString, UriKind uriKind)
DebugSetLeftCtor();
}

public Uri(string uriString, in UriCreationOptions creationOptions)
{
if (uriString is null)
throw new ArgumentNullException(nameof(uriString));

CreateThis(uriString, false, UriKind.Absolute, in creationOptions);
DebugSetLeftCtor();
}

//
// Uri(Uri, string)
//
Expand Down Expand Up @@ -1639,6 +1652,9 @@ public override bool Equals([NotNullWhen(true)] object? comparand)
// canonicalize the comparand, making comparison possible
if (obj is null)
{
if (DisablePathAndQueryCanonicalization)
return false;

if (!(comparand is string s))
return false;

Expand All @@ -1649,6 +1665,9 @@ public override bool Equals([NotNullWhen(true)] object? comparand)
return false;
}

if (DisablePathAndQueryCanonicalization != obj.DisablePathAndQueryCanonicalization)
return false;

if (ReferenceEquals(OriginalString, obj.OriginalString))
{
return true;
Expand Down Expand Up @@ -2553,7 +2572,7 @@ private unsafe void GetHostViaCustomSyntax()
//
internal string GetParts(UriComponents uriParts, UriFormat formatAs)
{
return GetComponents(uriParts, formatAs);
return InternalGetComponents(uriParts, formatAs);
}

private string GetEscapedParts(UriComponents uriParts)
Expand Down Expand Up @@ -3158,9 +3177,6 @@ private unsafe void ParseRemaining()
idx = _info.Offset.Path;
origIdx = _info.Offset.Path;

//Some uris do not have a query
// When '?' is passed as delimiter, then it's special case
// so both '?' and '#' will work as delimiters
if (buildIriStringFromPath)
{
DebugAssertInCtor();
Expand All @@ -3180,6 +3196,45 @@ private unsafe void ParseRemaining()

_info.Offset.Path = (ushort)_string.Length;
idx = _info.Offset.Path;
}

// If the user explicitly disabled canonicalization, only figure out the offsets
if (DisablePathAndQueryCanonicalization)
{
if (buildIriStringFromPath)
{
DebugAssertInCtor();
_string += _originalUnicodeString.Substring(origIdx);
}

string str = _string;

if (IsImplicitFile || (syntaxFlags & UriSyntaxFlags.MayHaveQuery) == 0)
{
idx = str.Length;
}
else
{
idx = str.IndexOf('?');
if (idx == -1)
{
idx = str.Length;
}
}

_info.Offset.Query = (ushort)idx;
_info.Offset.Fragment = (ushort)str.Length; // There is no fragment in UseRawTarget mode
_info.Offset.End = (ushort)str.Length;

goto Done;
}

//Some uris do not have a query
// When '?' is passed as delimiter, then it's special case
// so both '?' and '#' will work as delimiters
if (buildIriStringFromPath)
{
DebugAssertInCtor();

int offset = origIdx;
if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0))
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Private.Uri/src/System/UriCreationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System
{
public struct UriCreationOptions
{
public bool DangerousDisablePathAndQueryCanonicalization { readonly get; set; }
}
}
33 changes: 31 additions & 2 deletions src/libraries/System.Private.Uri/src/System/UriExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class Uri
//
// All public ctors go through here
//
private void CreateThis(string? uri, bool dontEscape, UriKind uriKind)
private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCreationOptions creationOptions = default)
{
DebugAssertInCtor();

Expand All @@ -31,6 +31,9 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind)
if (dontEscape)
_flags |= Flags.UserEscaped;

if (creationOptions.DangerousDisablePathAndQueryCanonicalization)
_flags |= Flags.DisablePathAndQueryCanonicalization;

ParsingError err = ParseScheme(_string, ref _flags, ref _syntax!);

InitializeUri(err, uriKind, out UriFormatException? e);
Expand Down Expand Up @@ -259,6 +262,19 @@ public static bool TryCreate([NotNullWhen(true)] string? uriString, UriKind uriK
return e is null && result != null;
}

public static bool TryCreate([NotNullWhen(true)] string? uriString, in UriCreationOptions creationOptions, [NotNullWhen(true)] out Uri? result)
{
if (uriString is null)
{
result = null;
return false;
}
UriFormatException? e = null;
result = CreateHelper(uriString, false, UriKind.Absolute, ref e, in creationOptions);
result?.DebugSetLeftCtor();
return e is null && result != null;
}

public static bool TryCreate(Uri? baseUri, string? relativeUri, [NotNullWhen(true)] out Uri? result)
{
if (TryCreate(relativeUri, UriKind.RelativeOrAbsolute, out Uri? relativeLink))
Expand Down Expand Up @@ -309,6 +325,16 @@ public static bool TryCreate(Uri? baseUri, Uri? relativeUri, [NotNullWhen(true)]
}

public string GetComponents(UriComponents components, UriFormat format)
{
if (DisablePathAndQueryCanonicalization && (components & (UriComponents.Path | UriComponents.Query)) != 0)
{
throw new InvalidOperationException(SR.net_uri_GetComponentsCalledWhenCanonicalizationDisabled);
}

return InternalGetComponents(components, format);
}

private string InternalGetComponents(UriComponents components, UriFormat format)
{
if (((components & UriComponents.SerializationInfoString) != 0) && components != UriComponents.SerializationInfoString)
throw new ArgumentOutOfRangeException(nameof(components), components, SR.net_uri_NotJustSerialization);
Expand Down Expand Up @@ -590,7 +616,7 @@ private Uri(Flags flags, UriParser? uriParser, string uri)
//
// a Uri.TryCreate() method goes through here.
//
internal static Uri? CreateHelper(string uriString, bool dontEscape, UriKind uriKind, ref UriFormatException? e)
internal static Uri? CreateHelper(string uriString, bool dontEscape, UriKind uriKind, ref UriFormatException? e, in UriCreationOptions creationOptions = default)
{
// if (!Enum.IsDefined(typeof(UriKind), uriKind)) -- We currently believe that Enum.IsDefined() is too slow
// to be used here.
Expand All @@ -606,6 +632,9 @@ private Uri(Flags flags, UriParser? uriParser, string uri)
if (dontEscape)
flags |= Flags.UserEscaped;

if (creationOptions.DangerousDisablePathAndQueryCanonicalization)
flags |= Flags.DisablePathAndQueryCanonicalization;

// We won't use User factory for these errors
if (err != ParsingError.None)
{
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/System.Private.Uri/src/System/UriScheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ protected virtual string GetComponents(Uri uri, UriComponents components, UriFor
if (!uri.IsAbsoluteUri)
throw new InvalidOperationException(SR.net_uri_NotAbsolute);

if (uri.DisablePathAndQueryCanonicalization && (components & (UriComponents.Path | UriComponents.Query)) != 0)
throw new InvalidOperationException(SR.net_uri_GetComponentsCalledWhenCanonicalizationDisabled);

return uri.GetComponentsHelper(components, format);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Compile Include="UriBuilderParameterTest.cs" />
<Compile Include="UriBuilderRefreshTest.cs" />
<Compile Include="UriBuilderTests.cs" />
<Compile Include="UriCreationOptionsTest.cs" />
<Compile Include="UriEscapingTest.cs" />
<Compile Include="UriGetComponentsTest.cs" />
<Compile Include="UriIpHostTest.cs" />
Expand Down
Loading