From b7a3713946271cca97b15477339b89ad6f51960b Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 28 Sep 2022 09:43:02 -0400 Subject: [PATCH] Fix #2439 - ensure resource urls are constructed consistently on client and server --- Oqtane.Client/Modules/ModuleBase.cs | 2 +- Oqtane.Client/Themes/ThemeBase.cs | 3 ++- Oqtane.Client/UI/ThemeBuilder.razor | 2 +- Oqtane.Server/Pages/_Host.cshtml.cs | 26 ++++++++++++++------------ Oqtane.Shared/Models/Resource.cs | 11 ++++++++++- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index b0810bdb..0d0b0eec 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -75,7 +75,7 @@ namespace Oqtane.Modules var scripts = new List(); foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { - var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + (!resource.Url.StartsWith("/") ? "/" : "") + resource.Url; + var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url; scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module }); } if (scripts.Any()) diff --git a/Oqtane.Client/Themes/ThemeBase.cs b/Oqtane.Client/Themes/ThemeBase.cs index 232f1996..45584ffb 100644 --- a/Oqtane.Client/Themes/ThemeBase.cs +++ b/Oqtane.Client/Themes/ThemeBase.cs @@ -35,7 +35,8 @@ namespace Oqtane.Themes var scripts = new List(); foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { - scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module }); + var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url; + scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module }); } if (scripts.Any()) { diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index d5137a02..1766374e 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -36,7 +36,7 @@ foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) { var prefix = "app-stylesheet-" + resource.Level.ToString().ToLower(); - var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + (!resource.Url.StartsWith("/") ? "/" : "") + resource.Url; + var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url; links.Add(new { id = prefix + "-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", insertbefore = prefix }); } if (links.Any()) diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 8ae0696f..8b3044da 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -20,6 +20,7 @@ using Oqtane.Enums; using Oqtane.Security; using Oqtane.Extensions; using Oqtane.Themes; +using Oqtane.UI; namespace Oqtane.Pages { @@ -179,7 +180,7 @@ namespace Oqtane.Pages { ThemeType = page.ThemeType; } - ProcessThemeResources(ThemeType); + ProcessThemeResources(ThemeType, alias); } else // page not found { @@ -203,7 +204,7 @@ namespace Oqtane.Pages var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); foreach (Assembly assembly in assemblies) { - ProcessHostResources(assembly); + ProcessHostResources(assembly, alias); } // set culture if not specified @@ -436,7 +437,7 @@ namespace Oqtane.Pages ""; } - private void ProcessHostResources(Assembly assembly) + private void ProcessHostResources(Assembly assembly, Alias alias) { var types = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IHostResources))); foreach (var type in types) @@ -445,12 +446,12 @@ namespace Oqtane.Pages foreach (var resource in obj.Resources) { resource.Level = ResourceLevel.App; - ProcessResource(resource, 0); + ProcessResource(resource, 0, alias); } } } - private void ProcessThemeResources(string ThemeType) + private void ProcessThemeResources(string ThemeType, Alias alias) { var type = Type.GetType(ThemeType); if (type != null) @@ -462,40 +463,41 @@ namespace Oqtane.Pages foreach (var resource in obj.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) { resource.Level = ResourceLevel.Page; - ProcessResource(resource, count++); + ProcessResource(resource, count++, alias); } } } } - private void ProcessResource(Resource resource, int count) + private void ProcessResource(Resource resource, int count, Alias alias) { + var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url; switch (resource.ResourceType) { case ResourceType.Stylesheet: - if (!HeadResources.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) + if (!HeadResources.Contains(url, StringComparison.OrdinalIgnoreCase)) { string id = ""; if (resource.Level == ResourceLevel.Page) { id = "id=\"app-stylesheet-" + resource.Level.ToString().ToLower() + "-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + count.ToString("00") + "\" "; } - HeadResources += "" + Environment.NewLine; + HeadResources += "" + Environment.NewLine; } break; case ResourceType.Script: if (resource.Location == Shared.ResourceLocation.Body) { - if (!BodyResources.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) + if (!BodyResources.Contains(url, StringComparison.OrdinalIgnoreCase)) { - BodyResources += "" + Environment.NewLine; + BodyResources += "" + Environment.NewLine; } } else { if (!HeadResources.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) { - HeadResources += "" + Environment.NewLine; + HeadResources += "" + Environment.NewLine; } } break; diff --git a/Oqtane.Shared/Models/Resource.cs b/Oqtane.Shared/Models/Resource.cs index ce7087e8..fae66050 100644 --- a/Oqtane.Shared/Models/Resource.cs +++ b/Oqtane.Shared/Models/Resource.cs @@ -8,6 +8,8 @@ namespace Oqtane.Models /// public class Resource { + private string _url; + /// /// A so the Interop can properly create `script` or `link` tags /// @@ -16,7 +18,14 @@ namespace Oqtane.Models /// /// Path to the resources. /// - public string Url { get; set; } + public string Url + { + get => _url; + set + { + _url = (value.Contains("://")) ? value : (!value.StartsWith("/") ? "/" : "") + value; + } + } /// /// Integrity checks to increase the security of resources accessed. Especially common in CDN resources.