diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index fda4d7ca32..84538c9310 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -275,6 +275,8 @@ namespace Umbraco.Extensions }); builder.Services.AddSmidge(builder.Config.GetSection(Constants.Configuration.ConfigRuntimeMinification)); + // Replace the Smidge request helper, in order to discourage the use of brotli since it's super slow + builder.Services.AddUnique(); builder.Services.AddSmidgeNuglify(); builder.Services.AddSmidgeInMemory(false); // it will be enabled based on config/cachebuster diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRequestHelper.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRequestHelper.cs new file mode 100644 index 0000000000..4313e0e359 --- /dev/null +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRequestHelper.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; +using Smidge; +using Smidge.Models; + +namespace Umbraco.Cms.Web.Common.RuntimeMinification +{ + public class SmidgeRequestHelper : IRequestHelper + { + private RequestHelper _wrappedRequestHelper; + + public SmidgeRequestHelper(IWebsiteInfo siteInfo) + { + _wrappedRequestHelper = new RequestHelper(siteInfo); + } + + /// + public string Content(string path) => _wrappedRequestHelper.Content(path); + + /// + public string Content(IWebFile file) => _wrappedRequestHelper.Content(file); + + /// + public bool IsExternalRequestPath(string path) => _wrappedRequestHelper.IsExternalRequestPath(path); + + /// + /// Overrides the default order of compression from Smidge, since Brotli is super slow (~10 seconds for backoffice.js) + /// + /// + /// + public CompressionType GetClientCompression(IDictionary headers) + { + var type = CompressionType.None; + + if (headers is not IHeaderDictionary headerDictionary) + { + headerDictionary = new HeaderDictionary(headers.Count); + foreach ((var key, StringValues stringValues) in headers) + { + headerDictionary[key] = stringValues; + } + } + + var acceptEncoding = headerDictionary.GetCommaSeparatedValues(HeaderNames.AcceptEncoding); + if (acceptEncoding.Length > 0) + { + // Prefer in order: GZip, Deflate, Brotli. + for (var i = 0; i < acceptEncoding.Length; i++) + { + var encoding = acceptEncoding[i].Trim(); + + CompressionType parsed = CompressionType.Parse(encoding); + + // Not pack200-gzip. + if (parsed == CompressionType.GZip) + { + return CompressionType.GZip; + } + + if (parsed == CompressionType.Deflate) + { + type = CompressionType.Deflate; + } + + // Brotli is typically last in the accept encoding header. + if (type != CompressionType.Deflate && parsed == CompressionType.Brotli) + { + type = CompressionType.Brotli; + } + } + } + + return type; + } + } +} diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index 1f03b83bf1..031a7a782f 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -35,8 +35,8 @@ - - + + all