diff --git a/src/libraries/System.Private.Uri/src/System/Uri.cs b/src/libraries/System.Private.Uri/src/System/Uri.cs index 9a8d500e77c3b1..60c279e020b2a1 100644 --- a/src/libraries/System.Private.Uri/src/System/Uri.cs +++ b/src/libraries/System.Private.Uri/src/System/Uri.cs @@ -3888,6 +3888,14 @@ 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 '#')) + { + // A valid IPv6 address wasn't followed by a valid delimiter (e.g. http://[::]extra). + flags |= Flags.UnknownHostType; + err = ParsingError.BadHostName; + return idx; + } + flags |= Flags.IPv6HostType; if (hasUnicode) diff --git a/src/libraries/System.Private.Uri/tests/FunctionalTests/UriIpHostTest.cs b/src/libraries/System.Private.Uri/tests/FunctionalTests/UriIpHostTest.cs index 6f1eecca2c057a..cd9b55186d91d9 100644 --- a/src/libraries/System.Private.Uri/tests/FunctionalTests/UriIpHostTest.cs +++ b/src/libraries/System.Private.Uri/tests/FunctionalTests/UriIpHostTest.cs @@ -369,18 +369,37 @@ private void ParseIPv6Address(string ipv6String, string expected) // TryCreate Assert.True(Uri.TryCreate($"http://[{ipv6String}]", UriKind.Absolute, out Uri testUri), ipv6String); - Assert.Equal(UriHostNameType.IPv6, testUri.HostNameType); - Assert.Equal(expectedResultWithBrackets, testUri.Host); - Assert.Equal(expected, testUri.DnsSafeHost); + CheckProperties(testUri); // Constructor testUri = new Uri($"http://[{ipv6String}]"); - Assert.Equal(UriHostNameType.IPv6, testUri.HostNameType); - Assert.Equal(expectedResultWithBrackets, testUri.Host); - Assert.Equal(expected, testUri.DnsSafeHost); + CheckProperties(testUri); // 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 = "") + { + Assert.Equal(UriHostNameType.IPv6, uri.HostNameType); + Assert.Equal(expectedResultWithBrackets, uri.Host); + Assert.Equal(expected, uri.DnsSafeHost); + Assert.Equal(port, uri.Port); + Assert.Equal(path, uri.AbsolutePath); + Assert.Equal(query, uri.Query); + Assert.Equal(fragment, uri.Fragment); + } } private void ParseBadIPv6Address(string badIpv6String)