Skip to content

Commit ee16d23

Browse files
Merge branch 'master' into bp/updatesharedinfra
2 parents 531bf49 + a5b0da1 commit ee16d23

File tree

4 files changed

+139
-12
lines changed

4 files changed

+139
-12
lines changed

src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public ImageSharpMiddleware(
160160
? CultureInfo.InvariantCulture
161161
: CultureInfo.CurrentCulture;
162162

163-
var commands = new HashSet<string>();
163+
var commands = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
164164
foreach (IImageWebProcessor processor in this.processors)
165165
{
166166
foreach (string command in processor.Commands)
@@ -184,23 +184,31 @@ public ImageSharpMiddleware(
184184
public async Task Invoke(HttpContext context)
185185
#pragma warning restore IDE1006 // Naming Styles
186186
{
187-
IDictionary<string, string> commands = this.requestParser.ParseRequestCommands(context);
187+
// We expect to get concrete collection type which removes virtual dispatch concerns and enumerator allocations
188+
IDictionary<string, string> parsedCommands = this.requestParser.ParseRequestCommands(context);
189+
Dictionary<string, string> commands = parsedCommands as Dictionary<string, string> ?? new Dictionary<string, string>(parsedCommands, StringComparer.OrdinalIgnoreCase);
190+
188191
if (commands.Count > 0)
189192
{
190-
// Strip out any unknown commands.
191-
foreach (string command in new List<string>(commands.Keys))
193+
// Strip out any unknown commands, if needed.
194+
int index = 0;
195+
foreach (string command in commands.Keys)
192196
{
193197
if (!this.knownCommands.Contains(command))
194198
{
195-
commands.Remove(command);
199+
// Need to actually remove, allocates new list to allow modifications
200+
this.StripUnknownCommands(commands, startAtIndex: index);
201+
break;
196202
}
203+
204+
index++;
197205
}
198206
}
199207

200208
await this.options.OnParseCommandsAsync.Invoke(
201209
new ImageCommandContext(context, commands, this.commandParser, this.parserCulture));
202210

203-
// Get the correct service for the request.
211+
// Get the correct service for the request
204212
IImageProvider provider = null;
205213
foreach (IImageProvider resolver in this.providers)
206214
{
@@ -238,6 +246,19 @@ await this.ProcessRequestAsync(
238246
commands);
239247
}
240248

249+
private void StripUnknownCommands(Dictionary<string, string> commands, int startAtIndex)
250+
{
251+
var keys = new List<string>(commands.Keys);
252+
for (int index = startAtIndex; index < keys.Count; index++)
253+
{
254+
string command = keys[index];
255+
if (!this.knownCommands.Contains(command))
256+
{
257+
commands.Remove(command);
258+
}
259+
}
260+
}
261+
241262
private async Task ProcessRequestAsync(
242263
HttpContext context,
243264
IImageResolver sourceImageResolver,

src/ImageSharp.Web/Processors/WebProcessingExtensions.cs

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Apache License, Version 2.0.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Globalization;
67
using Microsoft.Extensions.Logging;
@@ -33,15 +34,66 @@ public static FormattedImage Process(
3334
CommandParser commandParser,
3435
CultureInfo culture)
3536
{
36-
if (commands.Count != 0)
37+
var commandKeys = new List<string>(commands.Keys);
38+
39+
foreach (IImageWebProcessor processor in processors.GetBySupportedCommands(commandKeys))
40+
{
41+
source = processor.Process(source, logger, commands, commandParser, culture);
42+
}
43+
44+
return source;
45+
}
46+
47+
/// <summary>
48+
/// Sorts the processors according to the first supported command and removes processors without supported commands.
49+
/// </summary>
50+
/// <param name="processors">The collection of available processors.</param>
51+
/// <param name="commands">The parsed collection of processing commands.</param>
52+
/// <returns>
53+
/// The sorted proccessors that supports any of the specified commands.
54+
/// </returns>
55+
public static IEnumerable<IImageWebProcessor> GetBySupportedCommands(this IEnumerable<IImageWebProcessor> processors, List<string> commands)
56+
{
57+
var indexedProcessors = new List<(int Index, IImageWebProcessor Processor)>();
58+
59+
foreach (IImageWebProcessor processor in processors)
3760
{
38-
foreach (IImageWebProcessor processor in processors)
61+
// Get index of first supported command
62+
int index = commands.FindIndex(c => processor.IsSupportedCommand(c));
63+
if (index != -1)
3964
{
40-
source = processor.Process(source, logger, commands, commandParser, culture);
65+
indexedProcessors.Add((index, processor));
4166
}
4267
}
4368

44-
return source;
69+
indexedProcessors.Sort((x, y) => x.Index.CompareTo(y.Index));
70+
71+
// Return sorted processors
72+
foreach ((int _, IImageWebProcessor processor) in indexedProcessors)
73+
{
74+
yield return processor;
75+
}
76+
}
77+
78+
/// <summary>
79+
/// Determines whether the specified command is supported by the processor
80+
/// </summary>
81+
/// <param name="processor">The processor.</param>
82+
/// <param name="command">The command.</param>
83+
/// <returns>
84+
/// <c>true</c> if the specified command is supported by the processor; otherwise, <c>false</c>.
85+
/// </returns>
86+
public static bool IsSupportedCommand(this IImageWebProcessor processor, string command)
87+
{
88+
foreach (string processorCommand in processor.Commands)
89+
{
90+
if (processorCommand.Equals(command, StringComparison.OrdinalIgnoreCase))
91+
{
92+
return true;
93+
}
94+
}
95+
96+
return false;
4597
}
4698
}
4799
}

tests/ImageSharp.Web.Tests/Processing/PhysicalFileSystemCacheServerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ namespace SixLabors.ImageSharp.Web.Tests.Processing
1616
public class PhysicalFileSystemCacheServerTests : ServerTestBase<PhysicalFileSystemCacheTestServerFixture>
1717
{
1818
private const int Width = 20;
19-
private static readonly string Command = "?width=" + Width + "&v=" + Guid.NewGuid().ToString();
20-
private static readonly string Command2 = "?width=" + (Width + 1) + "&v=" + Guid.NewGuid().ToString();
19+
private static readonly string Command = "?invalidcommand=qwerty&width=" + Width + "&v=" + Guid.NewGuid().ToString();
20+
private static readonly string Command2 = "?invalidcommand=qwerty&width=" + (Width + 1) + "&v=" + Guid.NewGuid().ToString();
2121

2222
public PhysicalFileSystemCacheServerTests(PhysicalFileSystemCacheTestServerFixture fixture)
2323
: base(fixture)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using SixLabors.ImageSharp.Web.Processors;
7+
using SixLabors.ImageSharp.Web.Tests.DependencyInjection;
8+
using Xunit;
9+
10+
namespace SixLabors.ImageSharp.Web.Tests.Processors
11+
{
12+
public class WebProcessingExtensionsTests
13+
{
14+
[Fact]
15+
public void WebProcessingExtensions_GetBySupportedCommands()
16+
{
17+
var processors = new IImageWebProcessor[]
18+
{
19+
new JpegQualityWebProcessor(),
20+
new ResizeWebProcessor(),
21+
new BackgroundColorWebProcessor(),
22+
new MockWebProcessor()
23+
};
24+
25+
var commands = new List<string>
26+
{
27+
ResizeWebProcessor.Width,
28+
JpegQualityWebProcessor.Quality,
29+
ResizeWebProcessor.Height
30+
};
31+
32+
var supportedProcessors = WebProcessingExtensions.GetBySupportedCommands(processors, commands).ToArray();
33+
34+
Assert.Equal(2, supportedProcessors.Length);
35+
Assert.IsType<ResizeWebProcessor>(supportedProcessors[0]);
36+
Assert.IsType<JpegQualityWebProcessor>(supportedProcessors[1]);
37+
}
38+
39+
[Fact]
40+
public void WebProcessingExtensions_GetBySupportedCommands_Empty()
41+
{
42+
var processors = new IImageWebProcessor[]
43+
{
44+
new MockWebProcessor()
45+
};
46+
47+
var commands = new List<string>();
48+
49+
var supportedProcessors = WebProcessingExtensions.GetBySupportedCommands(processors, commands).ToArray();
50+
51+
Assert.Empty(supportedProcessors);
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)