Added verbose, rambling, log warning to help users with config issues (hoping to reduce false issues reports).

Also added a test to exercise it, which is perhaps silly but convenient.
This commit is contained in:
WizardOfYendor1
2026-07-17 12:02:09 -04:00
parent 97e666c566
commit 0c7428f136
2 changed files with 133 additions and 0 deletions
@@ -562,6 +562,95 @@ namespace Jellyfin.Networking.Tests
Assert.Null(port);
}
[Theory]
// Full-URL override with a different public path: warn about the Live TV fallback.
[InlineData("all=https://media.example.com", "/jellyfin", true)]
// Full-URL override that ends with the base URL (with and without a trailing slash): no warning.
[InlineData("all=https://media.example.com/jellyfin", "/jellyfin", false)]
[InlineData("all=https://media.example.com/jellyfin/", "/jellyfin", false)]
[InlineData("all=https://media.example.com/media/jellyfin", "/jellyfin", false)]
[InlineData("all=https://media.example.com/cool%20server", "/cool server", false)]
// A similar segment or a path following the base URL is a different public API base.
[InlineData("all=https://media.example.com/jellyfinx", "/jellyfin", true)]
[InlineData("all=https://media.example.com/jellyfin/media", "/jellyfin", true)]
// No base URL configured: there is no path to compare.
[InlineData("all=https://media.example.com", "", false)]
// Bare host overrides get the base URL appended when the API URL is built: no warning.
[InlineData("all=media.example.com", "/jellyfin", false)]
[InlineData("internal=http-proxy.lan:8097", "/jellyfin", false)]
// Keyword overrides go through the same check as "all".
[InlineData("internal=http://10.0.0.5:8096", "/jellyfin", true)]
public void InitializeOverrides_FullUrlPublicPathDiffersFromBaseUrl_LogsWarning(string publishedServers, string baseUrl, bool expectWarning)
{
var conf = new NetworkConfiguration
{
LocalNetworkSubnets = new[] { "192.168.1.0/24" },
LocalNetworkAddresses = new[] { "eth16" },
EnableIPv4 = true,
PublishedServerUriBySubnet = new[] { publishedServers },
BaseUrl = baseUrl
};
var logger = new Mock<ILogger<NetworkManager>>();
NetworkManager.MockNetworkSettings = "192.168.1.208/24,-16,eth16";
var startupConf = new Mock<IConfiguration>();
using var nm = new NetworkManager(NetworkParseTests.GetMockConfig(conf), startupConf.Object, logger.Object);
NetworkManager.MockNetworkSettings = string.Empty;
VerifyBaseUrlWarning(logger, expectWarning ? Times.AtLeastOnce() : Times.Never());
}
/// <summary>
/// The JELLYFIN_PublishedServerUrl environment variable / --published-server-url option takes the
/// startup-configuration branch of <c>InitializeOverrides</c> and must funnel through the same
/// base URL check as the dashboard overrides.
/// </summary>
[Fact]
public void InitializeOverrides_StartupPublishedServerUrlPathDiffersFromBaseUrl_LogsWarningWithoutCredentials()
{
var conf = new NetworkConfiguration
{
LocalNetworkSubnets = new[] { "192.168.1.0/24" },
LocalNetworkAddresses = new[] { "eth16" },
EnableIPv4 = true,
BaseUrl = "/jellyfin"
};
var logger = new Mock<ILogger<NetworkManager>>();
var startupConf = new Mock<IConfiguration>();
startupConf.Setup(x => x[MediaBrowser.Controller.Extensions.ConfigurationExtensions.AddressOverrideKey]).Returns("https://user:password@media.example.com?access_token=secret#fragment");
NetworkManager.MockNetworkSettings = "192.168.1.208/24,-16,eth16";
using var nm = new NetworkManager(NetworkParseTests.GetMockConfig(conf), startupConf.Object, logger.Object);
NetworkManager.MockNetworkSettings = string.Empty;
VerifyBaseUrlWarning(logger, Times.AtLeastOnce());
logger.Verify(
l => l.Log(
LogLevel.Warning,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((state, _) => state.ToString()!.Contains("user", StringComparison.Ordinal)
|| state.ToString()!.Contains("password", StringComparison.Ordinal)
|| state.ToString()!.Contains("access_token", StringComparison.Ordinal)
|| state.ToString()!.Contains("secret", StringComparison.Ordinal)
|| state.ToString()!.Contains("fragment", StringComparison.Ordinal)),
It.IsAny<Exception?>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Never());
}
private static void VerifyBaseUrlWarning(Mock<ILogger<NetworkManager>> logger, Times times)
{
logger.Verify(
l => l.Log(
LogLevel.Warning,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((state, _) => state.ToString()!.Contains("Jellyfin will append this base URL when generating Live TV client URLs", StringComparison.Ordinal)),
It.IsAny<Exception?>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
times);
}
/// <summary>
/// <see cref="NetworkManager.GetBindAddress(HttpRequest, out int?)"/> is the piece of request-host
/// normalization that a request-host-aware smart API URL policy relies on: it resolves the bind address