From e59b4b09bee68e1da22d5dfb6fac01c1f69d90dd Mon Sep 17 00:00:00 2001 From: James South Date: Fri, 15 Aug 2014 16:16:30 +0100 Subject: [PATCH] Fixing file dependencies and mime/type Former-commit-id: 1d2dadabad90334cd6425ac7f0256e3f00a897b2 --- .../Helpers/ImageHelpers.cs | 34 +++++++++++-- .../HttpModules/ImageProcessingModule.cs | 51 ++++++++++--------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/ImageProcessor.Web/Helpers/ImageHelpers.cs b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs index f48e8d9d1..e52f5aa3b 100644 --- a/src/ImageProcessor.Web/Helpers/ImageHelpers.cs +++ b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs @@ -10,6 +10,9 @@ namespace ImageProcessor.Web.Helpers { + using System; + using System.Collections.Generic; + using System.Linq; using System.Text; using System.Text.RegularExpressions; using ImageProcessor.Configuration; @@ -23,17 +26,17 @@ namespace ImageProcessor.Web.Helpers /// /// The regex pattern. /// - private static readonly string RegexPattern = BuildRegexPattern(); + private static readonly string ExtensionRegexPattern = BuildExtensionRegexPattern(); /// /// The image format regex. /// - private static readonly Regex FormatRegex = new Regex(@"(\.?)(png8|" + RegexPattern + ")", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); + private static readonly Regex FormatRegex = new Regex(@"(\.?)(png8|" + ExtensionRegexPattern + ")", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); /// /// The image format regex for matching the file format at the end of a string. /// - private static readonly Regex EndFormatRegex = new Regex(@"(\.)" + RegexPattern + "$", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); + private static readonly Regex EndFormatRegex = new Regex(@"(\.)" + ExtensionRegexPattern + "$", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); /// /// Checks a given string to check whether the value contains a valid image extension. @@ -72,13 +75,36 @@ namespace ImageProcessor.Web.Helpers return string.Empty; } + /// + /// Get the correct mime-type for the given string input. + /// + /// + /// The identifier. + /// + /// + /// The matching the correct mime-type. + /// + public static string GetMimeType(string identifier) + { + identifier = GetExtension(identifier).Replace(".", string.Empty); + List formats = ImageProcessorBootstrapper.Instance.SupportedImageFormats.ToList(); + ISupportedImageFormat format = formats.FirstOrDefault(f => f.FileExtensions.Any(e => e.Equals(identifier, StringComparison.InvariantCultureIgnoreCase))); + + if (format != null) + { + return format.MimeType; + } + + return string.Empty; + } + /// /// Builds a regular expression from the type, this allows extensibility. /// /// /// The to match matrix filters. /// - private static string BuildRegexPattern() + private static string BuildExtensionRegexPattern() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("("); diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index 82f82d012..edea79750 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -12,6 +12,7 @@ namespace ImageProcessor.Web.HttpModules { #region Using using System; + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -208,10 +209,10 @@ namespace ImageProcessor.Web.HttpModules if (responseTypeObject != null && dependencyFileObject != null) { string responseType = (string)responseTypeObject; - string dependencyFile = (string)dependencyFileObject; + List dependencyFiles = (List)dependencyFileObject; // Set the headers - this.SetHeaders(context, responseType, dependencyFile); + this.SetHeaders(context, responseType, dependencyFiles); context.Items[CachedResponseTypeKey] = null; context.Items[CachedResponseFileDependency] = null; @@ -352,11 +353,7 @@ namespace ImageProcessor.Web.HttpModules { if (isRemote) { -#if NET45 && !__MonoCS__ using (await Locker.LockAsync(cachedPath)) -#else - using (Locker.Lock(cachedPath)) -#endif { Uri uri = new Uri(requestPath + "?" + urlParameters); RemoteFile remoteFile = new RemoteFile(uri, false); @@ -382,14 +379,15 @@ namespace ImageProcessor.Web.HttpModules .AutoProcess(queryString) .Save(cachedPath); - // Store the response type in the context for later retrieval. - context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; - // Add to the cache. cache.AddImageToCache(cachedPath); // Trim the cache. await cache.TrimCachedFolderAsync(cachedPath); + + // Store the response type and cache dependency in the context for later retrieval. + context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; + context.Items[CachedResponseFileDependency] = new List { cachedPath }; } } } @@ -398,11 +396,7 @@ namespace ImageProcessor.Web.HttpModules } else { -#if NET45 && !__MonoCS__ using (await Locker.LockAsync(cachedPath)) -#else - using (Locker.Lock(cachedPath)) -#endif { // Check to see if the file exists. // ReSharper disable once AssignNullToNotNullAttribute @@ -418,14 +412,15 @@ namespace ImageProcessor.Web.HttpModules .AutoProcess(queryString) .Save(cachedPath); - // Store the response type in the context for later retrieval. - context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; - // Add to the cache. cache.AddImageToCache(cachedPath); // Trim the cache. await cache.TrimCachedFolderAsync(cachedPath); + + // Store the response type and cache dependencies in the context for later retrieval. + context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; + context.Items[CachedResponseFileDependency] = new List { requestPath, cachedPath }; } } } @@ -434,26 +429,32 @@ namespace ImageProcessor.Web.HttpModules // Image is from the cache so the mime-type will need to be set. if (context.Items[CachedResponseTypeKey] == null) { - context.Items[CachedResponseTypeKey] = ImageHelpers.GetExtension(cachedPath).Replace(".", "image/"); - } + string mimetype = ImageHelpers.GetMimeType(cachedPath); - context.Items[CachedResponseFileDependency] = cachedPath; + if (!string.IsNullOrEmpty(mimetype)) + { + context.Items[CachedResponseTypeKey] = mimetype; + } + } string incomingEtag = context.Request.Headers["If" + "-None-Match"]; if (incomingEtag != null && !isNewOrUpdated) { - // Explicitly set the Content-Length header so the client doesn't wait for - // content but keeps the connection open for other requests + // Set the Content-Length header so the client doesn't wait for + // content but keeps the connection open for other requests. context.Response.AddHeader("Content-Length", "0"); context.Response.StatusCode = (int)HttpStatusCode.NotModified; context.Response.SuppressContent = true; - this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], cachedPath); if (!isRemote) { + // Set the headers and quit. + this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], new List { requestPath, cachedPath }); return; } + + this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], new List { cachedPath }); } // The cached file is valid so just rewrite the path. @@ -483,10 +484,10 @@ namespace ImageProcessor.Web.HttpModules /// /// The HTTP MIME type to to send. /// - /// + /// /// The dependency path for the cache dependency. /// - private void SetHeaders(HttpContext context, string responseType, string dependencyPath) + private void SetHeaders(HttpContext context, string responseType, IEnumerable dependencyPaths) { HttpResponse response = context.Response; @@ -501,7 +502,7 @@ namespace ImageProcessor.Web.HttpModules cache.SetCacheability(HttpCacheability.Public); cache.VaryByHeaders["Accept-Encoding"] = true; - context.Response.AddFileDependency(dependencyPath); + context.Response.AddFileDependencies(dependencyPaths.ToArray()); cache.SetLastModifiedFromFileDependencies(); int maxDays = DiskCache.MaxFileCachedDuration;