Compare commits

...
2 changed files with 31 additions and 8 deletions
@@ -7,7 +7,11 @@ namespace Umbraco.Cms.Core.Templates;
public sealed class HtmlImageSourceParser
{
private static readonly Regex ResolveImgPattern = new(
@"(<img[^>]*src="")([^""\?]*)((?:\?[^""]*)?""[^>]*data-udi="")([^""]*)(""[^>]*>)",
@"<img[^>]*(data-udi=""([^""]*)"")[^>]*>",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex SrcAttributeRegex = new(
@"src=""([^""\?]*)(\?[^""]*)?""",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex DataUdiAttributeRegex = new(
@@ -61,17 +65,26 @@ public sealed class HtmlImageSourceParser
return ResolveImgPattern.Replace(text, match =>
{
// match groups:
// - 1 = from the beginning of the image tag until src attribute value begins
// - 2 = the src attribute value excluding the querystring (if present)
// - 3 = anything after group 2 and before the data-udi attribute value begins
// - 4 = the data-udi attribute value
// - 5 = anything after group 4 until the image tag is closed
var udi = match.Groups[4].Value;
// - 1 = the data-udi attribute
// - 2 = the data-udi attribute value
var udi = match.Groups[2].Value;
if (udi.IsNullOrWhiteSpace() || UdiParser.TryParse<GuidUdi>(udi, out GuidUdi? guidUdi) == false)
{
return match.Value;
}
// Find the src attribute
// src match groups:
// - 1 = the src attribute value
// - 2 = the src attribute query string
Match src = SrcAttributeRegex.Match(match.Value);
if (src.Success == false)
{
// the src attribute isn't found, return the original value
return match.Value;
}
var mediaUrl = _getMediaUrl(guidUdi.Guid);
if (mediaUrl == null)
{
@@ -80,7 +93,9 @@ public sealed class HtmlImageSourceParser
return match.Value;
}
return $"{match.Groups[1].Value}{mediaUrl}{match.Groups[3].Value}{udi}{match.Groups[5].Value}";
var newImgTag = match.Value.Replace(src.Value, $"src=\"{mediaUrl}{src.Groups[2].Value}\"");
return newImgTag;
});
}
@@ -146,6 +146,10 @@ public class HtmlImageSourceParserTests
@"<div><img src=""non empty src"" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4""/></div>",
ExpectedResult = @"<div><img src=""/media/1001/image.jpg"" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4""/></div>",
TestName = "Filled source is overwritten with data-udi set")]
[TestCase(
@"<div><img alt title=""Test"" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4"" src=""non empty src"" /></div>",
ExpectedResult = @"<div><img alt title=""Test"" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4"" src=""/media/1001/image.jpg"" /></div>",
TestName = "Order of attributes does not matter")]
[TestCase(
@"<div><img src=""some src"" some-attribute data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4"" another-attribute/></div>",
ExpectedResult = @"<div><img src=""/media/1001/image.jpg"" some-attribute data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4"" another-attribute/></div>",
@@ -158,6 +162,10 @@ public class HtmlImageSourceParserTests
@"<div><img src=""?width=100&height=500"" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4""/></div>",
ExpectedResult = @"<div><img src=""/media/1001/image.jpg?width=100&height=500"" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4""/></div>",
TestName = "Parameters are prefixed")]
[TestCase(
@"<div><img data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4"" src=""?width=100&height=500"" /></div>",
ExpectedResult = @"<div><img data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4"" src=""/media/1001/image.jpg?width=100&height=500"" /></div>",
TestName = "Parameters are prefixed (order of attributes reversed)")]
[TestCase(
@"<div>
<img src="""" data-udi=""umb://media/81BB2036034F418BB61FC7160D68DCD4""/>