Skip to content

Commit 583b063

Browse files
committed
Refactor ProcessRequestAsync() slightly so that SendResponseAsync() is always called from outside the lock.
1 parent f804401 commit 583b063

File tree

1 file changed

+69
-73
lines changed

1 file changed

+69
-73
lines changed

src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs

Lines changed: 69 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,6 @@ private async Task ProcessRequestAsync(
286286

287287
// Enter an asynchronous write worker which prevents multiple writes and delays any reads for the same request.
288288
// This reduces the overheads of unnecessary processing.
289-
ImageWorkerResult writeResult;
290-
291289
RecyclableMemoryStream outStream = null;
292290
try
293291
{
@@ -301,89 +299,87 @@ private async Task ProcessRequestAsync(
301299
if (lockWasAlreadyHeld)
302300
{
303301
readResult = await this.IsNewOrUpdatedAsync(sourceImageResolver, key);
304-
if (!readResult.IsNewOrUpdated)
305-
{
306-
await this.SendResponseAsync(imageContext, key, readResult.CacheImageMetadata, readResult.Resolver, null);
307-
return;
308-
}
309302
}
310303

311-
try
304+
if (readResult.IsNewOrUpdated)
312305
{
313-
ImageCacheMetadata cachedImageMetadata = default;
314-
outStream = new RecyclableMemoryStream(this.options.MemoryStreamManager);
315-
IImageFormat format;
316-
317-
// 14.9.3 CacheControl Max-Age
318-
// Check to see if the source metadata has a CacheControl Max-Age value
319-
// and use it to override the default max age from our options.
320-
TimeSpan maxAge = this.options.BrowserMaxAge;
321-
if (!sourceImageMetadata.CacheControlMaxAge.Equals(TimeSpan.MinValue))
322-
{
323-
maxAge = sourceImageMetadata.CacheControlMaxAge;
324-
}
325-
326-
using (Stream inStream = await sourceImageResolver.OpenReadAsync())
306+
try
327307
{
328-
// No commands? We simply copy the stream across.
329-
if (commands.Count == 0)
308+
ImageCacheMetadata cachedImageMetadata = default;
309+
outStream = new RecyclableMemoryStream(this.options.MemoryStreamManager);
310+
IImageFormat format;
311+
312+
// 14.9.3 CacheControl Max-Age
313+
// Check to see if the source metadata has a CacheControl Max-Age value
314+
// and use it to override the default max age from our options.
315+
TimeSpan maxAge = this.options.BrowserMaxAge;
316+
if (!sourceImageMetadata.CacheControlMaxAge.Equals(TimeSpan.MinValue))
330317
{
331-
await inStream.CopyToAsync(outStream);
332-
outStream.Position = 0;
333-
format = await Image.DetectFormatAsync(this.options.Configuration, outStream);
318+
maxAge = sourceImageMetadata.CacheControlMaxAge;
334319
}
335-
else
336-
{
337-
using var image = FormattedImage.Load(this.options.Configuration, inStream);
338-
339-
image.Process(
340-
this.logger,
341-
this.processors,
342-
commands,
343-
this.commandParser,
344-
this.parserCulture);
345320

346-
await this.options.OnBeforeSaveAsync.Invoke(image);
347-
348-
image.Save(outStream);
349-
format = image.Format;
321+
using (Stream inStream = await sourceImageResolver.OpenReadAsync())
322+
{
323+
// No commands? We simply copy the stream across.
324+
if (commands.Count == 0)
325+
{
326+
await inStream.CopyToAsync(outStream);
327+
outStream.Position = 0;
328+
format = await Image.DetectFormatAsync(this.options.Configuration, outStream);
329+
}
330+
else
331+
{
332+
using var image = FormattedImage.Load(this.options.Configuration, inStream);
333+
334+
image.Process(
335+
this.logger,
336+
this.processors,
337+
commands,
338+
this.commandParser,
339+
this.parserCulture);
340+
341+
await this.options.OnBeforeSaveAsync.Invoke(image);
342+
343+
image.Save(outStream);
344+
format = image.Format;
345+
}
350346
}
351-
}
352347

353-
// Allow for any further optimization of the image.
354-
outStream.Position = 0;
355-
string contentType = format.DefaultMimeType;
356-
string extension = this.formatUtilities.GetExtensionFromContentType(contentType);
357-
await this.options.OnProcessedAsync.Invoke(new ImageProcessingContext(context, outStream, commands, contentType, extension));
358-
outStream.Position = 0;
359-
360-
cachedImageMetadata = new ImageCacheMetadata(
361-
sourceImageMetadata.LastWriteTimeUtc,
362-
DateTime.UtcNow,
363-
contentType,
364-
maxAge,
365-
outStream.Length);
366-
367-
// Save the image to the cache and send the response to the caller.
368-
await this.cache.SetAsync(key, outStream, cachedImageMetadata);
369-
outStream.Position = 0;
370-
371-
// Remove any resolver from the cache so we always resolve next request
372-
// for the same key.
373-
CacheResolverLru.TryRemove(key);
374-
375-
writeResult = new ImageWorkerResult(cachedImageMetadata, null);
376-
}
377-
catch (Exception ex)
378-
{
379-
// Log the error internally then rethrow.
380-
// We don't call next here, the pipeline will automatically handle it
381-
this.logger.LogImageProcessingFailed(imageContext.GetDisplayUrl(), ex);
382-
throw;
348+
// Allow for any further optimization of the image.
349+
outStream.Position = 0;
350+
string contentType = format.DefaultMimeType;
351+
string extension = this.formatUtilities.GetExtensionFromContentType(contentType);
352+
await this.options.OnProcessedAsync.Invoke(new ImageProcessingContext(context, outStream, commands, contentType, extension));
353+
outStream.Position = 0;
354+
355+
cachedImageMetadata = new ImageCacheMetadata(
356+
sourceImageMetadata.LastWriteTimeUtc,
357+
DateTime.UtcNow,
358+
contentType,
359+
maxAge,
360+
outStream.Length);
361+
362+
// Save the image to the cache and send the response to the caller.
363+
await this.cache.SetAsync(key, outStream, cachedImageMetadata);
364+
outStream.Position = 0;
365+
366+
// Remove any resolver from the cache so we always resolve next request
367+
// for the same key.
368+
CacheResolverLru.TryRemove(key);
369+
370+
readResult = new ImageWorkerResult(cachedImageMetadata, null);
371+
}
372+
catch (Exception ex)
373+
{
374+
// Log the error internally then rethrow.
375+
// We don't call next here, the pipeline will automatically handle it
376+
this.logger.LogImageProcessingFailed(imageContext.GetDisplayUrl(), ex);
377+
throw;
378+
}
383379
}
384380
}
385381

386-
await this.SendResponseAsync(imageContext, key, writeResult.CacheImageMetadata, writeResult.Resolver, outStream);
382+
await this.SendResponseAsync(imageContext, key, readResult.CacheImageMetadata, readResult.Resolver, outStream);
387383
}
388384
finally
389385
{

0 commit comments

Comments
 (0)