From 537674a0b392d4a035beae1bbd858ba1d96fd838 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aleksandr=20=C5=A0mailov?=
Date: Wed, 29 Jan 2020 09:53:08 +0200
Subject: [PATCH] Improve RTE performance when using base64 images (#7530)
---
.../Templates/HtmlImageSourceParserTests.cs | 84 +++++++++++++++++--
.../Templates/HtmlImageSourceParser.cs | 33 +++++---
2 files changed, 97 insertions(+), 20 deletions(-)
diff --git a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs b/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs
index 3bef495507..bce9bd4155 100644
--- a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs
+++ b/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs
@@ -1,7 +1,6 @@
using Umbraco.Core.Logging;
using Moq;
using NUnit.Framework;
-using Umbraco.Core.Services;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web.Templates;
using Umbraco.Web;
@@ -13,12 +12,10 @@ using System;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core;
-using Umbraco.Web.PropertyEditors;
+using System.Diagnostics;
namespace Umbraco.Tests.Templates
{
-
-
[TestFixture]
public class HtmlImageSourceParserTests
{
@@ -31,10 +28,9 @@ namespace Umbraco.Tests.Templates

";
- var logger = Mock.Of();
var umbracoContextAccessor = new TestUmbracoContextAccessor();
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
-
+
var result = imageSourceParser.FindUdisFromDataAttributes(input).ToList();
Assert.AreEqual(2, result.Count);
Assert.AreEqual(Udi.Parse("umb://media/D4B18427A1544721B09AC7692F35C264"), result[0]);
@@ -44,7 +40,6 @@ namespace Umbraco.Tests.Templates
[Test]
public void Remove_Image_Sources()
{
- var logger = Mock.Of();
var umbracoContextAccessor = new TestUmbracoContextAccessor();
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
@@ -111,10 +106,83 @@ namespace Umbraco.Tests.Templates
![]()
", result);
-
}
+ }
+ [TestCase(
+ @"![]()
",
+ ExpectedResult = @"![]()
",
+ TestName = "Empty source is not updated with no data-udi set"
+ )]
+ [TestCase(
+ @"![]()
",
+ ExpectedResult = @"![]()
",
+ TestName = "Empty source is updated with data-udi set"
+ )]
+ [TestCase(
+ @"![]()
",
+ ExpectedResult = @"![]()
",
+ TestName = "Filled source is overwritten with data-udi set"
+ )]
+ [TestCase(
+ @"![]()
",
+ ExpectedResult = @"![]()
",
+ TestName = "Attributes are persisted"
+ )]
+ [TestCase(
+ @"![]()
",
+ ExpectedResult = @"![]()
",
+ TestName = "Source is trimmed and parameters are prefixed"
+ )]
+ [TestCase(
+ @"![]()
",
+ ExpectedResult = @"![]()
",
+ TestName = "Parameters are prefixed"
+ )]
+ [TestCase(
+ @"",
+ ExpectedResult =
+ @"",
+ TestName = "Multiple img tags are handled"
+ )]
+ [Category("Ensure image sources")]
+ public string Ensure_ImageSources_Processing(string sourceHtml)
+ {
+ var fakeMediaUrl = "/media/1001/image.jpg";
+ var parser = new HtmlImageSourceParser((guid) => fakeMediaUrl);
+ var actual = parser.EnsureImageSources(sourceHtml);
+
+ return actual;
+ }
+
+ [Category("Ensure image sources")]
+ [Test]
+ public void Ensure_Large_Html_Is_Processed_Quickly()
+ {
+ int symbolCount = 25000;
+ int maxMsToRun = 200;
+
+ var longText = new string('*', symbolCount);
+ var text = $@"
";
+
+ var fakeMediaUrl = "/media/1001/image.jpg";
+ var parser = new HtmlImageSourceParser((guid) => fakeMediaUrl);
+
+ var timer = new Stopwatch();
+ timer.Start();
+ var actual = parser.EnsureImageSources(text);
+ timer.Stop();
+
+ Assert.IsTrue(timer.ElapsedMilliseconds <= maxMsToRun);
}
}
}
diff --git a/src/Umbraco.Web/Templates/HtmlImageSourceParser.cs b/src/Umbraco.Web/Templates/HtmlImageSourceParser.cs
index b0d6980ef3..dcc5318b89 100644
--- a/src/Umbraco.Web/Templates/HtmlImageSourceParser.cs
+++ b/src/Umbraco.Web/Templates/HtmlImageSourceParser.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Text.RegularExpressions;
using Umbraco.Core;
@@ -7,18 +8,29 @@ namespace Umbraco.Web.Templates
public sealed class HtmlImageSourceParser
{
- public HtmlImageSourceParser(IUmbracoContextAccessor umbracoContextAccessor)
+ public HtmlImageSourceParser(Func getMediaUrl)
{
- _umbracoContextAccessor = umbracoContextAccessor;
+ this._getMediaUrl = getMediaUrl;
}
- private static readonly Regex ResolveImgPattern = new Regex(@"(
]*src="")([^""\?]*)([^""]*""[^>]*data-udi="")([^""]*)(""[^>]*>)",
+ public HtmlImageSourceParser(IUmbracoContextAccessor umbracoContextAccessor)
+ {
+ if (umbracoContextAccessor?.UmbracoContext?.UrlProvider == null)
+ {
+ return;
+ }
+
+ _getMediaUrl = (guid) => umbracoContextAccessor.UmbracoContext.UrlProvider.GetMediaUrl(guid);
+ }
+
+ private static readonly Regex ResolveImgPattern = new Regex(@"(
]*src="")([^""\?]*)((?:\?[^""]*)?""[^>]*data-udi="")([^""]*)(""[^>]*>)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
- private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private static readonly Regex DataUdiAttributeRegex = new Regex(@"data-udi=\\?(?:""|')(?umb://[A-z0-9\-]+/[A-z0-9]+)\\?(?:""|')",
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
+ private readonly Func _getMediaUrl;
+
///
/// Parses out media UDIs from an html string based on 'data-udi' html attributes
///
@@ -45,14 +57,13 @@ namespace Umbraco.Web.Templates
/// Umbraco image tags are identified by their data-udi attributes
public string EnsureImageSources(string text)
{
- // don't attempt to proceed without a context
- if (_umbracoContextAccessor?.UmbracoContext?.UrlProvider == null)
+ // no point in doing any processing if we don't have
+ // a function to retrieve Urls
+ if (_getMediaUrl == null)
{
return text;
}
- var urlProvider = _umbracoContextAccessor.UmbracoContext.UrlProvider;
-
return ResolveImgPattern.Replace(text, match =>
{
// match groups:
@@ -66,7 +77,7 @@ namespace Umbraco.Web.Templates
{
return match.Value;
}
- var mediaUrl = urlProvider.GetMediaUrl(guidUdi.Guid);
+ var mediaUrl = _getMediaUrl(guidUdi.Guid);
if (mediaUrl == null)
{
// image does not exist - we could choose to remove the image entirely here (return empty string),
@@ -86,7 +97,5 @@ namespace Umbraco.Web.Templates
public string RemoveImageSources(string text)
// see comment in ResolveMediaFromTextString for group reference
=> ResolveImgPattern.Replace(text, "$1$3$4$5");
-
-
}
}