From e03d784fd20021549561bba21164f10fa55ac6c5 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 19 Feb 2015 14:02:26 +0000 Subject: [PATCH] Fixing redirect and cleanup. Former-commit-id: 32e418b0f8b0b3b5a48dde36cc2f0ca52b8d3713 Former-commit-id: 31ab4e4c9d803625819d2646641c204460f69ed5 --- build/build.xml | 6 +- .../AzureBlobCache.cs | 12 ++- .../Properties/AssemblyInfo.cs | 4 +- .../README.md | 8 +- .../Configuration/Resources/security.config | 1 + .../Helpers/ImageHelpers.cs | 24 ------ src/ImageProcessor.Web/Helpers/RemoteFile.cs | 11 ++- .../HttpModules/ImageProcessingModule.cs | 82 +++++++++++-------- .../Services/RemoteImageService.cs | 5 +- src/ImageProcessor.sln.DotSettings | 1 + src/ImageProcessor/ImageFactory.cs | 6 +- .../Imaging/Formats/FormatBase.cs | 1 - src/TestWebsites/MVC/Global.asax.cs | 18 ++-- src/TestWebsites/MVC/Views/Home/Index.cshtml | 3 +- .../MVC/config/imageprocessor/security.config | 2 + 15 files changed, 94 insertions(+), 90 deletions(-) diff --git a/build/build.xml b/build/build.xml index c2cf5d0bd..eddcb6daa 100644 --- a/build/build.xml +++ b/build/build.xml @@ -13,7 +13,7 @@ ImageProcessor Web - 4.1.5.0 + 4.2.0.0 ..\src\ImageProcessor.Web ImageProcessor.Web.csproj @@ -24,7 +24,7 @@ ImageProcessor Web PostProcessor - 1.0.1.0 + 1.0.2.0 ..\src\ImageProcessor.Web.PostProcessor ImageProcessor.Web.PostProcessor.csproj @@ -35,7 +35,7 @@ ImageProcessor Web.config sample - 2.1.1.0 + 2.2.0.0 ImageProcessor.Web.Config.nuspec diff --git a/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs b/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs index 6bda004f3..a206938f8 100644 --- a/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs +++ b/src/ImageProcessor.Web.AzureBlobCache/AzureBlobCache.cs @@ -17,6 +17,7 @@ namespace ImageProcessor.Web.Caching using System.IO; using System.Linq; using System.Net; + using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; @@ -217,16 +218,16 @@ namespace ImageProcessor.Web.Caching Uri uri = new Uri(this.CachedPath); string path = uri.GetLeftPart(UriPartial.Path).Substring(this.cloudCachedBlobContainer.Uri.ToString().Length + 1); string directory = path.Substring(0, path.LastIndexOf('/')); - string parent = directory.Substring(path.LastIndexOf('/')); + string parent = directory.Substring(0, directory.LastIndexOf('/')); BlobContinuationToken continuationToken = null; - CloudBlobDirectory directoryBlob = this.cloudCachedBlobContainer.GetDirectoryReference(parent); List results = new List(); // Loop through the all the files in a non blocking fashion. do { - BlobResultSegment response = await directoryBlob.ListBlobsSegmentedAsync(continuationToken); + BlobResultSegment response = await this.cloudCachedBlobContainer + .ListBlobsSegmentedAsync(parent, true, BlobListingDetails.Metadata, 5000, continuationToken, null, null); continuationToken = response.ContinuationToken; results.AddRange(response.Results); } @@ -280,7 +281,10 @@ namespace ImageProcessor.Web.Caching } else { - string blobPath = this.CachedPath.Substring(this.cloudSourceBlobContainer.Uri.ToString().Length + 1); + Regex regex = new Regex("^http(s)?://"); + string container = regex.Replace(this.cloudSourceBlobContainer.Uri.ToString(), string.Empty); + string blobPath = regex.Replace(this.RequestPath, string.Empty); + blobPath = blobPath.Replace(container, string.Empty).TrimStart('/'); CloudBlockBlob blockBlob = this.cloudSourceBlobContainer.GetBlockBlobReference(blobPath); if (await blockBlob.ExistsAsync()) diff --git a/src/ImageProcessor.Web.PostProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web.PostProcessor/Properties/AssemblyInfo.cs index d0ffe6879..308ac564f 100644 --- a/src/ImageProcessor.Web.PostProcessor/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor.Web.PostProcessor/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.1.0")] -[assembly: AssemblyVersion("1.0.1.0")] -[assembly: AssemblyFileVersion("1.0.1.0")] +[assembly: AssemblyVersion("1.0.2.0")] +[assembly: AssemblyFileVersion("1.0.2.0")] diff --git a/src/ImageProcessor.Web.PostProcessor/README.md b/src/ImageProcessor.Web.PostProcessor/README.md index 05c331aeb..c91c7eb72 100644 --- a/src/ImageProcessor.Web.PostProcessor/README.md +++ b/src/ImageProcessor.Web.PostProcessor/README.md @@ -1,13 +1,13 @@ #Resource locations ###gifsicle -http://www.lcdf.org/gifsicle/ +[http://www.lcdf.org/gifsicle/](http://www.lcdf.org/gifsicle/) ###jpegtran -http://jpegclub.org/jpegtran/ +[http://jpegclub.org/jpegtran/](http://jpegclub.org/jpegtran/) ###optipng -http://optipng.sourceforge.net/ +[http://optipng.sourceforge.net/](http://optipng.sourceforge.net/) ###pngout -http://advsys.net/ken/utils.htm \ No newline at end of file +[http://advsys.net/ken/utils.htm](http://advsys.net/ken/utils.htm) \ No newline at end of file diff --git a/src/ImageProcessor.Web/Configuration/Resources/security.config b/src/ImageProcessor.Web/Configuration/Resources/security.config index 86e92d567..1160ce63b 100644 --- a/src/ImageProcessor.Web/Configuration/Resources/security.config +++ b/src/ImageProcessor.Web/Configuration/Resources/security.config @@ -5,6 +5,7 @@ + diff --git a/src/ImageProcessor.Web/Helpers/ImageHelpers.cs b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs index 22d73d537..d53adf88b 100644 --- a/src/ImageProcessor.Web/Helpers/ImageHelpers.cs +++ b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs @@ -104,30 +104,6 @@ namespace ImageProcessor.Web.Helpers return string.Empty; } - /// - /// Get the correct mime-type for the given string input. - /// - /// - /// The path to the cached image. - /// - /// - /// The matching the correct mime-type. - /// - public static string GetMimeType(string path) - { - using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false)) - { - ISupportedImageFormat format = FormatUtilities.GetFormat(file); - - if (format != null) - { - return format.MimeType; - } - } - - return string.Empty; - } - /// /// Builds a regular expression from the type, this allows extensibility. /// diff --git a/src/ImageProcessor.Web/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/Helpers/RemoteFile.cs index caff6afe3..cf2950c1d 100644 --- a/src/ImageProcessor.Web/Helpers/RemoteFile.cs +++ b/src/ImageProcessor.Web/Helpers/RemoteFile.cs @@ -173,16 +173,20 @@ namespace ImageProcessor.Web.Helpers /// internal async Task GetWebResponseAsync() { - WebResponse response; + WebResponse response = null; try { response = await this.GetWebRequest().GetResponseAsync(); } catch (WebException ex) { - if (ex.Status == WebExceptionStatus.NameResolutionFailure) + if (response != null) { - throw new HttpException(404, "No image exists at " + Uri); + HttpWebResponse errorResponse = (HttpWebResponse)ex.Response; + if (errorResponse.StatusCode == HttpStatusCode.NotFound) + { + throw new HttpException(404, "No image exists at " + this.Uri); + } } throw; @@ -217,7 +221,6 @@ namespace ImageProcessor.Web.Helpers #endregion #region Private - /// /// Creates the WebRequest object used internally for this RemoteFile instance. /// diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index d78bbc485..ae07b8e63 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -148,7 +148,7 @@ namespace ImageProcessor.Web.HttpModules context.AddOnPostAuthorizeRequestAsync(postAuthorizeHelper.BeginEventHandler, postAuthorizeHelper.EndEventHandler); EventHandlerTaskAsyncHelper postProcessHelper = new EventHandlerTaskAsyncHelper(this.PostProcessImage); - context.AddOnPostRequestHandlerExecuteAsync(postProcessHelper.BeginEventHandler, postProcessHelper.EndEventHandler); + context.AddOnEndRequestAsync(postProcessHelper.BeginEventHandler, postProcessHelper.EndEventHandler); context.PreSendRequestHeaders += this.ContextPreSendRequestHeaders; } @@ -231,11 +231,11 @@ namespace ImageProcessor.Web.HttpModules if (cachedPathObject != null) { - string cachedPath = cachedPathObject.ToString(); - // Trim the cache. await this.imageCache.TrimCacheAsync(); + string cachedPath = cachedPathObject.ToString(); + // Fire the post processing event. EventHandler handler = OnPostProcessing; if (handler != null) @@ -300,6 +300,7 @@ namespace ImageProcessor.Web.HttpModules string queryString = string.Empty; string urlParameters = string.Empty; + // Legacy support. I'd like to remove this asap. if (hasMultiParams) { // We need to split the querystring to get the actual values we want. @@ -338,7 +339,13 @@ namespace ImageProcessor.Web.HttpModules } else { - requestPath = HttpUtility.UrlDecode(request.QueryString.ToString()); + // Parse any protocol values from settings. + string protocol = currentService.Settings["Protocol"] != null + ? currentService.Settings["Protocol"] + "://" + : string.Empty; + + requestPath = protocol + request.Path.Replace(currentService.Prefix, string.Empty).TrimStart('/'); + queryString = HttpUtility.UrlDecode(request.QueryString.ToString()); } } @@ -359,6 +366,7 @@ namespace ImageProcessor.Web.HttpModules string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString); object resourcePath; + // More legacy support code. if (hasMultiParams) { resourcePath = string.IsNullOrWhiteSpace(urlParameters) @@ -394,50 +402,55 @@ namespace ImageProcessor.Web.HttpModules { byte[] imageBuffer = await currentService.GetImage(resourcePath); - using (MemoryStream memoryStream = new MemoryStream(imageBuffer)) + using (MemoryStream inStream = new MemoryStream(imageBuffer)) { - // Reset the position of the stream to ensure we're reading the correct part. - memoryStream.Position = 0; - // Process the Image - imageFactory.Load(memoryStream).AutoProcess(queryString).Save(memoryStream); - memoryStream.Position = 0; + using (MemoryStream outStream = new MemoryStream()) + { + imageFactory.Load(inStream).AutoProcess(queryString).Save(outStream); - // Add to the cache. - await this.imageCache.AddImageToCacheAsync(memoryStream, imageFactory.CurrentImageFormat.MimeType); + // Add to the cache. + await this.imageCache.AddImageToCacheAsync(outStream, imageFactory.CurrentImageFormat.MimeType); + } + } - // Store the cached path, response type, and cache dependency in the context for later retrieval. - context.Items[CachedPathKey] = cachedPath; - context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; - bool isFileCached = new Uri(cachedPath).IsFile; + // Store the cached path, response type, and cache dependency in the context for later retrieval. + context.Items[CachedPathKey] = cachedPath; + context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; + bool isFileCached = new Uri(cachedPath).IsFile; - if (isFileLocal) + if (isFileLocal) + { + if (isFileCached) { - if (isFileCached) - { - // Some services might only provide filename so we can't monitor for the browser. - context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath - ? new List { cachedPath } - : new List { requestPath, cachedPath }; - } - else - { - context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath - ? null - : new List { requestPath }; - } + // Some services might only provide filename so we can't monitor for the browser. + context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath + ? new List { cachedPath } + : new List { requestPath, cachedPath }; } - else if (isFileCached) + else { - context.Items[CachedResponseFileDependency] = new List { cachedPath }; + context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath + ? null + : new List { requestPath }; } } + else if (isFileCached) + { + context.Items[CachedResponseFileDependency] = new List { cachedPath }; + } } } } // The cached file is valid so just rewrite the path. this.imageCache.RewritePath(context); + + // Redirect if not a locally store file. + if (!new Uri(cachedPath).IsFile) + { + context.ApplicationInstance.CompleteRequest(); + } } } @@ -557,11 +570,11 @@ namespace ImageProcessor.Web.HttpModules IImageService imageService = null; IList services = ImageProcessorConfiguration.Instance.ImageServices; - string path = request.Path; + string path = request.Path.TrimStart('/'); foreach (IImageService service in services) { string key = service.Prefix; - if (!string.IsNullOrWhiteSpace(key) && path.EndsWith(key, StringComparison.InvariantCultureIgnoreCase)) + if (!string.IsNullOrWhiteSpace(key) && path.StartsWith(key, StringComparison.InvariantCultureIgnoreCase)) { imageService = service; } @@ -575,7 +588,6 @@ namespace ImageProcessor.Web.HttpModules // Return the file based service return services.FirstOrDefault(s => string.IsNullOrWhiteSpace(s.Prefix) && s.IsValidRequest(path)); } - #endregion } } \ No newline at end of file diff --git a/src/ImageProcessor.Web/Services/RemoteImageService.cs b/src/ImageProcessor.Web/Services/RemoteImageService.cs index a8a46319a..36888a6f0 100644 --- a/src/ImageProcessor.Web/Services/RemoteImageService.cs +++ b/src/ImageProcessor.Web/Services/RemoteImageService.cs @@ -37,7 +37,8 @@ namespace ImageProcessor.Web.Services this.Settings = new Dictionary { { "MaxBytes", "4194304" }, - { "Timeout", "30000" } + { "Timeout", "30000" }, + { "Protocol", "http" } }; this.WhiteList = new Uri[] { }; @@ -105,7 +106,7 @@ namespace ImageProcessor.Web.Services { if (!uri.IsAbsoluteUri) { - Uri rebaseUri = new Uri("http://" + uri.ToString().TrimStart(new[] { '.', '/' })); + Uri rebaseUri = new Uri("http://" + uri.ToString().TrimStart('.', '/')); validUrl = upper.StartsWith(rebaseUri.Host.ToUpperInvariant()) || upper.EndsWith(rebaseUri.Host.ToUpperInvariant()); } else diff --git a/src/ImageProcessor.sln.DotSettings b/src/ImageProcessor.sln.DotSettings index 0395ee1ba..d8fb7528a 100644 --- a/src/ImageProcessor.sln.DotSettings +++ b/src/ImageProcessor.sln.DotSettings @@ -18,5 +18,6 @@ REF RGB RGBA + SHA SRGB SS \ No newline at end of file diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 0d07129e3..a473d8b63 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -139,6 +139,9 @@ namespace ImageProcessor /// public ImageFactory Load(Stream stream) { + // Reset the position of the stream to ensure we're reading the correct part. + stream.Position = 0; + ISupportedImageFormat format = FormatUtilities.GetFormat(stream); if (format == null) @@ -1070,8 +1073,9 @@ namespace ImageProcessor if (this.ShouldProcess) { // Allow the same stream to be used as for input. - stream.Position = 0; + stream.SetLength(0); this.Image = this.CurrentImageFormat.Save(stream, this.Image); + stream.Position = 0; } return this; diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs index c74134670..cfad02046 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -108,7 +108,6 @@ namespace ImageProcessor.Imaging.Formats public virtual Image Save(Stream stream, Image image) { image.Save(stream, this.ImageFormat); - stream.Position = 0; return image; } diff --git a/src/TestWebsites/MVC/Global.asax.cs b/src/TestWebsites/MVC/Global.asax.cs index 11a3d306a..ef908f1ba 100644 --- a/src/TestWebsites/MVC/Global.asax.cs +++ b/src/TestWebsites/MVC/Global.asax.cs @@ -28,17 +28,17 @@ namespace Test_Website_NET45 RouteConfig.RegisterRoutes(RouteTable.Routes); // Test the post processing event. - ImageProcessingModule.OnPostProcessing += (sender, args) => Debug.WriteLine(args.CachedImagePath); + //ImageProcessingModule.OnPostProcessing += (sender, args) => Debug.WriteLine(args.CachedImagePath); - ImageProcessingModule.OnProcessQuerystring += (sender, args) => - { - if (!args.RawUrl.Contains("penguins")) - { - return args.Querystring += "watermark=protected&color=fff&fontsize=36&fontopacity=70textshadow=true&fontfamily=arial"; - } + //ImageProcessingModule.OnProcessQuerystring += (sender, args) => + // { + // if (!args.RawUrl.Contains("penguins")) + // { + // return args.Querystring += "watermark=protected&color=fff&fontsize=36&fontopacity=70textshadow=true&fontfamily=arial"; + // } - return args.Querystring; - }; + // return args.Querystring; + // }; } private async void WritePath(object sender, PostProcessingEventArgs e) diff --git a/src/TestWebsites/MVC/Views/Home/Index.cshtml b/src/TestWebsites/MVC/Views/Home/Index.cshtml index f010a23d9..4fed9c4b5 100644 --- a/src/TestWebsites/MVC/Views/Home/Index.cshtml +++ b/src/TestWebsites/MVC/Views/Home/Index.cshtml @@ -7,7 +7,8 @@

Resized

- + + @*

Foreign language test.

diff --git a/src/TestWebsites/MVC/config/imageprocessor/security.config b/src/TestWebsites/MVC/config/imageprocessor/security.config index dc9d8fe95..eb61ad133 100644 --- a/src/TestWebsites/MVC/config/imageprocessor/security.config +++ b/src/TestWebsites/MVC/config/imageprocessor/security.config @@ -6,8 +6,10 @@ + +