diff --git a/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs b/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs index 2887efe..3b8e21f 100644 --- a/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs +++ b/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs @@ -72,7 +72,10 @@ public override void Process(TagHelperContext context, TagHelperOutput output) } else { - href = AddCdn(AddPathBase(href)); + if (!Uri.TryCreate(href, UriKind.Absolute, out Uri _)) + { + href = AddCdn(AddPathBase(href)); + } output.Attributes.SetAttribute("href", href); } } diff --git a/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs b/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs index 4c09951..9f4b441 100644 --- a/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs +++ b/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs @@ -72,7 +72,10 @@ public override void Process(TagHelperContext context, TagHelperOutput output) } else { - src = AddCdn(AddPathBase(src)); + if (!Uri.TryCreate(src, UriKind.Absolute, out Uri _)) + { + src = AddCdn(AddPathBase(src)); + } output.Attributes.SetAttribute("src", src); } diff --git a/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs b/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs index 453787a..8b81b76 100644 --- a/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs +++ b/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs @@ -240,5 +240,112 @@ public void CdnUrl_RouteIsAsset_TagHelperBundlingDisabled_Success(string cdnUrl, Assert.Contains($"href=\"{options.CdnUrl}{pathBase}{cacheValue}\"", linkTags[0]); Assert.Contains($"href=\"{options.CdnUrl}{pathBase}{cacheValue2}\"", linkTags[1]); } + + [Theory2] + [InlineData("//google.com/test.css")] + [InlineData("http://google.com/test.css")] + [InlineData("https://google.com/test.css")] + public void AbsoluteUrl_RouteIsNotAsset_DoesNotAddCdnOrPath(string absoluteUrl) + { + var fileInfo = new Mock(); + fileInfo.SetupGet(fi => fi.Exists).Returns(true); + var fileProvider = new Mock(); + fileProvider.Setup(fp => fp.GetFileInfo(It.IsAny())).Returns(fileInfo.Object); + var env = new Mock(); + env.Setup(e => e.WebRootFileProvider).Returns(fileProvider.Object); + + var options = new WebOptimizerOptions + { + CdnUrl = "https://mycdn.com" + }; + var optionsFactory = new Mock>(); + optionsFactory.Setup(x => x.Create(It.IsAny())).Returns(options); + var optionsMonitor = new Mock>(optionsFactory.Object, new List>(), new Mock>().Object); + optionsMonitor.Setup(x => x.Get(It.IsAny())).Returns(options); + var linkTagHelper = new LinkTagHelper(env.Object, new Mock().Object, + new Mock().Object, optionsMonitor.Object); + var context = new Mock().SetupAllProperties(); + StringValues ae = "gzip, deflate"; + + context.SetupSequence(c => c.Request.Headers.TryGetValue("Accept-Encoding", out ae)) + .Returns(false) + .Returns(true); + context.Setup(c => c.RequestServices.GetService(typeof(IWebHostEnvironment))) + .Returns(env.Object); + var pathBase = "/myApp"; + context.SetupGet(c => c.Request.PathBase).Returns(pathBase); + + var viewContext = new ViewContext + { + HttpContext = context.Object + }; + linkTagHelper.ViewContext = viewContext; + linkTagHelper.CurrentViewContext = viewContext; + + var tagHelperContext = new Mock( + "link", + new TagHelperAttributeList(), + new Dictionary(), + "unique"); + var attributes = new TagHelperAttributeList { new TagHelperAttribute("href", absoluteUrl) }; + + var tagHelperOutput = new TagHelperOutput("link", attributes, (useCachedResult, encoder) => Task.Factory.StartNew( + () => new DefaultTagHelperContent())); + linkTagHelper.Process(tagHelperContext.Object, tagHelperOutput); + var hrefValue = tagHelperOutput.Attributes.First(x => x.Name == "href").Value; + Assert.Equal(absoluteUrl, hrefValue); + } + + [Fact2] + public void RelativeUrl_RouteIsNotAsset_DoesAddCdnAndPath() + { + var fileInfo = new Mock(); + fileInfo.SetupGet(fi => fi.Exists).Returns(true); + var fileProvider = new Mock(); + fileProvider.Setup(fp => fp.GetFileInfo(It.IsAny())).Returns(fileInfo.Object); + var env = new Mock(); + env.Setup(e => e.WebRootFileProvider).Returns(fileProvider.Object); + + var options = new WebOptimizerOptions + { + CdnUrl = "https://mycdn.com" + }; + var optionsFactory = new Mock>(); + optionsFactory.Setup(x => x.Create(It.IsAny())).Returns(options); + var optionsMonitor = new Mock>(optionsFactory.Object, new List>(), new Mock>().Object); + optionsMonitor.Setup(x => x.Get(It.IsAny())).Returns(options); + var linkTagHelper = new LinkTagHelper(env.Object, new Mock().Object, new Mock().Object, optionsMonitor.Object); + var context = new Mock().SetupAllProperties(); + StringValues ae = "gzip, deflate"; + + context.SetupSequence(c => c.Request.Headers.TryGetValue("Accept-Encoding", out ae)) + .Returns(false) + .Returns(true); + context.Setup(c => c.RequestServices.GetService(typeof(IWebHostEnvironment))) + .Returns(env.Object); + var pathBase = "/myApp"; + context.SetupGet(c => c.Request.PathBase).Returns(pathBase); + + var viewContext = new ViewContext + { + HttpContext = context.Object + }; + linkTagHelper.ViewContext = viewContext; + linkTagHelper.CurrentViewContext = viewContext; + + var tagHelperContext = new Mock( + "link", + new TagHelperAttributeList(), + new Dictionary(), + "unique"); + var relativeUrl = "/test.css"; + var attributes = new TagHelperAttributeList { new TagHelperAttribute("href", relativeUrl) }; + + var tagHelperOutput = new TagHelperOutput("link", attributes, (useCachedResult, encoder) => Task.Factory.StartNew( + () => new DefaultTagHelperContent())); + linkTagHelper.Process(tagHelperContext.Object, tagHelperOutput); + var hrefValue = tagHelperOutput.Attributes.First(x => x.Name == "href").Value; + Assert.Equal($"{options.CdnUrl}{pathBase}{relativeUrl}", hrefValue); + } } } \ No newline at end of file diff --git a/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs b/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs index 68d5467..79785de 100644 --- a/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs +++ b/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs @@ -243,5 +243,111 @@ public void CdnUrl_RouteIsAsset_TagHelperBundlingDisabled_Success(string cdnUrl, Assert.Contains($"src=\"{options.CdnUrl}{pathBase}{cacheValue}\"", scriptTags[0]); Assert.Contains($"src=\"{options.CdnUrl}{pathBase}{cacheValue2}\"", scriptTags[1]); } + + [Theory2] + [InlineData("//google.com/test.js")] + [InlineData("http://google.com/test.js")] + [InlineData("https://google.com/test.js")] + public void AbsoluteUrl_RouteIsNotAsset_DoesNotAddCdnOrPath(string absoluteUrl) + { + var fileInfo = new Mock(); + fileInfo.SetupGet(fi => fi.Exists).Returns(true); + var fileProvider = new Mock(); + fileProvider.Setup(fp => fp.GetFileInfo(It.IsAny())).Returns(fileInfo.Object); + var env = new Mock(); + env.Setup(e => e.WebRootFileProvider).Returns(fileProvider.Object); + + var options = new WebOptimizerOptions + { + CdnUrl = "https://mycdn.com" + }; + var optionsFactory = new Mock>(); + optionsFactory.Setup(x => x.Create(It.IsAny())).Returns(options); + var optionsMonitor = new Mock>(optionsFactory.Object, new List>(), new Mock>().Object); + optionsMonitor.Setup(x => x.Get(It.IsAny())).Returns(options); + var scriptTagHelper = new ScriptTagHelper(env.Object, new Mock().Object, new Mock().Object, optionsMonitor.Object); + var context = new Mock().SetupAllProperties(); + StringValues ae = "gzip, deflate"; + + context.SetupSequence(c => c.Request.Headers.TryGetValue("Accept-Encoding", out ae)) + .Returns(false) + .Returns(true); + context.Setup(c => c.RequestServices.GetService(typeof(IWebHostEnvironment))) + .Returns(env.Object); + var pathBase = "/myApp"; + context.SetupGet(c => c.Request.PathBase).Returns(pathBase); + + var viewContext = new ViewContext + { + HttpContext = context.Object + }; + scriptTagHelper.ViewContext = viewContext; + scriptTagHelper.CurrentViewContext = viewContext; + + var tagHelperContext = new Mock( + "script", + new TagHelperAttributeList(), + new Dictionary(), + "unique"); + var attributes = new TagHelperAttributeList { new TagHelperAttribute("src", absoluteUrl) }; + + var tagHelperOutput = new TagHelperOutput("scripts", attributes, (useCachedResult, encoder) => Task.Factory.StartNew( + () => new DefaultTagHelperContent())); + scriptTagHelper.Process(tagHelperContext.Object, tagHelperOutput); + var srcValue = tagHelperOutput.Attributes.First(x => x.Name == "src").Value; + Assert.Equal(absoluteUrl, srcValue); + } + + [Fact2] + public void RelativeUrl_RouteIsNotAsset_DoesAddCdnAndPath() + { + var fileInfo = new Mock(); + fileInfo.SetupGet(fi => fi.Exists).Returns(true); + var fileProvider = new Mock(); + fileProvider.Setup(fp => fp.GetFileInfo(It.IsAny())).Returns(fileInfo.Object); + var env = new Mock(); + env.Setup(e => e.WebRootFileProvider).Returns(fileProvider.Object); + + var options = new WebOptimizerOptions + { + CdnUrl = "https://mycdn.com" + }; + var optionsFactory = new Mock>(); + optionsFactory.Setup(x => x.Create(It.IsAny())).Returns(options); + var optionsMonitor = new Mock>(optionsFactory.Object, new List>(), new Mock>().Object); + optionsMonitor.Setup(x => x.Get(It.IsAny())).Returns(options); + var scriptTagHelper = new ScriptTagHelper(env.Object, new Mock().Object, new Mock().Object, optionsMonitor.Object); + var context = new Mock().SetupAllProperties(); + StringValues ae = "gzip, deflate"; + + context.SetupSequence(c => c.Request.Headers.TryGetValue("Accept-Encoding", out ae)) + .Returns(false) + .Returns(true); + context.Setup(c => c.RequestServices.GetService(typeof(IWebHostEnvironment))) + .Returns(env.Object); + var pathBase = "/myApp"; + context.SetupGet(c => c.Request.PathBase).Returns(pathBase); + + var viewContext = new ViewContext + { + HttpContext = context.Object + }; + scriptTagHelper.ViewContext = viewContext; + scriptTagHelper.CurrentViewContext = viewContext; + + var tagHelperContext = new Mock( + "script", + new TagHelperAttributeList(), + new Dictionary(), + "unique"); + var relativeUrl = "/test.js"; + var attributes = new TagHelperAttributeList { new TagHelperAttribute("src", relativeUrl) }; + + var tagHelperOutput = new TagHelperOutput("scripts", attributes, (useCachedResult, encoder) => Task.Factory.StartNew( + () => new DefaultTagHelperContent())); + scriptTagHelper.Process(tagHelperContext.Object, tagHelperOutput); + var srcValue = tagHelperOutput.Attributes.First(x => x.Name == "src").Value; + Assert.Equal($"{options.CdnUrl}{pathBase}{relativeUrl}", srcValue); + } } } \ No newline at end of file