Pārlūkot izejas kodu

Normalize baseUrl behaviour

Fully normalizes the baseUrl behaviour to better match how this sort of
feature works in other programs.

1. The baseUrl is always appended to paths, even the built-in `/emby`
and `/mediabrowser` paths.
2. The baseUrl is set statically at class instance creation, to ensure
it persists through changes until the next restart.
3. Configuration is normalized using a function when set, to ensure it's
in a standard `/mypath` format with leading `/`.
4. Cleans up the conditionals around default redirects. For sanity after
changing the URL, it will match *any* path that doesn't match the
current baseUrl and redirect it back to the main page (with baseUrl).
5. Adds a second method, NormalizeUrlPath, to avoid lots of `+ "/" +`
string manipulations which are unclean - we should always have a leading
slash.
6. Sets the default baseUrl to an empty string to avoid unexpected
behaviour, though this would be worked-around automatically.
7. Adds some debug logs whenever a URL is normalized, to help track down
issues with this code (if any arise).
Joshua Boniface 5 gadi atpakaļ
vecāks
revīzija
2a79ae0a6e

+ 34 - 39
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -39,6 +39,7 @@ namespace Emby.Server.Implementations.HttpServer
         private readonly IHttpListener _socketListener;
         private readonly IHttpListener _socketListener;
         private readonly Func<Type, Func<string, object>> _funcParseFn;
         private readonly Func<Type, Func<string, object>> _funcParseFn;
         private readonly string _defaultRedirectPath;
         private readonly string _defaultRedirectPath;
+        private readonly string _baseUrlPrefix;
         private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
         private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
         private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
         private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
         private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
         private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
@@ -58,6 +59,7 @@ namespace Emby.Server.Implementations.HttpServer
             _logger = logger;
             _logger = logger;
             _config = config;
             _config = config;
             _defaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
             _defaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
+            _baseUrlPrefix = _config.Configuration.BaseUrl;
             _networkManager = networkManager;
             _networkManager = networkManager;
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
             _xmlSerializer = xmlSerializer;
             _xmlSerializer = xmlSerializer;
@@ -87,6 +89,20 @@ namespace Emby.Server.Implementations.HttpServer
             return _appHost.CreateInstance(type);
             return _appHost.CreateInstance(type);
         }
         }
 
 
+        private string NormalizeUrlPath(string path)
+        {
+            if (path.StartsWith("/"))
+            {
+                // If the path begins with a leading slash, just return it as-is
+                return path;
+            }
+            else
+            {
+                // If the path does not begin with a leading slash, append one for consistency
+                return "/" + path;
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// Applies the request filters. Returns whether or not the request has been handled
         /// Applies the request filters. Returns whether or not the request has been handled
         /// and no more processing should be done.
         /// and no more processing should be done.
@@ -471,22 +487,15 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                 urlToLog = GetUrlToLog(urlString);
                 urlToLog = GetUrlToLog(urlString);
 
 
-                if (string.Equals(localPath, "/" + _config.Configuration.BaseUrl + "/", StringComparison.OrdinalIgnoreCase)
-                    || string.Equals(localPath, "/" + _config.Configuration.BaseUrl, StringComparison.OrdinalIgnoreCase))
-                {
-                    httpRes.Redirect("/" + _config.Configuration.BaseUrl + "/" + _defaultRedirectPath);
-                    return;
-                }
-
-                if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(localPath, _baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase)
+                    || string.Equals(localPath, _baseUrlPrefix, StringComparison.OrdinalIgnoreCase)
+                    || string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)
+                    || string.IsNullOrEmpty(localPath)
+                    || !localPath.StartsWith(_baseUrlPrefix))
                 {
                 {
-                    httpRes.Redirect(_defaultRedirectPath);
-                    return;
-                }
-
-                if (string.IsNullOrEmpty(localPath))
-                {
-                    httpRes.Redirect("/" + _defaultRedirectPath);
+                    // Always redirect back to the default path if the base prefix is invalid or missing
+                    _logger.LogDebug("Normalizing a URL at {0}", localPath);
+                    httpRes.Redirect(_baseUrlPrefix + "/" + _defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
@@ -596,7 +605,7 @@ namespace Emby.Server.Implementations.HttpServer
 
 
             foreach (var route in clone)
             foreach (var route in clone)
             {
             {
-                routes.Add(new RouteAttribute(NormalizeCustomRoutePath(_config.Configuration.BaseUrl, route.Path), route.Verbs)
+                routes.Add(new RouteAttribute(NormalizeCustomRoutePath(route.Path), route.Verbs)
                 {
                 {
                     Notes = route.Notes,
                     Notes = route.Notes,
                     Priority = route.Priority,
                     Priority = route.Priority,
@@ -651,36 +660,22 @@ namespace Emby.Server.Implementations.HttpServer
             return _socketListener.ProcessWebSocketRequest(context);
             return _socketListener.ProcessWebSocketRequest(context);
         }
         }
 
 
-        // this method was left for compatibility with third party clients
-        private static string NormalizeEmbyRoutePath(string path)
+        private string NormalizeEmbyRoutePath(string path)
         {
         {
-            if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
-            {
-                return "/emby" + path;
-            }
-
-            return "emby/" + path;
+            _logger.LogDebug("Normalizing /emby route");
+            return _baseUrlPrefix + "/emby" + NormalizeUrlPath(path);
         }
         }
 
 
-        // this method was left for compatibility with third party clients
-        private static string NormalizeMediaBrowserRoutePath(string path)
+        private string NormalizeMediaBrowserRoutePath(string path)
         {
         {
-            if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
-            {
-                return "/mediabrowser" + path;
-            }
-
-            return "mediabrowser/" + path;
+            _logger.LogDebug("Normalizing /mediabrowser route");
+            return _baseUrlPrefix + "/mediabrowser" + NormalizeUrlPath(path);
         }
         }
 
 
-        private static string NormalizeCustomRoutePath(string baseUrl, string path)
+        private string NormalizeCustomRoutePath(string path)
         {
         {
-            if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
-            {
-                return "/" + baseUrl + path;
-            }
-
-            return baseUrl + "/" + path;
+            _logger.LogDebug("Normalizing custom route {0}", path);
+            return _baseUrlPrefix + NormalizeUrlPath(path);
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />

+ 32 - 2
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -10,6 +10,7 @@ namespace MediaBrowser.Model.Configuration
     {
     {
         public const int DefaultHttpPort = 8096;
         public const int DefaultHttpPort = 8096;
         public const int DefaultHttpsPort = 8920;
         public const int DefaultHttpsPort = 8920;
+        private string _baseUrl;
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [enable u pn p].
         /// Gets or sets a value indicating whether [enable u pn p].
@@ -162,7 +163,36 @@ namespace MediaBrowser.Model.Configuration
         public bool SkipDeserializationForBasicTypes { get; set; }
         public bool SkipDeserializationForBasicTypes { get; set; }
 
 
         public string ServerName { get; set; }
         public string ServerName { get; set; }
-        public string BaseUrl { get; set; }
+        public string BaseUrl
+        {
+            get => _baseUrl;
+            set
+            {
+                _baseUrl = value;
+				// Normalize the start of the string
+                if (string.IsNullOrWhiteSpace(_baseUrl))
+                {
+                    // If baseUrl is empty, set an empty prefix string
+                    _baseUrl = string.Empty;
+                }
+                else if (!_baseUrl.StartsWith("/"))
+                {
+                    // If baseUrl was not configured with a leading slash, append one for consistency
+                    _baseUrl = "/" + _baseUrl;
+                }
+                else
+                {
+                    // If baseUrl was configured with a leading slash, just return it as-is
+                    _baseUrl = _baseUrl;
+                }
+                // Normalize the end of the string
+                if (_baseUrl.EndsWith("/"))
+                {
+                    // If baseUrl was configured with a trailing slash, remove it for consistency
+                    _baseUrl = _baseUrl.Remove(_baseUrl.Length - 1);
+                }
+            }
+        }
 
 
         public string UICulture { get; set; }
         public string UICulture { get; set; }
 
 
@@ -243,7 +273,7 @@ namespace MediaBrowser.Model.Configuration
             SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
             SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
             SortRemoveWords = new[] { "the", "a", "an" };
             SortRemoveWords = new[] { "the", "a", "an" };
 
 
-            BaseUrl = "jellyfin";
+            BaseUrl = string.Empty;
             UICulture = "en-US";
             UICulture = "en-US";
 
 
             MetadataOptions = new[]
             MetadataOptions = new[]