Browse Source

Further attempt at protecting the Save method

Former-commit-id: b2768040730f1934e0fecf74d4b304828c5a587d
af/merge-core
James South 12 years ago
parent
commit
29953451a5
  1. 1
      src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
  2. 2
      src/ImageProcessor.Web/NET45/Helpers/TaskHelpers.cs
  3. 163
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  4. 5
      src/ImageProcessor.Web/NET45/Settings.StyleCop
  5. 1
      src/ImageProcessor/ImageFactory.cs

1
src/ImageProcessor.Web/NET45/Caching/DiskCache.cs

@ -301,6 +301,7 @@ namespace ImageProcessor.Web.Caching
{ {
DateTime dateTime = imageFileInfo.LastWriteTimeUtc; DateTime dateTime = imageFileInfo.LastWriteTimeUtc;
creationTime = cachedFileInfo.CreationTimeUtc; creationTime = cachedFileInfo.CreationTimeUtc;
cachedFileInfo.LastWriteTimeUtc = dateTime; cachedFileInfo.LastWriteTimeUtc = dateTime;
lastWriteTime = dateTime; lastWriteTime = dateTime;

2
src/ImageProcessor.Web/NET45/Helpers/TaskHelpers.cs

@ -12,7 +12,7 @@ namespace ImageProcessor.Web.Helpers
{ {
#region Using #region Using
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
#endregion #endregion
/// <summary> /// <summary>

163
src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs

@ -12,6 +12,7 @@ namespace ImageProcessor.Web.HttpModules
{ {
#region Using #region Using
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -20,6 +21,7 @@ namespace ImageProcessor.Web.HttpModules
using System.Security; using System.Security;
using System.Security.Permissions; using System.Security.Permissions;
using System.Security.Principal; using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
@ -51,6 +53,44 @@ namespace ImageProcessor.Web.HttpModules
/// The assembly version. /// The assembly version.
/// </summary> /// </summary>
private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
/// <summary>
/// The collection of Semaphores for identifying given locking individual queries.
/// </summary>
private static readonly Dictionary<string, Semaphore> Semaphores = new Dictionary<string, Semaphore>();
/// <summary>
/// A value indicating whether this instance of the given entity has been disposed.
/// </summary>
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
/// <remarks>
/// If the entity is disposed, it must not be disposed a second
/// time. The isDisposed field is set the first time the entity
/// is disposed. If the isDisposed field is true, then the Dispose()
/// method will not dispose again. This help not to prolong the entity's
/// life in the Garbage Collector.
/// </remarks>
private bool isDisposed;
#endregion
#region Destructors
/// <summary>
/// Finalizes an instance of the <see cref="T:ImageProcessor.Web.HttpModules.ImageProcessingModule"/> class.
/// </summary>
/// <remarks>
/// Use C# destructor syntax for finalization code.
/// This destructor will run only if the Dispose method
/// does not get called.
/// It gives your base class the opportunity to finalize.
/// Do not provide destructors in types derived from this class.
/// </remarks>
~ImageProcessingModule()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
this.Dispose(false);
}
#endregion #endregion
#region IHttpModule Members #region IHttpModule Members
@ -83,7 +123,65 @@ namespace ImageProcessor.Web.HttpModules
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
// Nothing to dispose. this.Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Gets the specific <see cref="T:System.Threading.Semaphore"/> for the given id.
/// </summary>
/// <param name="id">
/// The id representing the <see cref="T:System.Threading.Semaphore"/>.
/// </param>
/// <returns>
/// The <see cref="T:System.Threading.Mutex"/> for the given id.
/// </returns>
private static Semaphore GetSemaphore(string id)
{
id = id.ToMD5Fingerprint();
if (Semaphores.ContainsKey(id))
{
return Semaphores[id];
}
Semaphore semaphore = new Semaphore(1, 1, id);
Semaphores.Add(id, semaphore);
return semaphore;
}
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">If true, the object gets disposed.</param>
private void Dispose(bool disposing)
{
if (this.isDisposed)
{
return;
}
if (disposing)
{
// Dispose of any managed resources here.
foreach (KeyValuePair<string, Semaphore> semaphore in Semaphores)
{
semaphore.Value.Dispose();
}
Semaphores.Clear();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// Note disposing is done.
this.isDisposed = true;
} }
#endregion #endregion
@ -294,19 +392,31 @@ namespace ImageProcessor.Web.HttpModules
{ {
responseStream.CopyTo(memoryStream); responseStream.CopyTo(memoryStream);
imageFactory.Load(memoryStream) Semaphore semaphore = GetSemaphore(cachedPath);
.AddQueryString(queryString) try
.Format(ImageUtils.GetImageFormat(imageName)) {
.AutoProcess().Save(cachedPath); semaphore.WaitOne();
// Ensure that the LastWriteTime property of the source and cached file match. // Process the Image
Tuple<DateTime, DateTime> creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync(); imageFactory.Load(memoryStream)
.AddQueryString(queryString)
// Add to the cache. .Format(ImageUtils.GetImageFormat(imageName))
cache.AddImageToCache(creationAndLastWriteDateTimes); .AutoProcess()
.Save(cachedPath);
// Trim the cache.
await cache.TrimCachedFolderAsync(cachedPath); // Ensure that the LastWriteTime property of the source and cached file match.
Tuple<DateTime, DateTime> creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync();
// Add to the cache.
cache.AddImageToCache(creationAndLastWriteDateTimes);
// Trim the cache.
await cache.TrimCachedFolderAsync(cachedPath);
}
finally
{
semaphore.Release();
}
} }
} }
} }
@ -323,16 +433,27 @@ namespace ImageProcessor.Web.HttpModules
throw new HttpException(404, "No image exists at " + fullPath); throw new HttpException(404, "No image exists at " + fullPath);
} }
imageFactory.Load(fullPath).AutoProcess().Save(cachedPath); Semaphore semaphore = GetSemaphore(cachedPath);
try
{
semaphore.WaitOne();
// Process the Image
imageFactory.Load(fullPath).AutoProcess().Save(cachedPath);
// Ensure that the LastWriteTime property of the source and cached file match. // Ensure that the LastWriteTime property of the source and cached file match.
Tuple<DateTime, DateTime> creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync(); Tuple<DateTime, DateTime> creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync();
// Add to the cache. // Add to the cache.
cache.AddImageToCache(creationAndLastWriteDateTimes); cache.AddImageToCache(creationAndLastWriteDateTimes);
// Trim the cache. // Trim the cache.
await cache.TrimCachedFolderAsync(cachedPath); await cache.TrimCachedFolderAsync(cachedPath);
}
finally
{
semaphore.Release();
}
} }
} }
} }

5
src/ImageProcessor.Web/NET45/Settings.StyleCop

@ -1,4 +1,9 @@
<StyleCopSettings Version="105"> <StyleCopSettings Version="105">
<GlobalSettings>
<CollectionProperty Name="RecognizedWords">
<Value>Mutexes</Value>
</CollectionProperty>
</GlobalSettings>
<Analyzers> <Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules"> <Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<AnalyzerSettings> <AnalyzerSettings>

1
src/ImageProcessor/ImageFactory.cs

@ -77,7 +77,6 @@ namespace ImageProcessor
// readability and maintainability. // readability and maintainability.
this.Dispose(false); this.Dispose(false);
} }
#endregion #endregion
#region Properties #region Properties

Loading…
Cancel
Save