Skip to content

Commit 93d73f0

Browse files
Merge pull request #327 from SixLabors/js/remove-async-hmac
Remove async HMAC operations.
2 parents 67e82ab + 58ffdf5 commit 93d73f0

File tree

6 files changed

+28
-88
lines changed

6 files changed

+28
-88
lines changed

src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,9 @@ private async Task Invoke(HttpContext httpContext, bool retry)
228228
//
229229
// As a rule all image requests should contain valid commands only.
230230
// Key generation uses string.Create under the hood with very low allocation so should be good enough as a cache key.
231-
hmac = await HMACTokenLru.GetOrAddAsync(
231+
hmac = HMACTokenLru.GetOrAdd(
232232
httpContext.Request.GetEncodedUrl(),
233-
_ => this.authorizationUtilities.ComputeHMACAsync(imageCommandContext));
233+
_ => this.authorizationUtilities.ComputeHMAC(imageCommandContext));
234234
}
235235

236236
await this.options.OnParseCommandsAsync.Invoke(imageCommandContext);

src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ namespace SixLabors.ImageSharp.Web.Middleware;
1515
/// </summary>
1616
public class ImageSharpMiddlewareOptions
1717
{
18-
private Func<ImageCommandContext, byte[], Task<string>> onComputeHMACAsync = (context, secret) =>
18+
private Func<ImageCommandContext, byte[], string> onComputeHMAC = (context, secret) =>
1919
{
2020
string uri = CaseHandlingUriBuilder.BuildRelative(
2121
CaseHandlingUriBuilder.CaseHandling.LowerInvariant,
2222
context.Context.Request.PathBase,
2323
context.Context.Request.Path,
2424
QueryString.Create(context.Commands));
2525

26-
return Task.FromResult(HMACUtilities.ComputeHMACSHA256(uri, secret));
26+
return HMACUtilities.ComputeHMACSHA256(uri, secret);
2727
};
2828

2929
private Func<ImageCommandContext, Task> onParseCommandsAsync = _ => Task.CompletedTask;
@@ -88,14 +88,14 @@ public class ImageSharpMiddlewareOptions
8888
/// Defaults to <see cref="HMACUtilities.ComputeHMACSHA256(string, byte[])"/> using an invariant lowercase relative Uri
8989
/// generated using <see cref="CaseHandlingUriBuilder.BuildRelative(CaseHandlingUriBuilder.CaseHandling, PathString, PathString, QueryString)"/>.
9090
/// </summary>
91-
public Func<ImageCommandContext, byte[], Task<string>> OnComputeHMACAsync
91+
public Func<ImageCommandContext, byte[], string> OnComputeHMAC
9292
{
93-
get => this.onComputeHMACAsync;
93+
get => this.onComputeHMAC;
9494

9595
set
9696
{
97-
Guard.NotNull(value, nameof(this.onComputeHMACAsync));
98-
this.onComputeHMACAsync = value;
97+
Guard.NotNull(value, nameof(this.onComputeHMAC));
98+
this.onComputeHMAC = value;
9999
}
100100
}
101101

src/ImageSharp.Web/RequestAuthorizationUtilities.cs

Lines changed: 3 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,6 @@ public void StripUnknownCommands(CommandCollection commands)
9898
public string? ComputeHMAC(string uri, CommandHandling handling)
9999
=> this.ComputeHMAC(new Uri(uri, UriKind.RelativeOrAbsolute), handling);
100100

101-
/// <summary>
102-
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
103-
/// </summary>
104-
/// <param name="uri">The uri to compute the code from.</param>
105-
/// <param name="handling">The command collection handling.</param>
106-
/// <returns>The computed HMAC.</returns>
107-
public Task<string?> ComputeHMACAsync(string uri, CommandHandling handling)
108-
=> this.ComputeHMACAsync(new Uri(uri, UriKind.RelativeOrAbsolute), handling);
109-
110101
/// <summary>
111102
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
112103
/// </summary>
@@ -124,23 +115,6 @@ public void StripUnknownCommands(CommandCollection commands)
124115
return this.ComputeHMAC(host, path, queryString, handling);
125116
}
126117

127-
/// <summary>
128-
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
129-
/// </summary>
130-
/// <param name="uri">The uri to compute the code from.</param>
131-
/// <param name="handling">The command collection handling.</param>
132-
/// <returns>The computed HMAC.</returns>
133-
public Task<string?> ComputeHMACAsync(Uri uri, CommandHandling handling)
134-
{
135-
ToComponents(
136-
uri,
137-
out HostString host,
138-
out PathString path,
139-
out QueryString queryString);
140-
141-
return this.ComputeHMACAsync(host, path, queryString, handling);
142-
}
143-
144118
/// <summary>
145119
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
146120
/// </summary>
@@ -152,17 +126,6 @@ public void StripUnknownCommands(CommandCollection commands)
152126
public string? ComputeHMAC(HostString host, PathString path, QueryString queryString, CommandHandling handling)
153127
=> this.ComputeHMAC(host, path, queryString, new(QueryHelpers.ParseQuery(queryString.Value)), handling);
154128

155-
/// <summary>
156-
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
157-
/// </summary>
158-
/// <param name="host">The host header.</param>
159-
/// <param name="path">The path or pathbase.</param>
160-
/// <param name="queryString">The querystring.</param>
161-
/// <param name="handling">The command collection handling.</param>
162-
/// <returns>The computed HMAC.</returns>
163-
public Task<string?> ComputeHMACAsync(HostString host, PathString path, QueryString queryString, CommandHandling handling)
164-
=> this.ComputeHMACAsync(host, path, queryString, new(QueryHelpers.ParseQuery(queryString.Value)), handling);
165-
166129
/// <summary>
167130
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
168131
/// </summary>
@@ -175,34 +138,13 @@ public void StripUnknownCommands(CommandCollection commands)
175138
public string? ComputeHMAC(HostString host, PathString path, QueryString queryString, QueryCollection query, CommandHandling handling)
176139
=> this.ComputeHMAC(this.ToHttpContext(host, path, queryString, query), handling);
177140

178-
/// <summary>
179-
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
180-
/// </summary>
181-
/// <param name="host">The host header.</param>
182-
/// <param name="path">The path or pathbase.</param>
183-
/// <param name="queryString">The querystring.</param>
184-
/// <param name="query">The query collection.</param>
185-
/// <param name="handling">The command collection handling.</param>
186-
/// <returns>The computed HMAC.</returns>
187-
public Task<string?> ComputeHMACAsync(HostString host, PathString path, QueryString queryString, QueryCollection query, CommandHandling handling)
188-
=> this.ComputeHMACAsync(this.ToHttpContext(host, path, queryString, query), handling);
189-
190141
/// <summary>
191142
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
192143
/// </summary>
193144
/// <param name="context">The request HTTP context.</param>
194145
/// <param name="handling">The command collection handling.</param>
195146
/// <returns>The computed HMAC.</returns>
196147
public string? ComputeHMAC(HttpContext context, CommandHandling handling)
197-
=> AsyncHelper.RunSync(() => this.ComputeHMACAsync(context, handling));
198-
199-
/// <summary>
200-
/// Compute a Hash-based Message Authentication Code (HMAC) for request authentication.
201-
/// </summary>
202-
/// <param name="context">The request HTTP context.</param>
203-
/// <param name="handling">The command collection handling.</param>
204-
/// <returns>The computed HMAC.</returns>
205-
public async Task<string?> ComputeHMACAsync(HttpContext context, CommandHandling handling)
206148
{
207149
byte[] secret = this.options.HMACSecretKey;
208150
if (secret is null || secret.Length == 0)
@@ -222,7 +164,7 @@ public void StripUnknownCommands(CommandCollection commands)
222164
}
223165

224166
ImageCommandContext imageCommandContext = new(context, commands, this.commandParser, this.parserCulture);
225-
return await this.options.OnComputeHMACAsync(imageCommandContext, secret);
167+
return this.options.OnComputeHMAC(imageCommandContext, secret);
226168
}
227169

228170
/// <summary>
@@ -234,14 +176,14 @@ public void StripUnknownCommands(CommandCollection commands)
234176
/// </remarks>
235177
/// <param name="context">Contains information about the current image request and parsed commands.</param>
236178
/// <returns>The computed HMAC.</returns>
237-
internal async Task<string?> ComputeHMACAsync(ImageCommandContext context)
179+
internal string? ComputeHMAC(ImageCommandContext context)
238180
{
239181
if (context.Commands.Count == 0)
240182
{
241183
return null;
242184
}
243185

244-
return await this.options.OnComputeHMACAsync(context, this.options.HMACSecretKey);
186+
return this.options.OnComputeHMAC(context, this.options.HMACSecretKey);
245187
}
246188

247189
private static void ToComponents(

src/ImageSharp.Web/AsyncHelper.cs renamed to tests/ImageSharp.Web.Tests/TestUtilities/AsyncHelper.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
using System.Globalization;
55

6-
namespace SixLabors.ImageSharp.Web;
6+
namespace SixLabors.ImageSharp.Web.Tests.TestUtilities;
77

88
/// <summary>
99
/// <see href="https://github.com/aspnet/AspNetIdentity/blob/b7826741279450c58b230ece98bd04b4815beabf/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs"/>
@@ -20,7 +20,7 @@ private static readonly TaskFactory TaskFactory
2020
/// <summary>
2121
/// Executes an async <see cref="Task"/> method synchronously.
2222
/// </summary>
23-
/// <param name="task">The task to excecute.</param>
23+
/// <param name="task">The task to execute.</param>
2424
public static void RunSync(Func<Task> task)
2525
{
2626
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
@@ -38,7 +38,7 @@ public static void RunSync(Func<Task> task)
3838
/// a <paramref name="task"/> return type synchronously.
3939
/// </summary>
4040
/// <typeparam name="TResult">The type of result to return.</typeparam>
41-
/// <param name="task">The task to excecute.</param>
41+
/// <param name="task">The task to execute.</param>
4242
/// <returns>The <typeparamref name="TResult"/>.</returns>
4343
public static TResult RunSync<TResult>(Func<Task<TResult>> task)
4444
{

tests/ImageSharp.Web.Tests/TestUtilities/AuthenticatedServerTestBase.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ public abstract class AuthenticatedServerTestBase<TFixture> : ServerTestBase<TFi
1111
where TFixture : AuthenticatedTestServerFixture
1212
{
1313
private readonly RequestAuthorizationUtilities authorizationUtilities;
14-
private readonly string relativeImageSouce;
14+
private readonly string relativeImageSource;
1515

1616
protected AuthenticatedServerTestBase(TFixture fixture, ITestOutputHelper outputHelper, string imageSource)
1717
: base(fixture, outputHelper, imageSource)
1818
{
1919
this.authorizationUtilities =
2020
this.Fixture.Services.GetRequiredService<RequestAuthorizationUtilities>();
2121

22-
this.relativeImageSouce = this.ImageSource.Replace("http://localhost", string.Empty);
22+
this.relativeImageSource = this.ImageSource.Replace("http://localhost", string.Empty);
2323
}
2424

2525
[Fact]
@@ -40,19 +40,17 @@ public async Task CanRejectUnauthorizedRequestAsync()
4040
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
4141
}
4242

43-
protected override async Task<string> AugmentCommandAsync(string command)
43+
protected override string AugmentCommand(string command)
4444
{
45-
string uri = this.relativeImageSouce + command;
46-
string token = await this.GetTokenAsync(uri);
45+
string uri = this.relativeImageSource + command;
46+
string token = this.GetToken(uri);
4747
return command + "&" + RequestAuthorizationUtilities.TokenCommand + "=" + token;
4848
}
4949

50-
private async Task<string> GetTokenAsync(string uri)
50+
private string GetToken(string uri)
5151
{
5252
string tokenSync = this.authorizationUtilities.ComputeHMAC(uri, CommandHandling.Sanitize);
53-
string tokenAsync = await this.authorizationUtilities.ComputeHMACAsync(uri, CommandHandling.Sanitize);
54-
55-
Assert.Equal(tokenSync, tokenAsync);
53+
Assert.NotNull(tokenSync);
5654
return tokenSync;
5755
}
5856
}

tests/ImageSharp.Web.Tests/TestUtilities/ServerTestBase.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task CanProcessAndResolveImageAsync()
4545
Assert.True(Configuration.Default.ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format));
4646

4747
// First response
48-
HttpResponseMessage response = await this.HttpClient.GetAsync(url + await this.AugmentCommandAsync(this.Fixture.Commands[0]));
48+
HttpResponseMessage response = await this.HttpClient.GetAsync(url + this.AugmentCommand(this.Fixture.Commands[0]));
4949

5050
Assert.NotNull(response);
5151
Assert.True(response.IsSuccessStatusCode);
@@ -60,7 +60,7 @@ public async Task CanProcessAndResolveImageAsync()
6060
response.Dispose();
6161

6262
// Cached Response
63-
response = await this.HttpClient.GetAsync(url + await this.AugmentCommandAsync(this.Fixture.Commands[0]));
63+
response = await this.HttpClient.GetAsync(url + this.AugmentCommand(this.Fixture.Commands[0]));
6464

6565
Assert.NotNull(response);
6666
Assert.True(response.IsSuccessStatusCode);
@@ -77,7 +77,7 @@ public async Task CanProcessAndResolveImageAsync()
7777
// 304 response
7878
HttpRequestMessage request = new()
7979
{
80-
RequestUri = new Uri(url + await this.AugmentCommandAsync(this.Fixture.Commands[0])),
80+
RequestUri = new Uri(url + this.AugmentCommand(this.Fixture.Commands[0])),
8181
Method = HttpMethod.Get,
8282
};
8383

@@ -100,7 +100,7 @@ public async Task CanProcessAndResolveImageAsync()
100100
// 412 response
101101
request = new HttpRequestMessage
102102
{
103-
RequestUri = new Uri(url + await this.AugmentCommandAsync(this.Fixture.Commands[0])),
103+
RequestUri = new Uri(url + this.AugmentCommand(this.Fixture.Commands[0])),
104104
Method = HttpMethod.Get,
105105
};
106106

@@ -119,8 +119,8 @@ public async Task CanProcessAndResolveImageAsync()
119119
public async Task CanProcessMultipleIdenticalQueriesAsync()
120120
{
121121
string url = this.ImageSource;
122-
string command1 = await this.AugmentCommandAsync(this.Fixture.Commands[0]);
123-
string command2 = await this.AugmentCommandAsync(this.Fixture.Commands[1]);
122+
string command1 = this.AugmentCommand(this.Fixture.Commands[0]);
123+
string command2 = this.AugmentCommand(this.Fixture.Commands[1]);
124124

125125
Task[] tasks = Enumerable.Range(0, 100).Select(i => Task.Run(async () =>
126126
{
@@ -136,5 +136,5 @@ public async Task CanProcessMultipleIdenticalQueriesAsync()
136136
Assert.True(all.IsCompletedSuccessfully);
137137
}
138138

139-
protected virtual Task<string> AugmentCommandAsync(string command) => Task.FromResult(command);
139+
protected virtual string AugmentCommand(string command) => command;
140140
}

0 commit comments

Comments
 (0)