diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 10a7e879e9..693b049cd8 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -1236,28 +1236,30 @@ namespace Emby.Server.Implementations
str.CopyTo(span.Slice(1));
span[^1] = ']';
- return GetLocalApiUrl(span).ToString();
+ return GetLocalApiUrl(span);
}
- return GetLocalApiUrl(ipAddress.ToString()).ToString();
+ return GetLocalApiUrl(ipAddress.ToString());
}
///
- public Uri GetLoopbackHttpApiUrl()
+ public string GetLoopbackHttpApiUrl()
{
return GetLocalApiUrl("127.0.0.1", Uri.UriSchemeHttp, HttpPort);
}
///
- public Uri GetLocalApiUrl(ReadOnlySpan host, string scheme = null, int? port = null)
+ public string GetLocalApiUrl(ReadOnlySpan host, string scheme = null, int? port = null)
{
+ // NOTE: If no BaseUrl is set then UriBuilder appends a trailing slash, but if there is no BaseUrl it does
+ // not. For consistency, always trim the trailing slash.
return new UriBuilder
{
Scheme = scheme ?? (ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp),
Host = host.ToString(),
Port = port ?? (ListenWithHttps ? HttpsPort : HttpPort),
Path = ServerConfigurationManager.Configuration.BaseUrl
- }.Uri;
+ }.ToString().TrimEnd('/');
}
public Task> GetLocalIpAddresses(CancellationToken cancellationToken)
@@ -1333,8 +1335,7 @@ namespace Emby.Server.Implementations
return true;
}
- var apiUrl = GetLocalApiUrl(address);
- apiUrl += "/system/ping";
+ var apiUrl = GetLocalApiUrl(address) + "/system/ping";
if (_validAddressResults.TryGetValue(apiUrl, out var cachedResult))
{
diff --git a/Emby.Server.Implementations/Browser/BrowserLauncher.cs b/Emby.Server.Implementations/Browser/BrowserLauncher.cs
index ccb733b3ca..7f7c6a0be4 100644
--- a/Emby.Server.Implementations/Browser/BrowserLauncher.cs
+++ b/Emby.Server.Implementations/Browser/BrowserLauncher.cs
@@ -31,18 +31,18 @@ namespace Emby.Server.Implementations.Browser
/// Opens the specified URL in an external browser window. Any exceptions will be logged, but ignored.
///
/// The application host.
- /// The URL.
- private static void TryOpenUrl(IServerApplicationHost appHost, string url)
+ /// The URL to open, relative to the server base URL.
+ private static void TryOpenUrl(IServerApplicationHost appHost, string relativeUrl)
{
try
{
- Uri baseUrl = appHost.GetLocalApiUrl("localhost");
- appHost.LaunchUrl(baseUrl + url);
+ string baseUrl = appHost.GetLocalApiUrl("localhost");
+ appHost.LaunchUrl(baseUrl + relativeUrl);
}
catch (Exception ex)
{
var logger = appHost.Resolve();
- logger?.LogError(ex, "Failed to open browser window with URL {URL}", url);
+ logger?.LogError(ex, "Failed to open browser window with URL {URL}", relativeUrl);
}
}
}
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 0028bd6893..4f0ff1ee12 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -76,7 +76,7 @@ namespace MediaBrowser.Controller
/// over HTTP (not HTTPS).
///
/// The API URL.
- public Uri GetLoopbackHttpApiUrl();
+ string GetLoopbackHttpApiUrl();
///
/// Gets a local (LAN) URL that can be used to access the API. HTTPS will be preferred when available.
@@ -98,7 +98,7 @@ namespace MediaBrowser.Controller
/// preferring the HTTPS port, if available.
///
/// The API URL.
- Uri GetLocalApiUrl(ReadOnlySpan hostname, string scheme = null, int? port = null);
+ string GetLocalApiUrl(ReadOnlySpan hostname, string scheme = null, int? port = null);
///
/// Open a URL in an external browser window.