From bed5b003be5b6153121c32aef64891791e5329fd Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 30 Nov 2013 17:39:53 +0000 Subject: [PATCH] Adding extension-less remote url parsing. Former-commit-id: e84842820b2ef0a43ea878f329e17c44f17a3b9e --- .gitignore | 4 +-- .../NET45/Config/ImageProcessorConfig.cs | 18 +++++----- .../NET45/Config/ImageSecuritySection.cs | 21 ++++++++---- .../NET45/Helpers/RemoteFile.cs | 17 ++++++---- .../HttpModules/ImageProcessingModule.cs | 32 ++++++++---------- src/TestWebsites/NET4/Views/Home/Index.cshtml | 1 + src/TestWebsites/NET4/Web.config | 4 ++- .../5/2/51610039b57900ffa3b6444378a9c2a2.jpg | 3 -- src/TestWebsites/NET4/cache/cache.db | Bin 35840 -> 0 bytes .../Views/Home/Index.cshtml | 1 + .../NET45/Test_Website_NET45/Web.config | 1 + src/packages/repositories.config | 6 ++++ 12 files changed, 64 insertions(+), 44 deletions(-) delete mode 100644 src/TestWebsites/NET4/cache/5/2/51610039b57900ffa3b6444378a9c2a2.jpg delete mode 100644 src/TestWebsites/NET4/cache/cache.db create mode 100644 src/packages/repositories.config diff --git a/.gitignore b/.gitignore index a39e0d3a0..7ee5bda06 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,7 @@ local.properties **/*.dotCover ## TODO: If you have NuGet Package Restore enabled, uncomment this -src/packages/ +##**/packages # Visual C++ cache files ipch/ @@ -165,4 +165,4 @@ pip-log.txt # cached images -**/cache/* \ No newline at end of file +##**/cache \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs b/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs index 76082ab7d..141538767 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs @@ -1,9 +1,13 @@ -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. // -// ----------------------------------------------------------------------- +// +// Encapsulates methods to allow the retrieval of ImageProcessor settings. +// +// +// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Config { @@ -16,8 +20,6 @@ namespace ImageProcessor.Web.Config using System.Text; using ImageProcessor.Processors; - using ImageProcessor.Web.Helpers; - #endregion /// @@ -111,7 +113,7 @@ namespace ImageProcessor.Web.Config #region Security /// - /// Gets a list of whitelisted url[s] that images can be downloaded from. + /// Gets a list of white listed url[s] that images can be downloaded from. /// public Uri[] RemoteFileWhiteList { @@ -122,7 +124,7 @@ namespace ImageProcessor.Web.Config } /// - /// + /// Gets a list of image extensions for url[s] with no extension. /// public ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions { diff --git a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs b/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs index 16ec62db7..dac3dd84e 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs @@ -1,9 +1,12 @@ -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. // -// ----------------------------------------------------------------------- +// +// Represents an image security section within a configuration file. +// +// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Config { @@ -168,9 +171,9 @@ namespace ImageProcessor.Web.Config public class SafeUrl : ConfigurationElement { /// - /// Gets or sets the url of the whitelisted file. + /// Gets or sets the url of the white listed file. /// - /// The url of the whitelisted file. + /// The url of the white listed file. [ConfigurationProperty("url", DefaultValue = "", IsRequired = true)] public Uri Url { @@ -179,6 +182,9 @@ namespace ImageProcessor.Web.Config set { this["url"] = value; } } + /// + /// Gets or sets a value indicating whether the white listed url is extension-less. + /// [ConfigurationProperty("extensionLess", DefaultValue = false, IsRequired = false)] public bool ExtensionLess { @@ -187,6 +193,9 @@ namespace ImageProcessor.Web.Config set { this["extensionLess"] = value; } } + /// + /// Gets or sets the image format for the extension-less url. + /// [ConfigurationProperty("imageFormat", DefaultValue = "", IsRequired = false)] public string ImageFormat { diff --git a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs index bd6cdee9c..13ce1c637 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs @@ -1,9 +1,12 @@ -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. // -// ----------------------------------------------------------------------- +// +// Encapsulates methods used to download files from a website address. +// +// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Helpers { @@ -46,12 +49,12 @@ namespace ImageProcessor.Web.Helpers /// /// The white-list of url[s] from which to download remote files. /// - private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList; + public static readonly ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions = ImageProcessorConfig.Instance.RemoteFileWhiteListExtensions; /// /// The white-list of url[s] from which to download remote files. /// - public static readonly ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions = ImageProcessorConfig.Instance.RemoteFileWhiteListExtensions; + private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList; /// /// The length of time, in milliseconds, that a remote file download attempt can last before timing out. @@ -177,6 +180,7 @@ namespace ImageProcessor.Web.Helpers if (value < 0) { + // ReSharper disable once NotResolvedInText throw new ArgumentOutOfRangeException("TimeoutLength"); } @@ -212,6 +216,7 @@ namespace ImageProcessor.Web.Helpers if (value < 0) { + // ReSharper disable once NotResolvedInText throw new ArgumentOutOfRangeException("MaxDownloadSize"); } diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index eaeaee427..e90b47221 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -8,16 +8,13 @@ // // -------------------------------------------------------------------------------------------------------------------- -using System.Linq; -using System.Security.Cryptography; -using System.Security.Policy; -using System.Text; - namespace ImageProcessor.Web.HttpModules { #region Using using System; + using System.Diagnostics.CodeAnalysis; using System.IO; + using System.Linq; using System.Net; using System.Reflection; using System.Security; @@ -176,6 +173,7 @@ namespace ImageProcessor.Web.HttpModules /// /// The . /// + [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1122:UseStringEmptyForEmptyStrings", Justification = "Reviewed. Suppression is OK here.")] private async Task ProcessImageAsync(HttpContext context) { HttpRequest request = context.Request; @@ -206,6 +204,7 @@ namespace ImageProcessor.Web.HttpModules requestPath = paths[0]; + // Handle extension-less urls. if (paths.Count() > 2) { queryString = paths[2]; @@ -217,13 +216,12 @@ namespace ImageProcessor.Web.HttpModules } validExtensionLessUrl = RemoteFile.RemoteFileWhiteListExtensions.Any( - x => x.ExtensionLess == true && requestPath.StartsWith(x.Url.AbsoluteUri)); + x => x.ExtensionLess && requestPath.StartsWith(x.Url.AbsoluteUri)); if (validExtensionLessUrl) { extensionLessExtension = RemoteFile.RemoteFileWhiteListExtensions.First( - x => x.ExtensionLess == true && requestPath.StartsWith(x.Url.AbsoluteUri)).ImageFormat; - + x => x.ExtensionLess && requestPath.StartsWith(x.Url.AbsoluteUri)).ImageFormat; } } } @@ -234,7 +232,7 @@ namespace ImageProcessor.Web.HttpModules } // Only process requests that pass our sanitizing filter. - if ((ImageUtils.IsValidImageExtension(requestPath) || validExtensionLessUrl ) && !string.IsNullOrWhiteSpace(queryString)) + if ((ImageUtils.IsValidImageExtension(requestPath) || validExtensionLessUrl) && !string.IsNullOrWhiteSpace(queryString)) { string fullPath = string.Format("{0}?{1}", requestPath, queryString); string imageName = Path.GetFileName(requestPath); @@ -245,14 +243,11 @@ namespace ImageProcessor.Web.HttpModules if (!string.IsNullOrWhiteSpace(urlParameters)) { - //TODO: Add hash for querystring parameters - HashAlgorithm algorithm = MD5.Create(); // SHA1.Create() - var hashCode = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlParameters)); - StringBuilder sb = new StringBuilder(); - foreach (byte b in hashCode) - sb.Append(b.ToString("X2")); - imageName += sb.ToString(); - fullPath += sb.ToString(); + string hashedUrlParameters = urlParameters.ToMD5Fingerprint(); + + // TODO: Add hash for querystring parameters. + imageName += hashedUrlParameters; + fullPath += hashedUrlParameters; } imageName += "." + extensionLessExtension; @@ -360,7 +355,7 @@ namespace ImageProcessor.Web.HttpModules context.Response.AddHeader("Content-Length", "0"); context.Response.StatusCode = (int)HttpStatusCode.NotModified; context.Response.SuppressContent = true; - + context.Response.AddFileDependency(context.Server.MapPath(cache.GetVirtualCachedPath())); this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey]); if (!isRemote) @@ -400,6 +395,7 @@ namespace ImageProcessor.Web.HttpModules HttpCachePolicy cache = response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.VaryByHeaders["Accept-Encoding"] = true; + cache.SetLastModifiedFromFileDependencies(); int maxDays = DiskCache.MaxFileCachedDuration; diff --git a/src/TestWebsites/NET4/Views/Home/Index.cshtml b/src/TestWebsites/NET4/Views/Home/Index.cshtml index 2efa21511..c1da5a373 100644 --- a/src/TestWebsites/NET4/Views/Home/Index.cshtml +++ b/src/TestWebsites/NET4/Views/Home/Index.cshtml @@ -100,6 +100,7 @@

Remote

@**@ + diff --git a/src/TestWebsites/NET4/Web.config b/src/TestWebsites/NET4/Web.config index 1335fd3b2..fbc37ab45 100644 --- a/src/TestWebsites/NET4/Web.config +++ b/src/TestWebsites/NET4/Web.config @@ -71,7 +71,9 @@ - + + + diff --git a/src/TestWebsites/NET4/cache/5/2/51610039b57900ffa3b6444378a9c2a2.jpg b/src/TestWebsites/NET4/cache/5/2/51610039b57900ffa3b6444378a9c2a2.jpg deleted file mode 100644 index d9cc15a91..000000000 --- a/src/TestWebsites/NET4/cache/5/2/51610039b57900ffa3b6444378a9c2a2.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:66b9e229f5cfd84fa563155485ba61cbe0679908d131f3e5ad60817ccc17a52d -size 27264 diff --git a/src/TestWebsites/NET4/cache/cache.db b/src/TestWebsites/NET4/cache/cache.db deleted file mode 100644 index c1e11601ebaf1488e90cd881e0f36c93dc88e57e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35840 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 @**@ + diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.config b/src/TestWebsites/NET45/Test_Website_NET45/Web.config index c2a70cb67..1a9c7f035 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Web.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/Web.config @@ -67,6 +67,7 @@ + diff --git a/src/packages/repositories.config b/src/packages/repositories.config new file mode 100644 index 000000000..eefad5d30 --- /dev/null +++ b/src/packages/repositories.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file