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
17 changes: 6 additions & 11 deletions BrowseRouter/Model/UriFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@ namespace BrowseRouter.Model;

public static class UriFactory
{
public static Uri Get(string url)
public static Uri? Get(string url) => url switch
{
try
{
return new Uri(WebUtility.UrlDecode(url));
}
catch (UriFormatException)
{
// Try to prepend https when given an incomplete URI e.g. "google.com"
return new Uri($"https://{url}");
}
}
_ when Uri.TryCreate(url, UriKind.Absolute, out var uri) => uri,
_ when Uri.TryCreate($"https://{url}", UriKind.Absolute, out var uri) => uri,
_ when Uri.TryCreate(WebUtility.UrlDecode(url), UriKind.Absolute, out var uri) => uri,
_ => null,
};
}
9 changes: 8 additions & 1 deletion BrowseRouter/Services/BrowserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ public async Task LaunchAsync(string rawUrl, string windowTitle)

IEnumerable<UrlPreference> urlPreferences = config.GetUrlPreferences(ConfigType.Urls);
IEnumerable<UrlPreference> sourcePreferences = config.GetUrlPreferences(ConfigType.Sources);
Uri uri = UriFactory.Get(url);
Uri? uri = UriFactory.Get(url);

if (uri is null)
{
Log.Write($"Invalid URL: {url}");
await notifier.NotifyAsync("Error", $"Invalid URL: {url}");
return;
}

UrlPreference? pref = null;
if (sourcePreferences.TryGetPreference(windowTitle, out UrlPreference sourcePref))
Expand Down
6 changes: 3 additions & 3 deletions BrowseRouter/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ ff = %ProgramFiles%\Mozilla Firefox\firefox.exe
chrome = %ProgramFiles%\Google\Chrome\Application\chrome.exe

[urls]
*.google.com = chrome
*.visualstudio.com = edge
*.mozilla.org = ff
*google.com = chrome
*microsoft.com = edge
*mozilla.org = ff

[sources]
*Microsoft Teams* = edge
Expand Down
6 changes: 3 additions & 3 deletions BrowseRouter/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"enabled": true
},
"urls": {
"*.google.com": "chrome",
"*.visualstudio.com": "edge",
"*.mozilla.org": "ff"
"*google.com": "chrome",
"*microsoft.com": "edge",
"*mozilla.org": "ff"
},
"browsers": {
"edge": "%ProgramFiles(x86)%\\Microsoft\\Edge\\Application\\msedge.exe",
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<Version>0.15.6</Version>
<Version>0.16.0</Version>
<Product>BrowseRouter</Product>
<Copyright>EnduraByte LLC 2025</Copyright>
<!-- Reduces flagging as malware -->
Expand Down
14 changes: 14 additions & 0 deletions Tests/BrowseRouter.Tests/Model/ArgsTests/FormatMethod.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using BrowseRouter.Model;

namespace BrowseRouter.Tests.Model.ArgsTests;

public class FormatMethod
{
[Fact]
public void DoesNotDecodeQueryString()
{
string result = Args.Format("", new Uri("https://www.google.com/search?q=C%23+Rocks"));

result.Should().NotContain("C# Rocks");
}
}
37 changes: 28 additions & 9 deletions Tests/BrowseRouter.Tests/Model/UriFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,45 @@ public class GetMethod
public void HandlesValidUrl()
{
string url = "https://www.example.com/path";
var act = () => UriFactory.Get(url);
var uri = UriFactory.Get(url);

act.Should().NotThrow<UriFormatException>();
uri?.AbsoluteUri.Should().Be("https://www.example.com/path");
}

[Fact]
public void HandlesUrlWithoutHttps()
public void PrependsHttps_ForUrlWithoutScheme()
{
string url = "www.example.com/path";
var act = () => UriFactory.Get(url);
var uri = UriFactory.Get(url);

act.Should().NotThrow<UriFormatException>();
uri?.Scheme.Should().Be("https");
uri?.AbsoluteUri.Should().Be("https://www.example.com/path");
}

[Fact]
public void HandlesUrlEncodedUrl()
public void DecodesUrlEncodedUrl()
{
string url = "https%3A%2F%2Fwww.example.com%2Fpath%2F";
var act = () => UriFactory.Get(url);
string url = "https%3A%2F%2Fwww.example.com%2Fpath";
var uri = UriFactory.Get(url);

act.Should().NotThrow<UriFormatException>();
uri?.AbsoluteUri.Should().Be("https://www.example.com/path");
}

[Fact]
public void PreservesQueryParameters()
{
string url = "https://www.example.com/path?token=6Us%2btD%2btWmVr";
var uri = UriFactory.Get(url);

uri?.Query.Should().Be("?token=6Us%2btD%2btWmVr");
}

[Fact]
public void ReturnsNull_ForInvalidUrl()
{
string url = "";
var uri = UriFactory.Get(url);

uri.Should().BeNull();
}
}