using System; using System.Threading.Tasks; using Jellyfin.Networking.Configuration; using MediaBrowser.Controller.Configuration; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using ConfigurationExtensions = MediaBrowser.Controller.Extensions.ConfigurationExtensions; namespace Jellyfin.Server.Middleware { /// /// Redirect requests without baseurl prefix to the baseurl prefixed URL. /// public class BaseUrlRedirectionMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly IConfiguration _configuration; /// /// Initializes a new instance of the class. /// /// The next delegate in the pipeline. /// The logger. /// The application configuration. public BaseUrlRedirectionMiddleware( RequestDelegate next, ILogger logger, IConfiguration configuration) { _next = next; _logger = logger; _configuration = configuration; } /// /// Executes the middleware action. /// /// The current HTTP context. /// The server configuration manager. /// The async task. public async Task Invoke(HttpContext httpContext, IServerConfigurationManager serverConfigurationManager) { var localPath = httpContext.Request.Path.ToString(); var baseUrlPrefix = serverConfigurationManager.GetNetworkConfiguration().BaseUrl; if (!string.IsNullOrEmpty(baseUrlPrefix)) { var startsWithBaseUrl = localPath.StartsWith(baseUrlPrefix, StringComparison.OrdinalIgnoreCase); if (!startsWithBaseUrl && (localPath.Equals("/health", StringComparison.OrdinalIgnoreCase) || localPath.Equals("/health/", StringComparison.OrdinalIgnoreCase))) { _logger.LogDebug("Redirecting /health check"); httpContext.Response.Redirect(baseUrlPrefix + "/health"); return; } if (!startsWithBaseUrl || localPath.Length == baseUrlPrefix.Length // Local path is /baseUrl/ || (localPath.Length == baseUrlPrefix.Length + 1 && localPath[^1] == '/')) { // Always redirect back to the default path if the base prefix is invalid, missing, or is the full path. _logger.LogDebug("Normalizing an URL at {LocalPath}", localPath); httpContext.Response.Redirect(baseUrlPrefix + "/" + _configuration[ConfigurationExtensions.DefaultRedirectKey]); return; } } else if (string.IsNullOrEmpty(localPath) || localPath.Equals("/", StringComparison.Ordinal)) { // Always redirect back to the default path if root is requested. _logger.LogDebug("Normalizing an URL at {LocalPath}", localPath); httpContext.Response.Redirect("/" + _configuration[ConfigurationExtensions.DefaultRedirectKey]); return; } await _next(httpContext).ConfigureAwait(false); } } }