Skip to content
This repository was archived by the owner on Apr 7, 2024. It is now read-only.

Commit 13370d9

Browse files
authored
Merge pull request #69 from 7h3Rabbit/svg-dependency
Svg dependency support and # url resource support
2 parents f37da13 + bf93fe7 commit 13370d9

File tree

7 files changed

+123
-20
lines changed

7 files changed

+123
-20
lines changed

Configuration/StaticWebConfiguration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static List<AllowedResourceTypeConfigurationElement> GetFallbackAllowedRe
7070
{
7171
List<AllowedResourceTypeConfigurationElement> allowedResourceTypes = new List<AllowedResourceTypeConfigurationElement>
7272
{
73-
new AllowedResourceTypeConfigurationElement() { FileExtension = ".html", MimeType = "text/html", UseHash = false, UseResourceUrl = true, UseResourceFolder = false, DenendencyLookup = ResourceDependencyLookup.Html },
73+
new AllowedResourceTypeConfigurationElement() { FileExtension = ".html", MimeType = "text/html", UseHash = false, UseResourceUrl = true, UseResourceFolder = false, DenendencyLookup = ResourceDependencyLookup.Html | ResourceDependencyLookup.Svg },
7474
new AllowedResourceTypeConfigurationElement() { FileExtension = ".xml", MimeType = "application/xml", UseHash = false, UseResourceUrl = true, UseResourceFolder = false },
7575
new AllowedResourceTypeConfigurationElement() { FileExtension = ".json", MimeType = "application/json", UseHash = false, UseResourceUrl = true, UseResourceFolder = false },
7676
new AllowedResourceTypeConfigurationElement() { FileExtension = ".txt", MimeType = "text/plain", UseHash = false, UseResourceUrl = true, UseResourceFolder = false },
@@ -87,7 +87,7 @@ public static List<AllowedResourceTypeConfigurationElement> GetFallbackAllowedRe
8787
new AllowedResourceTypeConfigurationElement() { FileExtension = ".gif", MimeType = "image/gif", UseHash = true, UseResourceUrl = false },
8888
new AllowedResourceTypeConfigurationElement() { FileExtension = ".ico", MimeType = "image/vnd.microsoft.icon", UseHash = true, UseResourceUrl = false },
8989
new AllowedResourceTypeConfigurationElement() { FileExtension = ".webp", MimeType = "image/webp", UseHash = true, UseResourceUrl = false },
90-
new AllowedResourceTypeConfigurationElement() { FileExtension = ".svg", MimeType = "image/svg+xml", UseHash = true, UseResourceUrl = false },
90+
new AllowedResourceTypeConfigurationElement() { FileExtension = ".svg", MimeType = "image/svg+xml", UseHash = true, UseResourceUrl = false, DenendencyLookup = ResourceDependencyLookup.Svg },
9191
new AllowedResourceTypeConfigurationElement() { FileExtension = ".pdf", MimeType = "application/pdf", UseHash = true, UseResourceUrl = false },
9292
new AllowedResourceTypeConfigurationElement() { FileExtension = ".woff", MimeType = "font/woff", UseHash = true, UseResourceUrl = false },
9393
new AllowedResourceTypeConfigurationElement() { FileExtension = ".woff2", MimeType = "font/woff2", UseHash = true, UseResourceUrl = false }

Models/ResourceDependencyLookup.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ namespace StaticWebEpiserverPlugin.Models
66
public enum ResourceDependencyLookup
77
{
88
None = 0,
9-
Html,
10-
Css
9+
Html = 1,
10+
Css = 2,
11+
Svg = 4
1112
}
1213
}

Services/CssDependencyService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace StaticWebEpiserverPlugin.Services
88
{
99
public class CssDependencyService : ITextResourceDependencyService
1010
{
11-
static readonly Regex REGEX_FIND_URL_REFERENCE = new Regex("url\\([\"|']{0,1}(?<resource>[^[\\)\"|']+)", RegexOptions.Compiled);
11+
static readonly Regex REGEX_FIND_URL_REFERENCE = new Regex("url\\([\"']{0,1}(?<resource>[^[\\)\"'#]+)", RegexOptions.Compiled);
1212

1313
public string EnsureDependencies(string referencingUrl, string content, IStaticWebService staticWebService, SiteConfigurationElement configuration, bool? useTemporaryAttribute, bool ignoreHtmlDependencies, Dictionary<string, string> currentPageResourcePairs = null, ConcurrentDictionary<string, string> replaceResourcePairs = null, int callDepth = 0)
1414
{

Services/HtmlDependencyService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ namespace StaticWebEpiserverPlugin.Services
99
{
1010
public class HtmlDependencyService : ITextResourceDependencyService
1111
{
12-
static readonly Regex REGEX_FIND_SOURCE_REFERENCE = new Regex("<(source).*(srcset)=[\"|'](?<imageCandidates>[^\"|']+)[\"|']", RegexOptions.Compiled);
12+
static readonly Regex REGEX_FIND_SOURCE_REFERENCE = new Regex("<(source).*(srcset)=[\"'](?<imageCandidates>[^\"']+)[\"'#]", RegexOptions.Compiled);
1313
static readonly Regex REGEX_FIND_SOURCE_RESOUCE_REFERENCE = new Regex("(?<resource>[^, ]+)( [0-9.]+[w|x][,]{0,1})*", RegexOptions.Compiled);
14-
static readonly Regex REGEX_FIND_SCRIPT_OR_LINK_OR_IMG_OR_A_URL_REFERENCE = new Regex("<(script|link|img|a).*(href|src)=[\"|'](?<resource>[^\"|']+)", RegexOptions.Compiled);
14+
static readonly Regex REGEX_FIND_SCRIPT_OR_LINK_OR_IMG_OR_A_URL_REFERENCE = new Regex("<(script|link|img|a).*(href|src)=[\"'](?<resource>[^\"'#]+)", RegexOptions.Compiled);
1515

1616
public string EnsureDependencies(string referencingUrl, string content, IStaticWebService staticWebService, SiteConfigurationElement configuration, bool? useTemporaryAttribute, bool ignoreHtmlDependencies, Dictionary<string, string> currentPageResourcePairs = null, ConcurrentDictionary<string, string> replaceResourcePairs = null, int callDepth = 0)
1717
{

Services/StaticWebService.cs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class StaticWebService : IStaticWebService
3939
public event EventHandler<StaticWebIOEvent> AfterIODelete;
4040

4141
public ITextResourceDependencyService _htmlDependencyService = new HtmlDependencyService();
42+
public ITextResourceDependencyService _svgDependencyService = new SvgDependencyService();
4243
public ITextResourceDependencyService _cssDependencyService = new CssDependencyService();
4344

4445
public StaticWebService()
@@ -598,18 +599,24 @@ protected static string TryToFixLinkUrls(string html)
598599

599600
protected string EnsureDependencies(string referencingUrl, string content, SiteConfigurationElement siteConfiguration, bool? useTemporaryAttribute, bool ignoreHtmlDependencies, AllowedResourceTypeConfigurationElement typeConfiguration, Dictionary<string, string> currentPageResourcePairs = null, ConcurrentDictionary<string, string> replaceResourcePairs = null, int callDepth = 0)
600601
{
601-
switch (typeConfiguration.DenendencyLookup)
602-
{
603-
case ResourceDependencyLookup.Html:
604-
if (ignoreHtmlDependencies && callDepth != 0)
605-
return content;
606-
return _htmlDependencyService.EnsureDependencies(referencingUrl, content, this, siteConfiguration, useTemporaryAttribute, ignoreHtmlDependencies, currentPageResourcePairs, replaceResourcePairs, ++callDepth);
607-
case ResourceDependencyLookup.Css:
608-
return _cssDependencyService.EnsureDependencies(referencingUrl, content, this, siteConfiguration, useTemporaryAttribute, ignoreHtmlDependencies, currentPageResourcePairs, replaceResourcePairs, ++callDepth);
609-
case ResourceDependencyLookup.None:
610-
default:
611-
return content;
602+
string workingContent = content;
603+
if (typeConfiguration.DenendencyLookup.HasFlag(ResourceDependencyLookup.Html))
604+
{
605+
if (!ignoreHtmlDependencies || callDepth == 0)
606+
{
607+
workingContent = _htmlDependencyService.EnsureDependencies(referencingUrl, workingContent, this, siteConfiguration, useTemporaryAttribute, ignoreHtmlDependencies, currentPageResourcePairs, replaceResourcePairs, ++callDepth);
608+
}
609+
}
610+
if (typeConfiguration.DenendencyLookup.HasFlag(ResourceDependencyLookup.Svg))
611+
{
612+
workingContent = _svgDependencyService.EnsureDependencies(referencingUrl, workingContent, this, siteConfiguration, useTemporaryAttribute, ignoreHtmlDependencies, currentPageResourcePairs, replaceResourcePairs, ++callDepth);
613+
}
614+
if (typeConfiguration.DenendencyLookup.HasFlag(ResourceDependencyLookup.Css))
615+
{
616+
workingContent = _cssDependencyService.EnsureDependencies(referencingUrl, workingContent, this, siteConfiguration, useTemporaryAttribute, ignoreHtmlDependencies, currentPageResourcePairs, replaceResourcePairs, ++callDepth);
612617
}
618+
619+
return workingContent;
613620
}
614621

615622
public string EnsureResource(SiteConfigurationElement siteConfiguration, string resourceUrl, Dictionary<string, string> currentPageResourcePairs, ConcurrentDictionary<string, string> replaceResourcePairs, bool? useTemporaryAttribute, bool ignoreHtmlDependencies, int callDepth = 0)
@@ -641,7 +648,7 @@ public string EnsureResource(SiteConfigurationElement siteConfiguration, string
641648
return null;
642649
}
643650

644-
if (ignoreHtmlDependencies && callDepth != 0 && resourceInfo.TypeConfiguration.DenendencyLookup == ResourceDependencyLookup.Html)
651+
if (ignoreHtmlDependencies && callDepth != 0 && resourceInfo.TypeConfiguration.DenendencyLookup.HasFlag(ResourceDependencyLookup.Html))
645652
{
646653
return null;
647654
}
@@ -658,7 +665,7 @@ public string EnsureResource(SiteConfigurationElement siteConfiguration, string
658665
currentPageResourcePairs.Add(resourceUrl, newResourceUrl);
659666
}
660667

661-
if (resourceInfo.TypeConfiguration.DenendencyLookup != ResourceDependencyLookup.None)
668+
if (!resourceInfo.TypeConfiguration.DenendencyLookup.HasFlag(ResourceDependencyLookup.None))
662669
{
663670
var content = Encoding.UTF8.GetString(resourceInfo.Data);
664671
content = EnsureDependencies(resourceUrl, content, siteConfiguration, useTemporaryAttribute, ignoreHtmlDependencies, resourceInfo.TypeConfiguration, currentPageResourcePairs, replaceResourcePairs, callDepth);

Services/SvgDependencyService.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using StaticWebEpiserverPlugin.Configuration;
2+
using StaticWebEpiserverPlugin.Interfaces;
3+
using System.Collections.Concurrent;
4+
using System.Collections.Generic;
5+
using System.Text;
6+
using System.Text.RegularExpressions;
7+
8+
namespace StaticWebEpiserverPlugin.Services
9+
{
10+
public class SvgDependencyService : ITextResourceDependencyService
11+
{
12+
static readonly Regex REGEX_FIND_USE_URL_REFERENCE = new Regex("<(use).*(xlink:href)=[\"'](?<resource>[^\"#']+)", RegexOptions.Compiled);
13+
14+
public string EnsureDependencies(string referencingUrl, string content, IStaticWebService staticWebService, SiteConfigurationElement configuration, bool? useTemporaryAttribute, bool ignoreHtmlDependencies, Dictionary<string, string> currentPageResourcePairs = null, ConcurrentDictionary<string, string> replaceResourcePairs = null, int callDepth = 0)
15+
{
16+
if (configuration == null || !configuration.Enabled)
17+
{
18+
return content;
19+
}
20+
21+
if (currentPageResourcePairs == null)
22+
{
23+
currentPageResourcePairs = new Dictionary<string, string>();
24+
}
25+
26+
if (replaceResourcePairs == null)
27+
{
28+
replaceResourcePairs = new ConcurrentDictionary<string, string>();
29+
}
30+
31+
// make sure we have all resources from script, link and img tags for current page
32+
// <(use).*(xlink:href)="(?<resource>[^"]+)
33+
EnsureUseTagSupport(staticWebService, configuration, ref content, ref currentPageResourcePairs, ref replaceResourcePairs, useTemporaryAttribute, ignoreHtmlDependencies, callDepth);
34+
35+
var sbHtml = new StringBuilder(content);
36+
foreach (KeyValuePair<string, string> pair in replaceResourcePairs)
37+
{
38+
// We have a value if we want to replace orginal url with a new one
39+
if (pair.Value != null)
40+
{
41+
sbHtml = sbHtml.Replace(pair.Key, pair.Value);
42+
}
43+
}
44+
45+
return sbHtml.ToString();
46+
}
47+
48+
protected void EnsureUseTagSupport(IStaticWebService staticWebService, SiteConfigurationElement configuration, ref string html, ref Dictionary<string, string> currentPageResourcePairs, ref ConcurrentDictionary<string, string> replaceResourcePairs, bool? useTemporaryAttribute, bool ignoreHtmlDependencies, int callDepth = 0)
49+
{
50+
if (configuration == null || !configuration.Enabled)
51+
{
52+
return;
53+
}
54+
55+
var matches = REGEX_FIND_USE_URL_REFERENCE.Matches(html);
56+
foreach (Match match in matches)
57+
{
58+
var group = match.Groups["resource"];
59+
if (group.Success)
60+
{
61+
var resourceUrl = group.Value;
62+
if (replaceResourcePairs.ContainsKey(resourceUrl))
63+
{
64+
/**
65+
* If we have already downloaded resource, we don't need to download it again.
66+
* Not only usefull for pages repeating same resource but also in our Scheduled job where we try to generate all pages.
67+
**/
68+
69+
if (!currentPageResourcePairs.ContainsKey(resourceUrl))
70+
{
71+
// current page has no info regarding this resource, add it
72+
currentPageResourcePairs.Add(resourceUrl, replaceResourcePairs[resourceUrl]);
73+
}
74+
continue;
75+
}
76+
77+
var newResourceUrl = staticWebService.EnsureResource(configuration, resourceUrl, currentPageResourcePairs, replaceResourcePairs, useTemporaryAttribute, ignoreHtmlDependencies, callDepth);
78+
if (!replaceResourcePairs.ContainsKey(resourceUrl))
79+
{
80+
replaceResourcePairs.TryAdd(resourceUrl, newResourceUrl);
81+
}
82+
if (!currentPageResourcePairs.ContainsKey(resourceUrl))
83+
{
84+
currentPageResourcePairs.Add(resourceUrl, newResourceUrl);
85+
}
86+
}
87+
}
88+
}
89+
90+
}
91+
}

StaticWebEpiserverPlugin.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
<DefineConstants>TRACE</DefineConstants>
4747
<ErrorReport>prompt</ErrorReport>
4848
<WarningLevel>4</WarningLevel>
49+
<CodeAnalysisRuleSet>
50+
</CodeAnalysisRuleSet>
51+
<RunCodeAnalysis>true</RunCodeAnalysis>
4952
</PropertyGroup>
5053
<ItemGroup>
5154
<Reference Include="EPiServer, Version=11.20.9.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7, processorArchitecture=MSIL">
@@ -151,6 +154,7 @@
151154
<Compile Include="Routing\StaticWebRouting.cs" />
152155
<Compile Include="ScheduledJobs\StaticWebScheduledJob.cs" />
153156
<Compile Include="Services\CssDependencyService.cs" />
157+
<Compile Include="Services\SvgDependencyService.cs" />
154158
<Compile Include="Services\HtmlDependencyService.cs" />
155159
<Compile Include="Services\IStaticWebService.cs" />
156160
<Compile Include="Services\StaticWebService.cs" />

0 commit comments

Comments
 (0)