From 8687156dbc210e252798bc6075a0edd09e830263 Mon Sep 17 00:00:00 2001 From: Dean Marcussen Date: Thu, 17 Dec 2020 13:49:42 +0000 Subject: [PATCH 1/6] correctly generate cdn base url for local scripts --- .../Filters/ResourceUrlFilter.cs | 4 +- .../ResourceDefinition.cs | 6 +- .../Razor/ResourceCdnHelperExtensions.cs | 4 +- .../ResourceDefinitionTests.cs | 154 +++++++++++++----- 4 files changed, 119 insertions(+), 49 deletions(-) diff --git a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs index d913462d72c..ddf0f0593c0 100644 --- a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs +++ b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs @@ -35,10 +35,10 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu resourcePath = _httpContextAccessor.HttpContext.Request.PathBase.Add(resourcePath.Substring(1)).Value; } - // Don't prefix cdn if the path is absolute, or is in debug mode. + // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (!_options.DebugMode && !String.IsNullOrEmpty(_options.CdnBaseUrl) - && !Uri.TryCreate(resourcePath, UriKind.Absolute, out var uri)) + && !resourcePath.Contains("//", StringComparison.OrdinalIgnoreCase)) { resourcePath = _options.CdnBaseUrl + resourcePath; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs index a2c5f01712b..47d7148fa09 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs @@ -228,10 +228,10 @@ public TagBuilder GetTagBuilder(RequireSettings settings, url = fileVersionProvider.AddFileVersionToPath(applicationPath, url); } - // Don't prefix cdn if the path is absolute, or is in debug mode. - if (!settings.DebugMode + // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. + if (url != null && !settings.DebugMode && !String.IsNullOrEmpty(settings.CdnBaseUrl) - && !Uri.TryCreate(url, UriKind.Absolute, out var uri)) + && !url.Contains("//", StringComparison.OrdinalIgnoreCase)) { url = settings.CdnBaseUrl + url; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs index 952422ea98e..9d6d72ef33d 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs @@ -27,10 +27,10 @@ public static string ResourceUrl(this IOrchardHelper orchardHelper, string resou resourcePath = fileVersionProvider.AddFileVersionToPath(orchardHelper.HttpContext.Request.PathBase, resourcePath); } - // Don't prefix cdn if the path is absolute, or is in debug mode. + // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (!options.DebugMode && !String.IsNullOrEmpty(options.CdnBaseUrl) - && !Uri.TryCreate(resourcePath, UriKind.Absolute, out var uri)) + && !resourcePath.Contains("//", StringComparison.OrdinalIgnoreCase)) { resourcePath = options.CdnBaseUrl + resourcePath; } diff --git a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs index d24ec40c4b7..4c2dc488354 100644 --- a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs +++ b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Html; @@ -10,7 +11,6 @@ namespace OrchardCore.Tests.ResourceManagement { public class ResourceDefinitionTests { - private const string basePath = "http://host"; private readonly ResourceManifest _resourceManifest; public ResourceDefinitionTests() @@ -18,116 +18,156 @@ public ResourceDefinitionTests() _resourceManifest = new ResourceManifest(); } - [Fact] - public void GetScriptResourceWithUrl() + // The application path is empty if it is the host site + // or contains the base path of a tenant. + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetScriptResourceWithUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") .SetUrl("~/foo.js", "~/foo.debug.js") .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("script", tagBuilder.TagName); - Assert.Equal($"{basePath}/foo.js", tagBuilder.Attributes["src"]); + Assert.Equal($"{applicationPath}/foo.js", tagBuilder.Attributes["src"]); } - [Fact] - public void GetScriptResourceWithDebugUrl() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetScriptResourceWithDebugUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") .SetUrl("~/foo.js", "~/foo.debug.js") .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("script", tagBuilder.TagName); - Assert.Equal($"{basePath}/foo.debug.js", tagBuilder.Attributes["src"]); + Assert.Equal($"{applicationPath}/foo.debug.js", tagBuilder.Attributes["src"]); } - [Fact] - public void GetScriptResourceWithCdnUrl() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetScriptResourceWithCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") .SetUrl("~/foo.js", "~/foo.debug.js") .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("script", tagBuilder.TagName); Assert.Equal("https://cdn.tld/foo.js", tagBuilder.Attributes["src"]); } - [Fact] - public void GetScriptResourceWithDebugCdnUrl() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetScriptResourceWithDebugCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") .SetUrl("~/foo.js", "~/foo.debug.js") .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); - var requireSettings = new RequireSettings { DebugMode = true, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var requireSettings = new RequireSettings { DebugMode = true, CdnMode = true, CdnBaseUrl = "https://hostcdn.net" }; + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("script", tagBuilder.TagName); Assert.Equal("https://cdn.tld/foo.debug.js", tagBuilder.Attributes["src"]); } + + [Theory] + [InlineData("", "~/foo.js", "https://hostcdn.net/foo.js")] + [InlineData("/tenant", "~/foo.js", "https://hostcdn.net/tenant/foo.js")] + [InlineData("", "//external.com/foo.js", "//external.com/foo.js")] + [InlineData("/tenant", "//external.com/foo.js", "//external.com/foo.js")] + [InlineData("", "http://external.com/foo.js", "http://external.com/foo.js")] + [InlineData("/tenant", "http://external.com/foo.js", "http://external.com/foo.js")] + [InlineData("", "https://external.com/foo.js", "https://external.com/foo.js")] + [InlineData("/tenant", "https://external.com/foo.js", "https://external.com/foo.js")] + public void GetLocalScriptResourceWithCdnBaseUrl(string applicationPath, string url, string expected) + { + var resourceDefinition = _resourceManifest.DefineScript("foo") + .SetUrl(url, url); + + var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true, CdnBaseUrl = "https://hostcdn.net" }; + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + + Assert.Equal("script", tagBuilder.TagName); + Assert.Equal(expected, tagBuilder.Attributes["src"]); + } - [Fact] - public void GetScriptResourceWithInlineContent() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetScriptResourceWithInlineContent(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") .SetInnerContent("console.log('foo');"); - var requireSettings = new RequireSettings(); - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var requireSettings = new RequireSettings() + .UseCdnBaseUrl("https://hostcdn.net"); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("script", tagBuilder.TagName); Assert.Equal("console.log('foo');", ReadIHtmlContent(tagBuilder.InnerHtml)); - } + } - [Fact] - public void GetStyleResourceWithUrl() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetStyleResourceWithUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") .SetUrl("~/foo.css", "~/foo.debug.css") .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); Assert.Equal("stylesheet", tagBuilder.Attributes["rel"]); - Assert.Equal($"{basePath}/foo.css", tagBuilder.Attributes["href"]); + Assert.Equal($"{applicationPath}/foo.css", tagBuilder.Attributes["href"]); } - [Fact] - public void GetStyleResourceWithDebugUrl() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetStyleResourceWithDebugUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") .SetUrl("~/foo.css", "~/foo.debug.css") .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); Assert.Equal("stylesheet", tagBuilder.Attributes["rel"]); - Assert.Equal($"{basePath}/foo.debug.css", tagBuilder.Attributes["href"]); + Assert.Equal($"{applicationPath}/foo.debug.css", tagBuilder.Attributes["href"]); } - [Fact] - public void GetStyleResourceWithCdnUrl() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetStyleResourceWithCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") .SetUrl("~/foo.css", "~/foo.debug.css") .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -135,15 +175,40 @@ public void GetStyleResourceWithCdnUrl() Assert.Equal("https://cdn.tld/foo.css", tagBuilder.Attributes["href"]); } - [Fact] - public void GetStyleResourceWithDebugCdnUrl() + [Theory] + [InlineData("", "~/foo.css", "https://hostcdn.net/foo.css")] + [InlineData("/tenant", "~/foo.css", "https://hostcdn.net/tenant/foo.css")] + [InlineData("", "//external.com/foo.css", "//external.com/foo.css")] + [InlineData("/tenant", "//external.com/foo.css", "//external.com/foo.css")] + [InlineData("", "http://external.com/foo.css", "http://external.com/foo.css")] + [InlineData("/tenant", "http://external.com/foo.css", "http://external.com/foo.css")] + [InlineData("", "https://external.com/foo.css", "https://external.com/foo.css")] + [InlineData("/tenant", "https://external.com/foo.css", "https://external.com/foo.css")] + public void GetLocalStyleResourceWithCdnBaseUrl(string applicationPath, string url, string expected) + { + var resourceDefinition = _resourceManifest.DefineStyle("foo") + .SetUrl(url, url); + + var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true, CdnBaseUrl = "https://hostcdn.net" }; + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + + Assert.Equal("link", tagBuilder.TagName); + Assert.Equal("text/css", tagBuilder.Attributes["type"]); + Assert.Equal("stylesheet", tagBuilder.Attributes["rel"]); + Assert.Equal(expected, tagBuilder.Attributes["href"]); + } + + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetStyleResourceWithDebugCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") .SetUrl("~/foo.css", "~/foo.debug.css") .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -151,8 +216,10 @@ public void GetStyleResourceWithDebugCdnUrl() Assert.Equal("https://cdn.tld/foo.debug.css", tagBuilder.Attributes["href"]); } - [Fact] - public void GetStyleResourceWithAttributes() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetStyleResourceWithAttributes(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") .SetUrl("~/foo.css", "~/foo.debug.css") @@ -160,7 +227,7 @@ public void GetStyleResourceWithAttributes() .SetAttribute("media", "all"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -169,14 +236,17 @@ public void GetStyleResourceWithAttributes() Assert.Equal("all", tagBuilder.Attributes["media"]); } - [Fact] - public void GetStyleResourceWithInlineContent() + [Theory] + [InlineData("")] + [InlineData("/tenant")] + public void GetStyleResourceWithInlineContent(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") .SetInnerContent("body { background-color: white; }"); - var requireSettings = new RequireSettings(); - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, basePath, StubFileVersionProvider.Instance); + var requireSettings = new RequireSettings() + .UseCdnBaseUrl("https://cdn.net"); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); Assert.Equal("style", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); From 426a0e5070fa7a1e701f205a25bd295c3673620b Mon Sep 17 00:00:00 2001 From: Dean Marcussen Date: Thu, 17 Dec 2020 16:12:50 +0000 Subject: [PATCH 2/6] Use StartsWith --- .../Filters/ResourceUrlFilter.cs | 4 +++- .../ResourceDefinition.cs | 4 +++- .../Razor/ResourceCdnHelperExtensions.cs | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs index ddf0f0593c0..dc4dfd5ea0a 100644 --- a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs +++ b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs @@ -38,7 +38,9 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (!_options.DebugMode && !String.IsNullOrEmpty(_options.CdnBaseUrl) - && !resourcePath.Contains("//", StringComparison.OrdinalIgnoreCase)) + && !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) + && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) + && !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { resourcePath = _options.CdnBaseUrl + resourcePath; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs index 47d7148fa09..ed1e8a3a326 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs @@ -231,7 +231,9 @@ public TagBuilder GetTagBuilder(RequireSettings settings, // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (url != null && !settings.DebugMode && !String.IsNullOrEmpty(settings.CdnBaseUrl) - && !url.Contains("//", StringComparison.OrdinalIgnoreCase)) + && !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) + && !url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) + && !url.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { url = settings.CdnBaseUrl + url; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs index 9d6d72ef33d..646d63551b1 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs @@ -30,7 +30,9 @@ public static string ResourceUrl(this IOrchardHelper orchardHelper, string resou // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (!options.DebugMode && !String.IsNullOrEmpty(options.CdnBaseUrl) - && !resourcePath.Contains("//", StringComparison.OrdinalIgnoreCase)) + && !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) + && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) + && !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { resourcePath = options.CdnBaseUrl + resourcePath; } From 3987ed5095c5fac4948413c0728ebf0e32baf8a0 Mon Sep 17 00:00:00 2001 From: Dean Marcussen Date: Fri, 18 Dec 2020 15:13:07 +0000 Subject: [PATCH 3/6] test base path --- .../Filters/ResourceUrlFilter.cs | 1 + .../ResourceDefinition.cs | 5 +++-- .../Razor/ResourceCdnHelperExtensions.cs | 1 + .../ResourceDefinitionTests.cs | 22 ++++++++++++++++--- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs index dc4dfd5ea0a..edc4e452e4c 100644 --- a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs +++ b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs @@ -38,6 +38,7 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (!_options.DebugMode && !String.IsNullOrEmpty(_options.CdnBaseUrl) + // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. && !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) diff --git a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs index ed1e8a3a326..f81023e94a8 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs @@ -60,9 +60,9 @@ public ResourceDefinition SetAttribute(string name, string value) return this; } - public ResourceDefinition SetBasePath(string virtualPath) + public ResourceDefinition SetBasePath(string basePath) { - _basePath = virtualPath; + _basePath = basePath; return this; } @@ -231,6 +231,7 @@ public TagBuilder GetTagBuilder(RequireSettings settings, // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (url != null && !settings.DebugMode && !String.IsNullOrEmpty(settings.CdnBaseUrl) + // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. && !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && !url.StartsWith("//", StringComparison.OrdinalIgnoreCase)) diff --git a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs index 646d63551b1..af4788b4987 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs @@ -30,6 +30,7 @@ public static string ResourceUrl(this IOrchardHelper orchardHelper, string resou // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. if (!options.DebugMode && !String.IsNullOrEmpty(options.CdnBaseUrl) + // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. && !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) diff --git a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs index 4c2dc488354..0451b28805f 100644 --- a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs +++ b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs @@ -36,6 +36,22 @@ public void GetScriptResourceWithUrl(string applicationPath) Assert.Equal($"{applicationPath}/foo.js", tagBuilder.Attributes["src"]); } + [Theory] + [InlineData("/base")] + [InlineData("https://base.com")] + public void GetScriptResourceWithBasePath(string basePath) + { + var resourceDefinition = _resourceManifest.DefineScript("foo") + .SetUrl("~/foo.js", "~/foo.debug.js") + .SetBasePath(basePath); + + var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, String.Empty, StubFileVersionProvider.Instance); + + Assert.Equal("script", tagBuilder.TagName); + Assert.Equal($"{basePath}/foo.js", tagBuilder.Attributes["src"]); + } + [Theory] [InlineData("")] [InlineData("/tenant")] @@ -83,7 +99,7 @@ public void GetScriptResourceWithDebugCdnUrl(string applicationPath) Assert.Equal("script", tagBuilder.TagName); Assert.Equal("https://cdn.tld/foo.debug.js", tagBuilder.Attributes["src"]); } - + [Theory] [InlineData("", "~/foo.js", "https://hostcdn.net/foo.js")] [InlineData("/tenant", "~/foo.js", "https://hostcdn.net/tenant/foo.js")] @@ -119,7 +135,7 @@ public void GetScriptResourceWithInlineContent(string applicationPath) Assert.Equal("script", tagBuilder.TagName); Assert.Equal("console.log('foo');", ReadIHtmlContent(tagBuilder.InnerHtml)); - } + } [Theory] [InlineData("")] @@ -196,7 +212,7 @@ public void GetLocalStyleResourceWithCdnBaseUrl(string applicationPath, string u Assert.Equal("text/css", tagBuilder.Attributes["type"]); Assert.Equal("stylesheet", tagBuilder.Attributes["rel"]); Assert.Equal(expected, tagBuilder.Attributes["href"]); - } + } [Theory] [InlineData("")] From c0d06ea23f9cdad4df6ca05514617b59030a598f Mon Sep 17 00:00:00 2001 From: Dean Marcussen Date: Sat, 19 Dec 2020 11:22:22 +0000 Subject: [PATCH 4/6] tweak tests --- .../ResourceManagement/ResourceDefinitionTests.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs index 0451b28805f..2c37f15b5f8 100644 --- a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs +++ b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs @@ -23,6 +23,7 @@ public ResourceDefinitionTests() [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetScriptResourceWithUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") @@ -38,7 +39,6 @@ public void GetScriptResourceWithUrl(string applicationPath) [Theory] [InlineData("/base")] - [InlineData("https://base.com")] public void GetScriptResourceWithBasePath(string basePath) { var resourceDefinition = _resourceManifest.DefineScript("foo") @@ -55,6 +55,7 @@ public void GetScriptResourceWithBasePath(string basePath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetScriptResourceWithDebugUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") @@ -71,6 +72,7 @@ public void GetScriptResourceWithDebugUrl(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetScriptResourceWithCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") @@ -87,6 +89,7 @@ public void GetScriptResourceWithCdnUrl(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetScriptResourceWithDebugCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") @@ -124,6 +127,7 @@ public void GetLocalScriptResourceWithCdnBaseUrl(string applicationPath, string [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetScriptResourceWithInlineContent(string applicationPath) { var resourceDefinition = _resourceManifest.DefineScript("foo") @@ -140,6 +144,7 @@ public void GetScriptResourceWithInlineContent(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetStyleResourceWithUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") @@ -158,6 +163,7 @@ public void GetStyleResourceWithUrl(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetStyleResourceWithDebugUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") @@ -176,6 +182,7 @@ public void GetStyleResourceWithDebugUrl(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetStyleResourceWithCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") @@ -217,6 +224,7 @@ public void GetLocalStyleResourceWithCdnBaseUrl(string applicationPath, string u [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetStyleResourceWithDebugCdnUrl(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") @@ -235,6 +243,7 @@ public void GetStyleResourceWithDebugCdnUrl(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetStyleResourceWithAttributes(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") @@ -255,6 +264,7 @@ public void GetStyleResourceWithAttributes(string applicationPath) [Theory] [InlineData("")] [InlineData("/tenant")] + [InlineData("/virtualpath/tenant")] public void GetStyleResourceWithInlineContent(string applicationPath) { var resourceDefinition = _resourceManifest.DefineStyle("foo") From 24c967300dcf143202244ffebbcda2a2a0e17814 Mon Sep 17 00:00:00 2001 From: Dean Marcussen Date: Mon, 21 Dec 2020 09:59:45 +0000 Subject: [PATCH 5/6] Formatting --- .../Filters/ResourceUrlFilter.cs | 9 ++++----- .../ResourceDefinition.cs | 9 ++++----- .../Razor/ResourceCdnHelperExtensions.cs | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs index edc4e452e4c..725e2db3aed 100644 --- a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs +++ b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs @@ -36,12 +36,11 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu } // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. - if (!_options.DebugMode - && !String.IsNullOrEmpty(_options.CdnBaseUrl) + if (!_options.DebugMode && !String.IsNullOrEmpty(_options.CdnBaseUrl) && // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. - && !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) - && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) - && !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && + !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && + !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { resourcePath = _options.CdnBaseUrl + resourcePath; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs index f81023e94a8..ad348230454 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs @@ -229,12 +229,11 @@ public TagBuilder GetTagBuilder(RequireSettings settings, } // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. - if (url != null && !settings.DebugMode - && !String.IsNullOrEmpty(settings.CdnBaseUrl) + if (url != null && !settings.DebugMode && !String.IsNullOrEmpty(settings.CdnBaseUrl) && // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. - && !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) - && !url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) - && !url.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && + !url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && + !url.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { url = settings.CdnBaseUrl + url; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs index af4788b4987..6ecd44e9e51 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs @@ -28,12 +28,11 @@ public static string ResourceUrl(this IOrchardHelper orchardHelper, string resou } // Don't prefix cdn if the path includes a protocol, i.e. is an external url, or is in debug mode. - if (!options.DebugMode - && !String.IsNullOrEmpty(options.CdnBaseUrl) + if (!options.DebugMode && !String.IsNullOrEmpty(options.CdnBaseUrl) && // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. - && !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) - && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) - && !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && + !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && + !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) { resourcePath = options.CdnBaseUrl + resourcePath; } From 24f982d1d33061574fbcc0029b6c9e3e78d75f02 Mon Sep 17 00:00:00 2001 From: Dean Marcussen Date: Wed, 23 Dec 2020 12:38:01 +0000 Subject: [PATCH 6/6] add file:// --- .../Filters/ResourceUrlFilter.cs | 3 ++- .../ResourceDefinition.cs | 3 ++- .../Razor/ResourceCdnHelperExtensions.cs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs index 725e2db3aed..a1982786d37 100644 --- a/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs +++ b/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Filters/ResourceUrlFilter.cs @@ -40,7 +40,8 @@ public ValueTask ProcessAsync(FluidValue input, FilterArguments argu // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && - !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase) && + !resourcePath.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { resourcePath = _options.CdnBaseUrl + resourcePath; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs index ad348230454..58fdf60f466 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement.Abstractions/ResourceDefinition.cs @@ -233,7 +233,8 @@ public TagBuilder GetTagBuilder(RequireSettings settings, // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && - !url.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + !url.StartsWith("//", StringComparison.OrdinalIgnoreCase) && + !url.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { url = settings.CdnBaseUrl + url; } diff --git a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs index 6ecd44e9e51..6888c94ecff 100644 --- a/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs +++ b/src/OrchardCore/OrchardCore.ResourceManagement/Razor/ResourceCdnHelperExtensions.cs @@ -32,7 +32,8 @@ public static string ResourceUrl(this IOrchardHelper orchardHelper, string resou // Don't evaluate with Uri.TryCreate as it produces incorrect results on Linux. !resourcePath.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !resourcePath.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && - !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase)) + !resourcePath.StartsWith("//", StringComparison.OrdinalIgnoreCase) && + !resourcePath.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { resourcePath = options.CdnBaseUrl + resourcePath; }