Browse Source

Fixing issue #65

Former-commit-id: 1d84cf69bee6805dadd0a2d46639d04149c10316
pull/17/head
James South 12 years ago
parent
commit
baf76a4331
  1. 72
      src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
  2. 10
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  3. 4
      src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs

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

@ -47,17 +47,17 @@ namespace ImageProcessor.Web.Caching
/// <see cref="http://stackoverflow.com/questions/115882/how-do-you-deal-with-lots-of-small-files"/> /// <see cref="http://stackoverflow.com/questions/115882/how-do-you-deal-with-lots-of-small-files"/>
/// <see cref="http://stackoverflow.com/questions/1638219/millions-of-small-graphics-files-and-how-to-overcome-slow-file-system-access-on"/> /// <see cref="http://stackoverflow.com/questions/1638219/millions-of-small-graphics-files-and-how-to-overcome-slow-file-system-access-on"/>
/// </remarks> /// </remarks>
private const int MaxFilesCount = 50; private const int MaxFilesCount = 100;
/// <summary> /// <summary>
/// The absolute path to virtual cache path on the server. /// The virtual cache path.
/// </summary> /// </summary>
private static readonly string AbsoluteCachePath = HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath); private static readonly string VirtualCachePath = ImageProcessorConfig.Instance.VirtualCachePath;
/// <summary> /// <summary>
/// The request for the image. /// The absolute path to virtual cache path on the server.
/// </summary> /// </summary>
private readonly HttpRequest request; private static readonly string AbsoluteCachePath = HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath);
/// <summary> /// <summary>
/// The request path for the image. /// The request path for the image.
@ -78,15 +78,22 @@ namespace ImageProcessor.Web.Caching
/// Whether the request is for a remote image. /// Whether the request is for a remote image.
/// </summary> /// </summary>
private readonly bool isRemote; private readonly bool isRemote;
/// <summary>
/// The physical cached path.
/// </summary>
private string physicalCachedPath;
/// <summary>
/// The virtual cached path.
/// </summary>
private string virtualCachedPath;
#endregion #endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DiskCache"/> class. /// Initializes a new instance of the <see cref="DiskCache"/> class.
/// </summary> /// </summary>
/// <param name="request">
/// The request for the image.
/// </param>
/// <param name="requestPath"> /// <param name="requestPath">
/// The request path for the image. /// The request path for the image.
/// </param> /// </param>
@ -99,14 +106,15 @@ namespace ImageProcessor.Web.Caching
/// <param name="isRemote"> /// <param name="isRemote">
/// Whether the request is for a remote image. /// Whether the request is for a remote image.
/// </param> /// </param>
public DiskCache(HttpRequest request, string requestPath, string fullPath, string imageName, bool isRemote) public DiskCache(string requestPath, string fullPath, string imageName, bool isRemote)
{ {
this.request = request;
this.requestPath = requestPath; this.requestPath = requestPath;
this.fullPath = fullPath; this.fullPath = fullPath;
this.imageName = imageName; this.imageName = imageName;
this.isRemote = isRemote; this.isRemote = isRemote;
this.CachedPath = this.GetCachePath();
// Get the physical and virtual paths.
this.GetCachePaths();
} }
#endregion #endregion
@ -114,30 +122,28 @@ namespace ImageProcessor.Web.Caching
/// <summary> /// <summary>
/// Gets the cached path. /// Gets the cached path.
/// </summary> /// </summary>
internal string CachedPath { get; private set; } public string CachedPath
#endregion {
get
{
return this.physicalCachedPath;
}
}
#region Methods
#region Internal
/// <summary> /// <summary>
/// Gets the virtual path to the cached processed image. /// Gets the cached path.
/// </summary> /// </summary>
/// <returns>The virtual path to the cached processed image.</returns> public string VirtualCachedPath
internal string GetVirtualCachedPath()
{ {
string applicationPath = this.request.PhysicalApplicationPath; get
string virtualDir = this.request.ApplicationPath;
virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
if (applicationPath != null)
{ {
return this.CachedPath.Replace(applicationPath, virtualDir).Replace(@"\", "/"); return this.virtualCachedPath;
} }
throw new InvalidOperationException(
"We can only map an absolute back to a relative path if the application path is available.");
} }
#endregion
#region Methods
#region Internal
/// <summary> /// <summary>
/// Adds an image to the cache. /// Adds an image to the cache.
/// </summary> /// </summary>
@ -269,11 +275,9 @@ namespace ImageProcessor.Web.Caching
/// taking the individual characters of the hash to determine their location. /// taking the individual characters of the hash to determine their location.
/// This allows us to store millions of images. /// This allows us to store millions of images.
/// </summary> /// </summary>
/// <returns>The full cached path for the image.</returns>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
private string GetCachePath() private void GetCachePaths()
{ {
string cachedPath = string.Empty;
string streamHash = string.Empty; string streamHash = string.Empty;
if (AbsoluteCachePath != null) if (AbsoluteCachePath != null)
@ -304,23 +308,23 @@ namespace ImageProcessor.Web.Caching
// Use an sha1 hash of the full path including the querystring to create the image name. // Use an sha1 hash of the full path including the querystring to create the image name.
// That name can also be used as a key for the cached image and we should be able to use // That name can also be used as a key for the cached image and we should be able to use
// The characters of that hash as subfolders. // The characters of that hash as sub-folders.
string parsedExtension = ImageHelpers.GetExtension(this.fullPath); string parsedExtension = ImageHelpers.GetExtension(this.fullPath);
string fallbackExtension = this.imageName.Substring(this.imageName.LastIndexOf(".", StringComparison.Ordinal) + 1); string fallbackExtension = this.imageName.Substring(this.imageName.LastIndexOf(".", StringComparison.Ordinal) + 1);
string encryptedName = (streamHash + this.fullPath).ToSHA1Fingerprint(); string encryptedName = (streamHash + this.fullPath).ToSHA1Fingerprint();
// Collision rate of about 1 in 10000 for the folder structure. // Collision rate of about 1 in 10000 for the folder structure.
string pathFromKey = string.Join("\\", encryptedName.ToCharArray().Take(6)); string pathFromKey = string.Join("\\", encryptedName.ToCharArray().Take(6));
string virtualPathFromKey = pathFromKey.Replace(@"\", "/");
string cachedFileName = string.Format( string cachedFileName = string.Format(
"{0}.{1}", "{0}.{1}",
encryptedName, encryptedName,
!string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : fallbackExtension); !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : fallbackExtension);
cachedPath = Path.Combine(AbsoluteCachePath, pathFromKey, cachedFileName); this.physicalCachedPath = Path.Combine(AbsoluteCachePath, pathFromKey, cachedFileName);
this.virtualCachedPath = Path.Combine(VirtualCachePath, virtualPathFromKey, cachedFileName).Replace(@"\", "/");
} }
return cachedPath;
} }
/// <summary> /// <summary>

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

@ -346,14 +346,14 @@ namespace ImageProcessor.Web.HttpModules
} }
// Create a new cache to help process and cache the request. // Create a new cache to help process and cache the request.
DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName, isRemote); DiskCache cache = new DiskCache(requestPath, fullPath, imageName, isRemote);
// Since we are now rewriting the path we need to check again that the current user has access // Since we are now rewriting the path we need to check again that the current user has access
// to the rewritten path. // to the rewritten path.
// Get the user for the current request // Get the user for the current request
// If the user is anonymous or authentication doesn't work for this suffix avoid a NullReferenceException // If the user is anonymous or authentication doesn't work for this suffix avoid a NullReferenceException
// in the UrlAuthorizationModule by creating a generic identity. // in the UrlAuthorizationModule by creating a generic identity.
string virtualCachedPath = cache.GetVirtualCachedPath(); string virtualCachedPath = cache.VirtualCachedPath;
IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);
@ -475,7 +475,7 @@ namespace ImageProcessor.Web.HttpModules
context.Response.AddHeader("Content-Length", "0"); context.Response.AddHeader("Content-Length", "0");
context.Response.StatusCode = (int)HttpStatusCode.NotModified; context.Response.StatusCode = (int)HttpStatusCode.NotModified;
context.Response.SuppressContent = true; context.Response.SuppressContent = true;
context.Response.AddFileDependency(context.Server.MapPath(cache.GetVirtualCachedPath())); context.Response.AddFileDependency(context.Server.MapPath(virtualCachedPath));
this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey]); this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey]);
if (!isRemote) if (!isRemote)
@ -484,10 +484,8 @@ namespace ImageProcessor.Web.HttpModules
} }
} }
string virtualPath = cache.GetVirtualCachedPath();
// The cached file is valid so just rewrite the path. // The cached file is valid so just rewrite the path.
context.RewritePath(virtualPath, false); context.RewritePath(virtualCachedPath, false);
} }
else else
{ {

4
src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs

@ -35,5 +35,5 @@ using ImageProcessor.Web.HttpModules;
// //
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly: AssemblyVersion("3.2.9.0")] [assembly: AssemblyVersion("3.3.0.0")]
[assembly: AssemblyFileVersion("3.2.9.0")] [assembly: AssemblyFileVersion("3.3.0.0")]
Loading…
Cancel
Save