Skip to content

Commit c625825

Browse files
Merge pull request #165 from marklagendijk/master
Implemented preset support
2 parents c9d6e31 + fdcdf98 commit c625825

File tree

4 files changed

+183
-1
lines changed

4 files changed

+183
-1
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.WebUtilities;
9+
using Microsoft.Extensions.Options;
10+
using Microsoft.Extensions.Primitives;
11+
12+
namespace SixLabors.ImageSharp.Web.Commands
13+
{
14+
/// <summary>
15+
/// Parses preset name from the request querystring and returns the commands configured for that preset.
16+
/// </summary>
17+
public class PresetOnlyQueryCollectionRequestParser : IRequestParser
18+
{
19+
private readonly IDictionary<string, IDictionary<string, string>> presets;
20+
21+
/// <summary>
22+
/// The command constant for the preset query parameter.
23+
/// </summary>
24+
public const string QueryKey = "preset";
25+
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="PresetOnlyQueryCollectionRequestParser"/> class.
28+
/// </summary>
29+
/// <param name="presetOptions">The preset options.</param>
30+
public PresetOnlyQueryCollectionRequestParser(IOptions<PresetOnlyQueryCollectionRequestParserOptions> presetOptions) =>
31+
this.presets = ParsePresets(presetOptions.Value.Presets);
32+
33+
/// <inheritdoc/>
34+
public IDictionary<string, string> ParseRequestCommands(HttpContext context)
35+
{
36+
if (context.Request.Query.Count == 0 || !context.Request.Query.ContainsKey(QueryKey))
37+
{
38+
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
39+
}
40+
41+
var requestedPreset = context.Request.Query["preset"][0];
42+
return this.presets.GetValueOrDefault(requestedPreset) ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
43+
}
44+
45+
private static IDictionary<string, IDictionary<string, string>> ParsePresets(
46+
IDictionary<string, string> unparsedPresets) =>
47+
unparsedPresets
48+
.Select(keyValue =>
49+
new KeyValuePair<string, IDictionary<string, string>>(keyValue.Key, ParsePreset(keyValue.Value)))
50+
.ToDictionary(keyValue => keyValue.Key, keyValue => keyValue.Value, StringComparer.OrdinalIgnoreCase);
51+
52+
private static IDictionary<string, string> ParsePreset(string unparsedPresetValue)
53+
{
54+
Dictionary<string, StringValues> parsed = QueryHelpers.ParseQuery(unparsedPresetValue);
55+
var transformed = new Dictionary<string, string>(parsed.Count, StringComparer.OrdinalIgnoreCase);
56+
foreach (KeyValuePair<string, StringValues> keyValue in parsed)
57+
{
58+
transformed[keyValue.Key] = keyValue.Value.ToString();
59+
}
60+
61+
return transformed;
62+
}
63+
}
64+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System.Collections.Generic;
5+
6+
namespace SixLabors.ImageSharp.Web.Commands
7+
{
8+
/// <summary>
9+
/// Configuration options for the <see cref="PresetOnlyQueryCollectionRequestParser"/>.
10+
/// </summary>
11+
public class PresetOnlyQueryCollectionRequestParserOptions
12+
{
13+
/// <summary>
14+
/// Gets or sets the presets, which is a Dictionary of preset names to command query strings.
15+
/// </summary>
16+
public IDictionary<string, string> Presets { get; set; } = new Dictionary<string, string>();
17+
}
18+
}

src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public IDictionary<string, string> ParseRequestCommands(HttpContext context)
2323
}
2424

2525
Dictionary<string, StringValues> parsed = QueryHelpers.ParseQuery(context.Request.QueryString.ToUriComponent());
26-
var transformed = new Dictionary<string, string>(parsed.Count);
26+
var transformed = new Dictionary<string, string>(parsed.Count, StringComparer.OrdinalIgnoreCase);
2727
foreach (KeyValuePair<string, StringValues> pair in parsed)
2828
{
2929
transformed[pair.Key] = pair.Value.ToString();
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.Extensions.Options;
8+
using SixLabors.ImageSharp.Web.Commands;
9+
using Xunit;
10+
11+
namespace SixLabors.ImageSharp.Web.Tests.Commands
12+
{
13+
public class PresetOnlyQueryCollectionRequestParserTests
14+
{
15+
[Fact]
16+
public void PresetOnlyQueryCollectionRequestParserExtractsCommands()
17+
{
18+
IDictionary<string, string> expected = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
19+
{
20+
{ "width", "400" },
21+
{ "height", "200" }
22+
};
23+
24+
HttpContext context = CreateHttpContext("?preset=Preset1");
25+
IDictionary<string, string> actual = new PresetOnlyQueryCollectionRequestParser(Options.Create(new PresetOnlyQueryCollectionRequestParserOptions
26+
{
27+
Presets = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
28+
{
29+
{ "Preset1", "width=400&height=200" }
30+
}
31+
})).ParseRequestCommands(context);
32+
33+
Assert.Equal(expected, actual);
34+
}
35+
36+
[Fact]
37+
public void PresetOnlyQueryCollectionRequestParserExtractsCommandsWithOtherCasing()
38+
{
39+
IDictionary<string, string> expected = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
40+
{
41+
{ "width", "400" },
42+
{ "height", "200" }
43+
};
44+
45+
HttpContext context = CreateHttpContext("?PRESET=PRESET1");
46+
IDictionary<string, string> actual = new PresetOnlyQueryCollectionRequestParser(Options.Create(new PresetOnlyQueryCollectionRequestParserOptions
47+
{
48+
Presets = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
49+
{
50+
{ "Preset1", "width=400&height=200" }
51+
}
52+
})).ParseRequestCommands(context);
53+
54+
Assert.Equal(expected, actual);
55+
}
56+
57+
58+
[Fact]
59+
public void PresetOnlyQueryCollectionRequestParserCommandsWithoutPresetParam()
60+
{
61+
IDictionary<string, string> expected = new Dictionary<string, string>();
62+
63+
HttpContext context = CreateHttpContext("?test=test");
64+
IDictionary<string, string> actual = new PresetOnlyQueryCollectionRequestParser(Options.Create(new PresetOnlyQueryCollectionRequestParserOptions
65+
{
66+
Presets = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
67+
{
68+
{ "Preset1", "width=400&height=200" }
69+
}
70+
})).ParseRequestCommands(context);
71+
72+
Assert.Equal(expected, actual);
73+
}
74+
75+
[Fact]
76+
public void PresetOnlyQueryCollectionRequestParserCommandsWithoutMatchingPreset()
77+
{
78+
IDictionary<string, string> expected = new Dictionary<string, string>();
79+
80+
HttpContext context = CreateHttpContext("?preset=Preset2");
81+
IDictionary<string, string> actual = new PresetOnlyQueryCollectionRequestParser(Options.Create(new PresetOnlyQueryCollectionRequestParserOptions
82+
{
83+
Presets = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
84+
{
85+
{ "Preset1", "width=400&height=200" }
86+
}
87+
})).ParseRequestCommands(context);
88+
89+
Assert.Equal(expected, actual);
90+
}
91+
92+
private static HttpContext CreateHttpContext(string query)
93+
{
94+
var httpContext = new DefaultHttpContext();
95+
httpContext.Request.Path = "/testwebsite.com/image-12345.jpeg";
96+
httpContext.Request.QueryString = new QueryString(query);
97+
return httpContext;
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)