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
51 changes: 21 additions & 30 deletions src/libraries/System.Private.Uri/src/System/Uri.cs
Original file line number Diff line number Diff line change
Expand Up @@ -700,41 +700,32 @@ private static void GetCombinedString(Uri baseUri, string relativeStr,
}
}

private static UriFormatException? GetException(ParsingError err)
private static UriFormatException GetException(ParsingError err)
{
switch (err)
Debug.Assert(err != ParsingError.None);

string message = err switch
{
case ParsingError.None:
return null;
// Could be OK for Relative Uri
case ParsingError.BadFormat:
return new UriFormatException(SR.net_uri_BadFormat);
case ParsingError.BadScheme:
return new UriFormatException(SR.net_uri_BadScheme);
case ParsingError.BadAuthority:
return new UriFormatException(SR.net_uri_BadAuthority);
case ParsingError.EmptyUriString:
return new UriFormatException(SR.net_uri_EmptyUri);
ParsingError.BadFormat => SR.net_uri_BadFormat,
ParsingError.BadScheme => SR.net_uri_BadScheme,
ParsingError.BadAuthority => SR.net_uri_BadAuthority,
ParsingError.EmptyUriString => SR.net_uri_EmptyUri,

// Fatal
case ParsingError.SchemeLimit:
return new UriFormatException(SR.net_uri_SchemeLimit);
case ParsingError.MustRootedPath:
return new UriFormatException(SR.net_uri_MustRootedPath);
ParsingError.SchemeLimit => SR.net_uri_SchemeLimit,
ParsingError.MustRootedPath => SR.net_uri_MustRootedPath,

// Derived class controllable
case ParsingError.BadHostName:
return new UriFormatException(SR.net_uri_BadHostName);
case ParsingError.NonEmptyHost: //unix-only
return new UriFormatException(SR.net_uri_BadFormat);
case ParsingError.BadPort:
return new UriFormatException(SR.net_uri_BadPort);
case ParsingError.BadAuthorityTerminator:
return new UriFormatException(SR.net_uri_BadAuthorityTerminator);
case ParsingError.CannotCreateRelative:
return new UriFormatException(SR.net_uri_CannotCreateRelative);
default:
break;
}
return new UriFormatException(SR.net_uri_BadFormat);
ParsingError.BadHostName => SR.net_uri_BadHostName,
ParsingError.BadPort => SR.net_uri_BadPort,
ParsingError.BadAuthorityTerminator => SR.net_uri_BadAuthorityTerminator,
ParsingError.CannotCreateRelative => SR.net_uri_CannotCreateRelative,

_ => throw new UnreachableException()
};

return new UriFormatException(message);
}

public string AbsolutePath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ internal enum ParsingError

// derived class controlled
BadHostName,
NonEmptyHost, // unix only
BadPort,
BadAuthorityTerminator,

Expand Down
233 changes: 97 additions & 136 deletions src/libraries/System.Private.Uri/src/System/UriExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
{
DebugAssertInCtor();

if ((int)uriKind < (int)UriKind.RelativeOrAbsolute || (int)uriKind > (int)UriKind.Relative)
if (uriKind is < UriKind.RelativeOrAbsolute or > UriKind.Relative)
{
throw new ArgumentException(SR.Format(SR.net_uri_InvalidUriKind, uriKind));
}
Expand All @@ -38,176 +38,137 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre

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

InitializeUri(err, uriKind, out UriFormatException? e);
UriFormatException? e = InitializeUri(err, uriKind);
if (e != null)
throw e;
}

private void InitializeUri(ParsingError err, UriKind uriKind, out UriFormatException? e)
private UriFormatException? InitializeUri(ParsingError err, UriKind uriKind)
{
DebugAssertInCtor();
Debug.Assert((err is ParsingError.None) == (_syntax is not null));

bool hasUnicode = false;

if (err == ParsingError.None)
if (IriParsing && CheckForUnicodeOrEscapedUnreserved(_string))
{
_flags |= Flags.HasUnicode;
hasUnicode = true;
_originalUnicodeString = _string; // original string location changed
}

if (err != ParsingError.None)
{
if (IsImplicitFile)
// If we encountered any parsing errors that indicate this may be a relative Uri,
// and we'll allow relative Uri's, then create one.
if (uriKind != UriKind.Absolute && err <= ParsingError.LastErrorOkayForRelativeUris)
{
// V1 compat
// A relative Uri wins over implicit UNC path unless the UNC path is of the form "\\something" and
// uriKind != Absolute
// A relative Uri wins over implicit Unix path unless uriKind == Absolute
if (NotAny(Flags.DosPath) &&
uriKind != UriKind.Absolute &&
((uriKind == UriKind.Relative || (_string.Length >= 2 && (_string[0] != '\\' || _string[1] != '\\')))
|| (!OperatingSystem.IsWindows() && InFact(Flags.UnixPath))))
{
_syntax = null!; //make it be relative Uri
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
e = null;
return;
// Otherwise an absolute file Uri wins when it's of the form "\\something"
}
//
// V1 compat issue
// We should support relative Uris of the form c:\bla or c:/bla
//
else if (uriKind == UriKind.Relative && InFact(Flags.DosPath))
_flags &= Flags.UserEscaped | Flags.HasUnicode; // the only flags that makes sense for a relative uri
if (hasUnicode)
{
_syntax = null!; //make it be relative Uri
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
e = null;
return;
// Otherwise an absolute file Uri wins when it's of the form "c:\something"
// Iri'ze and then normalize relative uris
_string = EscapeUnescapeIri(_originalUnicodeString, 0, _originalUnicodeString.Length, isQuery: false);
}
return null;
}
}
else if (err > ParsingError.LastErrorOkayForRelativeUris)
{
//This is a fatal error based solely on scheme name parsing

// This is a fatal error based solely on scheme name parsing
_string = null!; // make it be invalid Uri
e = GetException(err);
return;
return GetException(err);
}

bool hasUnicode = false;
Debug.Assert(_syntax is not null);

if (IriParsing && CheckForUnicodeOrEscapedUnreserved(_string))
if (IsImplicitFile)
{
_flags |= Flags.HasUnicode;
hasUnicode = true;
// switch internal strings
_originalUnicodeString = _string; // original string location changed
if (uriKind == UriKind.Relative)
{
_syntax = null!; // make it be relative Uri
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
return null;
}

// V1 compat
// A relative Uri wins over implicit UNC path unless the UNC path is of the form "\\something" and
// uriKind != Absolute
// A relative Uri wins over implicit Unix path unless uriKind == Absolute
if (NotAny(Flags.DosPath) && uriKind == UriKind.RelativeOrAbsolute &&
((_string.Length >= 2 && (_string[0] != '\\' || _string[1] != '\\'))
|| (!OperatingSystem.IsWindows() && InFact(Flags.UnixPath))))
{
_syntax = null!; //make it be relative Uri
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
return null;
// Otherwise an absolute file Uri wins when it's of the form "\\something"
}
}

if (_syntax != null)
if (_syntax.IsSimple)
{
if (_syntax.IsSimple)
if ((err = PrivateParseMinimal()) != ParsingError.None)
{
if ((err = PrivateParseMinimal()) != ParsingError.None)
{
if (uriKind != UriKind.Absolute && err <= ParsingError.LastErrorOkayForRelativeUris)
{
// RFC 3986 Section 5.4.2 - http:(relativeUri) may be considered a valid relative Uri.
_syntax = null!; // convert to relative uri
e = null;
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
return;
}
else
e = GetException(err);
}
else if (uriKind == UriKind.Relative)
if (uriKind != UriKind.Absolute && err <= ParsingError.LastErrorOkayForRelativeUris)
{
// Here we know that we can create an absolute Uri, but the user has requested only a relative one
e = GetException(ParsingError.CannotCreateRelative);
// RFC 3986 Section 5.4.2 - http:(relativeUri) may be considered a valid relative Uri.
_syntax = null!; // convert to relative uri
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
return null;
}
else
e = null;
// will return from here

if (e is null && hasUnicode)
{
// In this scenario we need to parse the whole string
try
{
EnsureParseRemaining();
}
catch (UriFormatException ex)
{
e = ex;
}
}
return GetException(err);
}
else

if (uriKind == UriKind.Relative)
{
// offer custom parser to create a parsing context
_syntax = _syntax.InternalOnNewUri();
// Here we know that we can create an absolute Uri, but the user has requested only a relative one
return GetException(ParsingError.CannotCreateRelative);
}
}
else
{
// offer custom parser to create a parsing context
_syntax = _syntax.InternalOnNewUri();

// in case they won't call us
_flags |= Flags.UserDrivenParsing;
// in case they won't call us
_flags |= Flags.UserDrivenParsing;

// Ask a registered type to validate this uri
_syntax.InternalValidate(this, out e);
// Ask a registered type to validate this uri
_syntax.InternalValidate(this, out UriFormatException? e);

if (e != null)
{
// Can we still take it as a relative Uri?
if (uriKind != UriKind.Absolute && err != ParsingError.None
&& err <= ParsingError.LastErrorOkayForRelativeUris)
{
_syntax = null!; // convert it to relative
e = null;
_flags &= Flags.UserEscaped; // the only flag that makes sense for a relative uri
}
}
else // e == null
{
if (err != ParsingError.None || InFact(Flags.ErrorOrParsingRecursion))
{
// User parser took over on an invalid Uri
// we use = here to clear all parsing flags for a uri that we think is invalid.
_flags = Flags.UserDrivenParsing | (_flags & Flags.UserEscaped);
}
else if (uriKind == UriKind.Relative)
{
// Here we know that custom parser can create an absolute Uri, but the user has requested only a
// relative one
e = GetException(ParsingError.CannotCreateRelative);
}
if (e is not null)
{
return e;
}

if (e is null && hasUnicode)
{
// In this scenario we need to parse the whole string
try
{
EnsureParseRemaining();
}
catch (UriFormatException ex)
{
e = ex;
}
}
}
// will return from here
if (InFact(Flags.ErrorOrParsingRecursion))
{
// User parser took over on an invalid Uri
// we use = here to clear all parsing flags for a uri that we think is invalid.
_flags = Flags.UserDrivenParsing | (_flags & Flags.UserEscaped);
}
}
// If we encountered any parsing errors that indicate this may be a relative Uri,
// and we'll allow relative Uri's, then create one.
else if (err != ParsingError.None && uriKind != UriKind.Absolute
&& err <= ParsingError.LastErrorOkayForRelativeUris)
{
e = null;
_flags &= (Flags.UserEscaped | Flags.HasUnicode); // the only flags that makes sense for a relative uri
if (hasUnicode)
else if (uriKind == UriKind.Relative)
{
// Iri'ze and then normalize relative uris
_string = EscapeUnescapeIri(_originalUnicodeString, 0, _originalUnicodeString.Length, isQuery: false);
// Here we know that custom parser can create an absolute Uri, but the user has requested only a
// relative one
return GetException(ParsingError.CannotCreateRelative);
}
}
else

if (hasUnicode)
{
_string = null!; // make it be invalid Uri
e = GetException(err);
// In this scenario we need to parse the whole string
try
{
EnsureParseRemaining();
}
catch (UriFormatException ex)
{
return ex;
}
}

// We have a valid absolute Uri.
return null;
}

/// <summary>SearchValues for all ASCII characters other than %</summary>
Expand Down Expand Up @@ -742,7 +703,7 @@ private Uri(Flags flags, UriParser? uriParser, string uri)
// Validate instance using ether built in or a user Parser
try
{
result.InitializeUri(err, uriKind, out e);
e = result.InitializeUri(err, uriKind);

if (e == null)
{
Expand Down
Loading