diff --git a/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs b/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs index 9df159f8..78532d55 100644 --- a/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs +++ b/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs @@ -9,7 +9,6 @@ using System.IO; using System.Linq; using System.Text; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -161,7 +160,7 @@ public ImageSharpMiddleware( ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture; - var commands = new HashSet(); + var commands = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (IImageWebProcessor processor in this.processors) { foreach (string command in processor.Commands) @@ -185,16 +184,24 @@ public ImageSharpMiddleware( public async Task Invoke(HttpContext context) #pragma warning restore IDE1006 // Naming Styles { - IDictionary commands = this.requestParser.ParseRequestCommands(context); + // We expect to get concrete collection type which removes virtual dispatch concerns and enumerator allocations + IDictionary parsedCommands = this.requestParser.ParseRequestCommands(context); + Dictionary commands = parsedCommands as Dictionary ?? new Dictionary(parsedCommands, StringComparer.OrdinalIgnoreCase); + if (commands.Count > 0) { - // Strip out any unknown commands - foreach (string command in new List(commands.Keys)) + // Strip out any unknown commands, if needed. + int index = 0; + foreach (string command in commands.Keys) { - if (!this.knownCommands.Contains(command, StringComparer.OrdinalIgnoreCase)) + if (!this.knownCommands.Contains(command)) { - commands.Remove(command); + // Need to actually remove, allocates new list to allow modifications + this.StripUnknownCommands(commands, startAtIndex: index); + break; } + + index++; } } @@ -239,6 +246,19 @@ await this.ProcessRequestAsync( commands); } + private void StripUnknownCommands(Dictionary commands, int startAtIndex) + { + var keys = new List(commands.Keys); + for (int index = startAtIndex; index < keys.Count; index++) + { + string command = keys[index]; + if (!this.knownCommands.Contains(command)) + { + commands.Remove(command); + } + } + } + private async Task ProcessRequestAsync( HttpContext context, IImageResolver sourceImageResolver, diff --git a/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs b/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs index a8cd8125..e96d08f0 100644 --- a/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs +++ b/tests/ImageSharp.Web.Tests/Commands/PresetOnlyQueryCollectionRequestParserTests.cs @@ -54,7 +54,6 @@ public void PresetOnlyQueryCollectionRequestParserExtractsCommandsWithOtherCasin Assert.Equal(expected, actual); } - [Fact] public void PresetOnlyQueryCollectionRequestParserCommandsWithoutPresetParam() { diff --git a/tests/ImageSharp.Web.Tests/Processing/PhysicalFileSystemCacheServerTests.cs b/tests/ImageSharp.Web.Tests/Processing/PhysicalFileSystemCacheServerTests.cs index 118b8ca7..076311da 100644 --- a/tests/ImageSharp.Web.Tests/Processing/PhysicalFileSystemCacheServerTests.cs +++ b/tests/ImageSharp.Web.Tests/Processing/PhysicalFileSystemCacheServerTests.cs @@ -16,8 +16,8 @@ namespace SixLabors.ImageSharp.Web.Tests.Processing public class PhysicalFileSystemCacheServerTests : ServerTestBase { private const int Width = 20; - private static readonly string Command = "?width=" + Width + "&v=" + Guid.NewGuid().ToString(); - private static readonly string Command2 = "?width=" + (Width + 1) + "&v=" + Guid.NewGuid().ToString(); + private static readonly string Command = "?invalidcommand=qwerty&width=" + Width + "&v=" + Guid.NewGuid().ToString(); + private static readonly string Command2 = "?invalidcommand=qwerty&width=" + (Width + 1) + "&v=" + Guid.NewGuid().ToString(); public PhysicalFileSystemCacheServerTests(PhysicalFileSystemCacheTestServerFixture fixture) : base(fixture)