Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/libraries/System.Private.Uri/src/System/Uri.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3888,7 +3888,7 @@ private unsafe int CheckAuthorityHelper(char* pString, int idx, int length,
if (ch == '[' && syntax.InFact(UriSyntaxFlags.AllowIPv6Host) &&
IPv6AddressHelper.IsValid(pString, start + 1, ref end))
{
if (end < length && pString[end] is not (':' or '/' or '?' or '#'))
if (end < length && pString[end] is not (':' or '/' or '\\' or '?' or '#'))
{
// A valid IPv6 address wasn't followed by a valid delimiter (e.g. http://[::]extra).
flags |= Flags.UnknownHostType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,20 +378,61 @@ private void ParseIPv6Address(string ipv6String, string expected)
// CheckHostName
Assert.Equal(UriHostNameType.IPv6, Uri.CheckHostName(ipv6String));

// IP followed by extra chars without a valid delimiter is invalid
Assert.False(Uri.TryCreate($"http://[{ipv6String}]extra", UriKind.Absolute, out _));
Assert.False(Uri.TryCreate($"http://[{ipv6String}] extra", UriKind.Absolute, out _));
Assert.False(Uri.TryCreate($"http://[{ipv6String}]\\extra", UriKind.Absolute, out _));

CheckProperties(new Uri($"http://[{ipv6String}] "));
CheckProperties(new Uri($"http://[{ipv6String}]/extra"), path: "/extra");
CheckProperties(new Uri($"http://[{ipv6String}]:"));
CheckProperties(new Uri($"http://[{ipv6String}]:123"), 123);
CheckProperties(new Uri($"http://[{ipv6String}]?extra"), query: "?extra");
CheckProperties(new Uri($"http://[{ipv6String}]#extra"), fragment: "#extra");

void CheckProperties(Uri uri, int port = 80, string path = "/", string query = "", string fragment = "")
// Various combinations of different schemes and suffixes
TestSuffixes("http://", 80);
TestSuffixes("custom-scheme://", -1);
TestSuffixes("file://", -1, backslashIsAllowed: true); // UNC path
TestSuffixes("file:////", -1, backslashIsAllowed: true); // UNC path
TestSuffixes("\\\\", -1, backslashIsAllowed: true, implicitFile: true); // UNC path

if (!UriParser.IsKnownScheme("parse-ip-file-based-scheme"))
{
UriParser.Register(new FileStyleUriParser(), "parse-ip-file-based-scheme", -1);
UriParser.Register(new HttpStyleUriParser(), "parse-ip-http-based-scheme", 12345);
}

TestSuffixes("parse-ip-file-based-scheme://", -1, backslashIsAllowed: true);
TestSuffixes("parse-ip-http-based-scheme://", 12345);

void TestSuffixes(string prefix, int port, bool backslashIsAllowed = false, bool implicitFile = false)
{
// IP followed by extra chars without a valid delimiter is invalid
Assert.False(Uri.TryCreate($"{prefix}[{ipv6String}]extra", UriKind.Absolute, out _));
Assert.False(Uri.TryCreate($"{prefix}[{ipv6String}] extra", UriKind.Absolute, out _));

// Some schemes (particularly file) allow backslashes to separate the host and path
if (backslashIsAllowed)
{
CheckProperties(new Uri($"{prefix}[{ipv6String}]\\extra"), implicitFile, port, path: "/extra");
}
else
{
Assert.False(Uri.TryCreate($"{prefix}[{ipv6String}]\\extra", UriKind.Absolute, out _));
}

// Regular delimiters like ? and # are allowed
CheckProperties(new Uri($"{prefix}[{ipv6String}] "), implicitFile, port);
CheckProperties(new Uri($"{prefix}[{ipv6String}]/extra"), implicitFile, port, path: "/extra");
CheckProperties(new Uri($"{prefix}[{ipv6String}]?extra"), implicitFile, port, query: "?extra");
CheckProperties(new Uri($"{prefix}[{ipv6String}]#extra"), implicitFile, port, fragment: "#extra");

if (port >= 0)
{
CheckProperties(new Uri($"{prefix}[{ipv6String}]:"), implicitFile, port);
CheckProperties(new Uri($"{prefix}[{ipv6String}]:123"), implicitFile, 123);
}
}

void CheckProperties(Uri uri, bool implicitFile = false, int port = 80, string path = "/", string query = "", string fragment = "")
{
if (implicitFile)
{
// Implicit file paths don't support queries/fragments, everything is treated as the path
path += Uri.EscapeDataString(query) + Uri.EscapeDataString(fragment);
query = "";
fragment = "";
}

Assert.Equal(UriHostNameType.IPv6, uri.HostNameType);
Assert.Equal(expectedResultWithBrackets, uri.Host);
Assert.Equal(expected, uri.DnsSafeHost);
Expand Down
Loading