Skip to content

Commit

Permalink
Update ImageSharp.Web v2 (OrchardCMS#11585)
Browse files Browse the repository at this point in the history
  • Loading branch information
deanmarcussen authored Apr 27, 2022
1 parent 309bae2 commit de48dc2
Show file tree
Hide file tree
Showing 12 changed files with 74 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/OrchardCore.Build/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<PackageManagement Include="PdfPig" Version="0.1.5" />
<PackageManagement Include="Serilog.AspNetCore" Version="5.0.0" />
<PackageManagement Include="Shortcodes" Version="1.3.3" />
<PackageManagement Include="SixLabors.ImageSharp.Web" Version="1.0.5" />
<PackageManagement Include="SixLabors.ImageSharp.Web" Version="2.0.0" />
<PackageManagement Include="System.Linq.Async" Version="6.0.1" />
<PackageManagement Include="xunit.analyzers" Version="0.10.0" />
<PackageManagement Include="xunit" Version="2.4.1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Caching;
using SixLabors.ImageSharp.Web.Commands;

namespace OrchardCore.Media.Processing
{
/// <summary>
/// Backwards compatible absolute url cache key.
/// </summary>
public class BackwardsCompatibleCacheKey : ICacheKey
{
/// <inheritdoc/>
public string Create(HttpContext context, CommandCollection commands)
{

var pathBase = context.Request.PathBase;
if (pathBase.HasValue)
{
// Due to bugs with an earlier version of cache calculation the cache key result was
// localhost:44300/agency1//media/portfolio/5.jpg?width=600&height=480&rmode=stretch
// the default ImageSharp absolute cache builder produces the correct value
// localhost:44300/agency1/media/portfolio/5.jpg?width=600&height=480&rmode=stretch
// which causes an entire cache refresh.
// refer https://github.com/SixLabors/ImageSharp.Web/issues/254

pathBase = new PathString(pathBase + "//");
}

return CaseHandlingUriBuilder.BuildAbsolute(CaseHandlingUriBuilder.CaseHandling.LowerInvariant, context.Request.Host, pathBase, context.Request.Path, QueryString.Create(commands));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@ public IEnumerable<string> Commands

public FormattedImage Process(FormattedImage image, ILogger logger, IDictionary<string, string> commands, CommandParser parser, CultureInfo culture)
=> image;

public FormattedImage Process(FormattedImage image, ILogger logger, CommandCollection commands, CommandParser parser, CultureInfo culture)
=> image;

public bool RequiresTrueColorPixelFormat(CommandCollection commands, CommandParser parser, CultureInfo culture)
=> false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void Configure(ImageSharpMiddlewareOptions options)
options.Configuration = Configuration.Default;
options.BrowserMaxAge = TimeSpan.FromDays(_mediaOptions.MaxBrowserCacheDays);
options.CacheMaxAge = TimeSpan.FromDays(_mediaOptions.MaxCacheDays);
options.CachedNameLength = 12;
options.CacheHashLength = 12;
options.OnParseCommandsAsync = context =>
{
if (context.Commands.Count == 0)
Expand Down Expand Up @@ -72,11 +72,11 @@ public void Configure(ImageSharpMiddlewareOptions options)
context.Commands.Remove(ResizeWebProcessor.Anchor);
// When only a version command is applied pass on this request.
if (context.Commands.Count == 1 && context.Commands.ContainsKey(ImageVersionProcessor.VersionCommand))
if (context.Commands.Count == 1 && context.Commands.Contains(ImageVersionProcessor.VersionCommand))
{
context.Commands.Clear();
}
else if (!context.Commands.ContainsKey(ResizeWebProcessor.Mode))
else if (!context.Commands.Contains(ResizeWebProcessor.Mode))
{
context.Commands[ResizeWebProcessor.Mode] = "max";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.Extensions.Options;
using OrchardCore.Routing;
using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Commands;
using SixLabors.ImageSharp.Web.Middleware;
using SixLabors.ImageSharp.Web.Providers;
using SixLabors.ImageSharp.Web.Resolvers;
Expand All @@ -25,7 +24,6 @@ public class MediaResizingFileProvider : IImageProvider

public MediaResizingFileProvider(
IMediaFileProvider mediaFileProvider,
CommandParser commandParser,
IOptions<ImageSharpMiddlewareOptions> imageSharpOptions,
IOptions<MediaOptions> mediaOptions
)
Expand All @@ -46,14 +44,7 @@ public Func<HttpContext, bool> Match

/// <inheritdoc/>
public bool IsValidRequest(HttpContext context)
{
if (_formatUtilities.GetExtensionFromUri(context.Request.GetDisplayUrl()) == null)
{
return false;
}

return true;
}
=> _formatUtilities.TryGetExtensionFromUri(context.Request.GetDisplayUrl(), out _);

/// <inheritdoc/>
public Task<IImageResolver> GetAsync(HttpContext context)
Expand All @@ -70,8 +61,7 @@ public Task<IImageResolver> GetAsync(HttpContext context)
}

// We don't care about the content type nor cache control max age here.
var metadata = new ImageMetadata(fileInfo.LastModified.UtcDateTime, fileInfo.Length);
return Task.FromResult<IImageResolver>(new PhysicalFileSystemResolver(fileInfo, metadata));
return Task.FromResult<IImageResolver>(new FileProviderImageResolver(fileInfo));
}

private bool IsMatch(HttpContext context)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
Expand Down Expand Up @@ -114,9 +115,9 @@ private void ParseQuery(
}
}

public bool TryValidateToken(IDictionary<string, string> commands, string token)
public bool TryValidateToken(KeyedCollection<string, KeyValuePair<string, string>> commands, string token)
{
var queryStringTokenKey = CreateQueryStringTokenKey(commands);
var queryStringTokenKey = CreateCommandCollectionTokenKey(commands);

// Store a hash of the valid query string commands.
var queryStringToken = GetHash(queryStringTokenKey);
Expand All @@ -140,17 +141,19 @@ private static string CreateQueryStringTokenKey(Dictionary<string, StringValues>
{
builder.Append(pair.Value.ToString());
}

return builder.ToString();
}

private static string CreateQueryStringTokenKey(IDictionary<string, string> values)
private static string CreateCommandCollectionTokenKey(KeyedCollection<string, KeyValuePair<string, string>> values)
{
using var builder = ZString.CreateStringBuilder();
builder.Append(TokenCacheKeyPrefix);
foreach (var pair in values)
{
builder.Append(pair.Value);
}

return builder.ToString();
}

Expand Down Expand Up @@ -183,11 +186,11 @@ private string GetHash(string queryStringTokenKey)
entry.Value = result = Convert.ToBase64String(hashBytes.Slice(0, hashBytesLength));
}

return (string) result;
return (string)result;
}

/// <summary>
/// Custom version of <see cref="QueryHelpers.AddQueryString(string,string,string)"/> that takes our pre-built
/// Custom version of <see cref="QueryHelpers.AddQueryString(String,String,String)"/> that takes our pre-built
/// dictionary, uri as ReadOnlySpan&lt;char&gt; and uses ZString. Otherwise same logic.
/// </summary>
private static string AddQueryString(
Expand Down Expand Up @@ -219,6 +222,7 @@ private static string AddQueryString(
}

sb.Append(anchorText);

return sb.ToString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@ public IEnumerable<string> Commands

public FormattedImage Process(FormattedImage image, ILogger logger, IDictionary<string, string> commands, CommandParser parser, CultureInfo culture)
=> image;

public FormattedImage Process(FormattedImage image, ILogger logger, CommandCollection commands, CommandParser parser, CultureInfo culture)
=> image;

public bool RequiresTrueColorPixelFormat(CommandCollection commands, CommandParser parser, CultureInfo culture)
=> false;
}
}
10 changes: 9 additions & 1 deletion src/OrchardCore.Modules/OrchardCore.Media/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
using OrchardCore.Recipes;
using OrchardCore.Security.Permissions;
using OrchardCore.Shortcodes;
using SixLabors.ImageSharp.Web.Caching;
using SixLabors.ImageSharp.Web.DependencyInjection;
using SixLabors.ImageSharp.Web.Middleware;
using SixLabors.ImageSharp.Web.Providers;
Expand Down Expand Up @@ -132,8 +133,15 @@ public override void ConfigureServices(IServiceCollection services)
// Add ImageSharp Configuration first, to override ImageSharp defaults.
services.AddTransient<IConfigureOptions<ImageSharpMiddlewareOptions>, MediaImageSharpConfiguration>();

services.AddImageSharp()
services
.AddImageSharp()
.RemoveProvider<PhysicalFileSystemProvider>()
// For multitenancy we must use an absolute path to prevent leakage across tenants on different hosts.
.SetCacheKey<BackwardsCompatibleCacheKey>()
.Configure<PhysicalFileSystemCacheOptions>(options =>
{
options.CacheFolderDepth = 12;
})
.AddProvider<MediaResizingFileProvider>()
.AddProcessor<ImageVersionProcessor>()
.AddProcessor<TokenCommandProcessor>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
<span asp-validation-for="Quality"></span>
</div>
<div class="w-100">
<span class="hint">@T["The quality percentage for the processed image. Only supported with the JPG format. A value of 100% means a quality command will not be applied."]</span>
<span class="hint">@T["The quality percentage for the processed image. Only supported with the JPG and WebP format. A value of 100% means a quality command will not be applied."]</span>
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
<span asp-validation-for="Quality"></span>
</div>
<div class="w-100">
<span class="hint">@T["The quality percentage for the processed image. Only supported with the JPG format. A value of 100% means a quality command will not be applied."]</span>
<span class="hint">@T["The quality percentage for the processed image. Only supported with the JPG or WebP format. A value of 100% means a quality command will not be applied."]</span>
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace OrchardCore.Media
{
Expand All @@ -9,6 +10,6 @@ namespace OrchardCore.Media
public interface IMediaTokenService
{
string AddTokenToPath(string path);
bool TryValidateToken(IDictionary<string, string> commands, string token);
bool TryValidateToken(KeyedCollection<string, KeyValuePair<string, string>> commands, string token);
}
}
2 changes: 1 addition & 1 deletion test/OrchardCore.Benchmarks/MediaTokenServiceBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ static MediaTokenServiceBenchmark()
new ResizeWebProcessor(),
new FormatWebProcessor(Options.Create(new ImageSharpMiddlewareOptions())),
new BackgroundColorWebProcessor(),
new JpegQualityWebProcessor(),
new QualityWebProcessor(),
new ImageVersionProcessor(),
new TokenCommandProcessor()
};
Expand Down

0 comments on commit de48dc2

Please sign in to comment.