diff --git a/Microsoft.Maui-dev.sln b/Microsoft.Maui-dev.sln index efaad84182ac..a31db7a6b1ac 100644 --- a/Microsoft.Maui-dev.sln +++ b/Microsoft.Maui-dev.sln @@ -133,6 +133,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A9C514B9 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.DeviceTests", "src\BlazorWebView\tests\DeviceTests\MauiBlazorWebView.DeviceTests.csproj", "{5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.UnitTests", "src\BlazorWebView\tests\MauiBlazorWebView.UnitTests\MauiBlazorWebView.UnitTests.csproj", "{00E708AA-402D-4BB5-AD88-348274F8E1DF}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedSource", "SharedSource", "{4F2926C8-43AB-4328-A735-D9EAD699F81D}" ProjectSection(SolutionItems) = preProject src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs = src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs @@ -463,6 +465,10 @@ Global {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Build.0 = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Deploy.0 = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.Build.0 = Release|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Build.0 = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -746,6 +752,7 @@ Global {71FFE8BF-EBE4-4078-8484-86C6EA685D14} = {50C758FE-4E10-409A-94F5-A75480960864} {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} = {1614D1A4-5C3D-4D5B-8C89-426E37A564EF} {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} + {00E708AA-402D-4BB5-AD88-348274F8E1DF} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} {4F2926C8-43AB-4328-A735-D9EAD699F81D} = {ED7F28E0-D0AF-417D-983D-3D874EEE8554} {5B56A734-D53C-4635-A53E-F889FCFCDD66} = {C564DDD6-DE79-45CD-88EA-3F690481572A} {E8728693-3537-4007-A4DB-9F9634548755} = {E8AD265B-3C67-4640-AC58-A522F9FB3361} diff --git a/Microsoft.Maui-mac.slnf b/Microsoft.Maui-mac.slnf index 623e1571661a..57f6a7e0562b 100644 --- a/Microsoft.Maui-mac.slnf +++ b/Microsoft.Maui-mac.slnf @@ -11,6 +11,7 @@ "src\\BlazorWebView\\samples\\WebViewAppShared\\WebViewAppShared.csproj", "src\\BlazorWebView\\src\\Maui\\Microsoft.AspNetCore.Components.WebView.Maui.csproj", "src\\BlazorWebView\\tests\\DeviceTests\\MauiBlazorWebView.DeviceTests.csproj", + "src\\BlazorWebView\\tests\\MauiBlazorWebView.UnitTests\\MauiBlazorWebView.UnitTests.csproj", "src\\Controls\\Foldable\\src\\Controls.Foldable.csproj", "src\\Controls\\Maps\\src\\Controls.Maps.csproj", "src\\Controls\\samples\\Controls.Sample.Profiling\\Maui.Controls.Sample.Profiling.csproj", @@ -71,4 +72,4 @@ "src\\Workload\\Microsoft.NET.Sdk.Maui.Manifest\\Microsoft.NET.Sdk.Maui.Manifest.csproj" ] } -} \ No newline at end of file +} diff --git a/Microsoft.Maui-vscode.sln b/Microsoft.Maui-vscode.sln index 3e88b3db593e..eb588bd623bc 100644 --- a/Microsoft.Maui-vscode.sln +++ b/Microsoft.Maui-vscode.sln @@ -125,6 +125,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A9C514B9 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.DeviceTests", "src\BlazorWebView\tests\DeviceTests\MauiBlazorWebView.DeviceTests.csproj", "{5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.UnitTests", "src\BlazorWebView\tests\MauiBlazorWebView.UnitTests\MauiBlazorWebView.UnitTests.csproj", "{00E708AA-402D-4BB5-AD88-348274F8E1DF}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedSource", "SharedSource", "{4F2926C8-43AB-4328-A735-D9EAD699F81D}" ProjectSection(SolutionItems) = preProject src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs = src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs @@ -414,6 +416,10 @@ Global {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Build.0 = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Deploy.0 = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.Build.0 = Release|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Build.0 = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -659,6 +665,7 @@ Global {71FFE8BF-EBE4-4078-8484-86C6EA685D14} = {50C758FE-4E10-409A-94F5-A75480960864} {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} = {1614D1A4-5C3D-4D5B-8C89-426E37A564EF} {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} + {00E708AA-402D-4BB5-AD88-348274F8E1DF} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} {4F2926C8-43AB-4328-A735-D9EAD699F81D} = {ED7F28E0-D0AF-417D-983D-3D874EEE8554} {5B56A734-D53C-4635-A53E-F889FCFCDD66} = {C564DDD6-DE79-45CD-88EA-3F690481572A} {E8728693-3537-4007-A4DB-9F9634548755} = {E8AD265B-3C67-4640-AC58-A522F9FB3361} diff --git a/Microsoft.Maui-windows.slnf b/Microsoft.Maui-windows.slnf index 4ed4c36e2225..00903f73421b 100644 --- a/Microsoft.Maui-windows.slnf +++ b/Microsoft.Maui-windows.slnf @@ -15,6 +15,7 @@ "src\\BlazorWebView\\src\\WindowsForms\\Microsoft.AspNetCore.Components.WebView.WindowsForms.csproj", "src\\BlazorWebView\\src\\Wpf\\Microsoft.AspNetCore.Components.WebView.Wpf.csproj", "src\\BlazorWebView\\tests\\DeviceTests\\MauiBlazorWebView.DeviceTests.csproj", + "src\\BlazorWebView\\tests\\MauiBlazorWebView.UnitTests\\MauiBlazorWebView.UnitTests.csproj", "src\\Controls\\Foldable\\src\\Controls.Foldable.csproj", "src\\Controls\\Maps\\src\\Controls.Maps.csproj", "src\\Controls\\samples\\Controls.Sample.Profiling\\Maui.Controls.Sample.Profiling.csproj", @@ -88,4 +89,4 @@ "src\\Workload\\Microsoft.NET.Sdk.Maui.Manifest\\Microsoft.NET.Sdk.Maui.Manifest.csproj" ] } -} \ No newline at end of file +} diff --git a/Microsoft.Maui.LegacyControlGallery.sln b/Microsoft.Maui.LegacyControlGallery.sln index e555b8990ce5..5a44235aa330 100644 --- a/Microsoft.Maui.LegacyControlGallery.sln +++ b/Microsoft.Maui.LegacyControlGallery.sln @@ -132,6 +132,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A9C514B9 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.DeviceTests", "src\BlazorWebView\tests\DeviceTests\MauiBlazorWebView.DeviceTests.csproj", "{5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.UnitTests", "src\BlazorWebView\tests\MauiBlazorWebView.UnitTests\MauiBlazorWebView.UnitTests.csproj", "{00E708AA-402D-4BB5-AD88-348274F8E1DF}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedSource", "SharedSource", "{4F2926C8-43AB-4328-A735-D9EAD699F81D}" ProjectSection(SolutionItems) = preProject src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs = src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs @@ -456,6 +458,10 @@ Global {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Build.0 = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Deploy.0 = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.Build.0 = Release|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Build.0 = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -737,6 +743,7 @@ Global {71FFE8BF-EBE4-4078-8484-86C6EA685D14} = {50C758FE-4E10-409A-94F5-A75480960864} {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} = {1614D1A4-5C3D-4D5B-8C89-426E37A564EF} {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} + {00E708AA-402D-4BB5-AD88-348274F8E1DF} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} {4F2926C8-43AB-4328-A735-D9EAD699F81D} = {ED7F28E0-D0AF-417D-983D-3D874EEE8554} {5B56A734-D53C-4635-A53E-F889FCFCDD66} = {C564DDD6-DE79-45CD-88EA-3F690481572A} {E8728693-3537-4007-A4DB-9F9634548755} = {E8AD265B-3C67-4640-AC58-A522F9FB3361} diff --git a/Microsoft.Maui.sln b/Microsoft.Maui.sln index 37c133515923..f3fd76fdc61d 100644 --- a/Microsoft.Maui.sln +++ b/Microsoft.Maui.sln @@ -140,6 +140,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A9C514B9 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.DeviceTests", "src\BlazorWebView\tests\DeviceTests\MauiBlazorWebView.DeviceTests.csproj", "{5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiBlazorWebView.UnitTests", "src\BlazorWebView\tests\MauiBlazorWebView.UnitTests\MauiBlazorWebView.UnitTests.csproj", "{00E708AA-402D-4BB5-AD88-348274F8E1DF}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SharedSource", "SharedSource", "{4F2926C8-43AB-4328-A735-D9EAD699F81D}" ProjectSection(SolutionItems) = preProject src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs = src\BlazorWebView\src\SharedSource\AutoCloseOnReadCompleteStream.cs @@ -469,6 +471,10 @@ Global {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Build.0 = Release|Any CPU {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6}.Release|Any CPU.Deploy.0 = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00E708AA-402D-4BB5-AD88-348274F8E1DF}.Release|Any CPU.Build.0 = Release|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Build.0 = Debug|Any CPU {5B56A734-D53C-4635-A53E-F889FCFCDD66}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -751,6 +757,7 @@ Global {71FFE8BF-EBE4-4078-8484-86C6EA685D14} = {50C758FE-4E10-409A-94F5-A75480960864} {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} = {1614D1A4-5C3D-4D5B-8C89-426E37A564EF} {5FEA7500-0ACE-4C26-9A7B-2EB3958CBBC6} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} + {00E708AA-402D-4BB5-AD88-348274F8E1DF} = {A9C514B9-1EE2-4A12-8E8A-CE16D87545C3} {4F2926C8-43AB-4328-A735-D9EAD699F81D} = {ED7F28E0-D0AF-417D-983D-3D874EEE8554} {5B56A734-D53C-4635-A53E-F889FCFCDD66} = {C564DDD6-DE79-45CD-88EA-3F690481572A} {E8728693-3537-4007-A4DB-9F9634548755} = {E8AD265B-3C67-4640-AC58-A522F9FB3361} diff --git a/eng/cake/dotnet.cake b/eng/cake/dotnet.cake index 09b7378ab229..86596fe5e78e 100644 --- a/eng/cake/dotnet.cake +++ b/eng/cake/dotnet.cake @@ -274,6 +274,7 @@ Task("dotnet-test") "**/Resizetizer.UnitTests.csproj", "**/Graphics.Tests.csproj", "**/Compatibility.Core.UnitTests.csproj", + "**/MauiBlazorWebView.UnitTests.csproj", }; var success = true; diff --git a/eng/helix.proj b/eng/helix.proj index 565ce270a50c..a6cae39a8567 100644 --- a/eng/helix.proj +++ b/eng/helix.proj @@ -37,6 +37,7 @@ + diff --git a/src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs b/src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs index 3767e19237c5..7e8b137b2fc8 100644 --- a/src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs +++ b/src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs @@ -1,20 +1,27 @@ using System; using System.IO; -namespace Microsoft.AspNetCore.Components.WebView.Maui +namespace Microsoft.AspNetCore.Components.WebView.Maui; + +internal static class UriExtensions { - internal static class UriExtensions + internal static bool IsBaseOfPage(this Uri baseUri, string? uriString) { - internal static bool IsBaseOfPage(this Uri baseUri, string? uriString) + if (string.IsNullOrWhiteSpace(uriString)) { - if (Path.HasExtension(uriString)) - { - // If the path ends in a file extension, it's not referring to a page. - return false; - } + return false; + } - var uri = new Uri(uriString!); - return baseUri.IsBaseOf(uri); + if (!Uri.TryCreate(uriString, UriKind.Absolute, out var uri)) + { + return false; } + + if (Path.HasExtension(uri.GetComponents(UriComponents.Path, UriFormat.Unescaped))) + { + return false; + } + + return baseUri.IsBaseOf(uri); } } diff --git a/src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs b/src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs index 75fc9e1e0adb..6ad8b3a8aa4b 100644 --- a/src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs +++ b/src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs @@ -1,6 +1,9 @@ using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.Internals; +using System.Runtime.CompilerServices; + [assembly: Preserve] [assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/2021/maui", "Microsoft.AspNetCore.Components.WebView.Maui")] +[assembly: InternalsVisibleTo("Microsoft.Maui.MauiBlazorWebView.UnitTests")] diff --git a/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj b/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj new file mode 100644 index 000000000000..0f164bfb04ea --- /dev/null +++ b/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj @@ -0,0 +1,26 @@ + + + + $(_MauiDotNetTfm) + enable + Microsoft.Maui.MauiBlazorWebView.UnitTests + Microsoft.Maui.MauiBlazorWebView.UnitTests + enable + false + + + + + + + + + + + + + + + + + diff --git a/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs b/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs new file mode 100644 index 000000000000..33ff4c061911 --- /dev/null +++ b/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs @@ -0,0 +1,81 @@ +using Microsoft.AspNetCore.Components.WebView.Maui; + +namespace Microsoft.Maui.MauiBlazorWebView.UnitTests; + +public class UriExtensions_Tests +{ + private readonly Uri _baseUri = new("https://example.com/"); + + [Theory] + [InlineData("https://example.com/page", true)] + [InlineData("page/subpage", false)] + [InlineData("this is not a uri!", false)] + [InlineData("https://example.com/", true)] + [InlineData("https://example.com/page/", true)] + [InlineData("https://example.com/page?weight=62.5", true)] + [InlineData("https://example.com/page#section.1", true)] + [InlineData("https://example.com/file.txt", false)] + [InlineData("https://example.com/page.json?foo=bar", false)] + [InlineData("ftp://example.com/page", false)] + [InlineData("/relative/path", false)] + [InlineData("", false)] + [InlineData(null, false)] + [InlineData("https://example.com/test", true)] + [InlineData("https://example.com/folder/subfolder/", true)] + [InlineData("https://example.com/folder/file.exe", false)] + [InlineData("https://subdomain.example.com/page", false)] + [InlineData("https://example.com/path/with/.dot/segment", true)] + [InlineData("https://example.com/path/with space", true)] + [InlineData("https://example.com/path/with%20encoded%20space", true)] + [InlineData("https://example.com/page?param=value¶m2=value2", true)] + [InlineData("https://example.com/page.html", false)] + [InlineData("HTTPS://EXAMPLE.COM/PAGE", true)] + [InlineData("https://subdomain.example.com/", false)] + [InlineData("https://subdomain.example.com/page/", false)] + [InlineData("https://subdomain.example.com/page?weight=62.5", false)] + [InlineData("https://subdomain.example.com/page#section.1", false)] + [InlineData("https://subdomain.example.com/file.txt", false)] + [InlineData("https://subdomain.example.com/page.json?foo=bar", false)] + [InlineData("ftp://subdomain.example.com/page", false)] + [InlineData("https://subdomain.example.com/test", false)] + [InlineData("https://subdomain.example.com/folder/subfolder/", false)] + [InlineData("https://subdomain.example.com/folder/file.exe", false)] + [InlineData("https://subdomain.example.com/path/with/.dot/segment", false)] + [InlineData("https://subdomain.example.com/path/with space", false)] + [InlineData("https://subdomain.example.com/path/with%20encoded%20space", false)] + [InlineData("https://subdomain.example.com/page?param=value¶m2=value2", false)] + [InlineData("https://subdomain.example.com/page.html", false)] + [InlineData("HTTPS://SUBDOMAIN.EXAMPLE.COM/PAGE", false)] + public void IsBaseOfPage_HandlesVariousUris(string? uriString, bool expected) + { + var result = _baseUri.IsBaseOfPage(uriString); + Assert.Equal(expected, result); + } + + // Regression test for https://github.com/dotnet/maui/issues/25689 + // A URL with a dot in the query parameter (e.g. ?weight=62.5) must not be + // treated as a file-extension path and must be allowed to fall back to the host page. + [Fact] + public void IsBaseOfPage_DoesNotTreatDotInQueryAsExtension() + { + var baseUri = new Uri("https://example.com"); + var urlWithDotInQuery = "https://example.com/customer?weight=62.5"; + Assert.True(baseUri.IsBaseOfPage(urlWithDotInQuery)); + } + + // Regression tests using the actual BlazorWebView platform app origins (https://github.com/dotnet/maui/issues/25689). + // Android/Windows use https://0.0.0.1/ and iOS/MacCatalyst use app://0.0.0.1/ as the host origin, + // so the original ?weight=62.5 bug must be verified against those real origins, not just a generic host. + [Theory] + [InlineData("https://0.0.0.1/", "https://0.0.0.1/customer?weight=62.5", true)] // Android/Windows: dot in query + [InlineData("https://0.0.0.1/", "https://0.0.0.1/customer#section.1", true)] // Android/Windows: dot in fragment + [InlineData("https://0.0.0.1/", "https://0.0.0.1/customer.json", false)] // Android/Windows: real file extension + [InlineData("app://0.0.0.1/", "app://0.0.0.1/customer?weight=62.5", true)] // iOS/MacCatalyst: dot in query + [InlineData("app://0.0.0.1/", "app://0.0.0.1/customer#section.1", true)] // iOS/MacCatalyst: dot in fragment + [InlineData("app://0.0.0.1/", "app://0.0.0.1/customer.json", false)] // iOS/MacCatalyst: real file extension + public void IsBaseOfPage_HandlesPlatformAppOrigins(string baseUri, string uriString, bool expected) + { + var result = new Uri(baseUri).IsBaseOfPage(uriString); + Assert.Equal(expected, result); + } +}