diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
index 911441ebd..7e30aaf9a 100644
--- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
+++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs
@@ -11,6 +11,7 @@ namespace ImageProcessor.Web.Caching
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+ using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -19,6 +20,7 @@ namespace ImageProcessor.Web.Caching
using System.Web;
using System.Web.Hosting;
using ImageProcessor.Helpers.Extensions;
+ using ImageProcessor.Imaging;
using ImageProcessor.Web.Config;
using ImageProcessor.Web.Helpers;
#endregion
@@ -429,7 +431,7 @@ namespace ImageProcessor.Web.Caching
// Use an md5 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
// The first character of that hash as a subfolder.
- string parsedExtension = this.ParseExtension(this.fullPath);
+ string parsedExtension = ImageUtils.GetExtension(this.fullPath);
string fallbackExtension = this.imageName.Substring(this.imageName.LastIndexOf(".", StringComparison.Ordinal) + 1);
string encryptedName = this.fullPath.ToMD5Fingerprint();
string firstSubpath = encryptedName.Substring(0, 1);
@@ -438,7 +440,7 @@ namespace ImageProcessor.Web.Caching
string cachedFileName = string.Format(
"{0}.{1}",
encryptedName,
- !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension : fallbackExtension);
+ !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : fallbackExtension);
cachedPath = Path.Combine(AbsoluteCachePath, firstSubpath, secondSubpath, cachedFileName);
}
@@ -446,22 +448,6 @@ namespace ImageProcessor.Web.Caching
return cachedPath;
}
- ///
- /// Returns the correct file extension for the given string input
- ///
- ///
- /// The string to parse.
- ///
- ///
- /// The correct file extension for the given string input if it can find one; otherwise an empty string.
- ///
- private string ParseExtension(string input)
- {
- Match match = FormatRegex.Match(input);
-
- return match.Success ? match.Value : string.Empty;
- }
-
///
/// The rough date time compare.
///
diff --git a/src/ImageProcessor.Web/NET45/Caching/SQLContext.cs b/src/ImageProcessor.Web/NET45/Caching/SQLContext.cs
index 4d2bb3983..fe1da938d 100644
--- a/src/ImageProcessor.Web/NET45/Caching/SQLContext.cs
+++ b/src/ImageProcessor.Web/NET45/Caching/SQLContext.cs
@@ -73,9 +73,9 @@ namespace ImageProcessor.Web.Caching
}
}
}
- catch (Exception ex)
+ catch
{
- throw ex;
+ throw;
}
}
diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
index 74e5df1e9..2cd0d3b1f 100644
--- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
+++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
@@ -12,10 +12,15 @@ namespace ImageProcessor.Web.HttpModules
using System.IO;
using System.Net;
using System.Reflection;
+ using System.Security;
+ using System.Security.Permissions;
+ using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
+ using System.Web.Security;
+
using ImageProcessor.Helpers.Extensions;
using ImageProcessor.Imaging;
using ImageProcessor.Web.Caching;
@@ -74,16 +79,15 @@ namespace ImageProcessor.Web.HttpModules
#if NET45
- EventHandlerTaskAsyncHelper wrapper = new EventHandlerTaskAsyncHelper(this.ContextBeginRequest);
- context.AddOnBeginRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler);
+ EventHandlerTaskAsyncHelper wrapper = new EventHandlerTaskAsyncHelper(this.PostAuthorizeRequest);
+ context.AddOnPostAuthorizeRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler);
#else
- context.BeginRequest += this.ContextBeginRequest;
+ context.PostAuthorizeRequest += this.PostAuthorizeRequest;
#endif
-
context.PreSendRequestHeaders += this.ContextPreSendRequestHeaders;
}
@@ -99,7 +103,7 @@ namespace ImageProcessor.Web.HttpModules
#if NET45
///
- /// Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET responds to a request.
+ /// Occurs when the user for the current request has been authorized.
///
///
/// The source of the event.
@@ -110,7 +114,7 @@ namespace ImageProcessor.Web.HttpModules
///
/// The .
///
- private Task ContextBeginRequest(object sender, EventArgs e)
+ private Task PostAuthorizeRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
return this.ProcessImageAsync(context);
@@ -119,11 +123,11 @@ namespace ImageProcessor.Web.HttpModules
#else
///
- /// Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET responds to a request.
+ /// Occurs when the user for the current request has been authorized.
///
/// The source of the event.
/// An EventArgs that contains the event data.
- private async void ContextBeginRequest(object sender, EventArgs e)
+ private async void PostAuthorizeRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
await this.ProcessImageAsync(context);
@@ -211,73 +215,103 @@ namespace ImageProcessor.Web.HttpModules
// Create a new cache to help process and cache the request.
DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName, isRemote);
- // Is the file new or updated?
- bool isNewOrUpdated = await cache.IsNewOrUpdatedFileAsync();
+ // Since we are now rewriting the path we need to check again that the current user has access
+ // to the rewritten path.
+ // Get the user for the current request
+ // If the user is anonymous or authentication doesn't work for this suffix avoid a NullReferenceException
+ // in the UrlAuthorizationModule by creating a generic identity.
+ string virtualCachedPath = cache.GetVirtualCachedPath();
+
+ IPrincipal user = context.User
+ ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);
+
+ // Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal?
+ PermissionSet permission = new PermissionSet(PermissionState.None);
+ permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted));
+ bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet);
+
+ bool isAllowed = true;
- // Only process if the file has been updated.
- if (isNewOrUpdated)
+ // Run the rewritten path past the auth system again, using the result as the default "AllowAccess" value
+ if (hasPermission && !context.SkipAuthorization)
{
- // Process the image.
- using (ImageFactory imageFactory = new ImageFactory())
+ isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET");
+ }
+
+ if (isAllowed)
+ {
+ // Is the file new or updated?
+ bool isNewOrUpdated = await cache.IsNewOrUpdatedFileAsync();
+
+ // Only process if the file has been updated.
+ if (isNewOrUpdated)
{
- if (isRemote)
+ // Process the image.
+ using (ImageFactory imageFactory = new ImageFactory())
{
- Uri uri = new Uri(requestPath);
+ if (isRemote)
+ {
+ Uri uri = new Uri(requestPath);
- RemoteFile remoteFile = new RemoteFile(uri, false);
+ RemoteFile remoteFile = new RemoteFile(uri, false);
- // Prevent response blocking.
- WebResponse webResponse = await remoteFile.GetWebResponseAsync().ConfigureAwait(false);
+ // Prevent response blocking.
+ WebResponse webResponse = await remoteFile.GetWebResponseAsync().ConfigureAwait(false);
- using (MemoryStream memoryStream = new MemoryStream())
- {
- using (WebResponse response = webResponse)
+ using (MemoryStream memoryStream = new MemoryStream())
{
- using (Stream responseStream = response.GetResponseStream())
+ using (WebResponse response = webResponse)
{
- if (responseStream != null)
+ using (Stream responseStream = response.GetResponseStream())
{
- // Trim the cache.
- await cache.TrimCachedFoldersAsync();
+ if (responseStream != null)
+ {
+ // Trim the cache.
+ await cache.TrimCachedFoldersAsync();
- responseStream.CopyTo(memoryStream);
+ responseStream.CopyTo(memoryStream);
- imageFactory.Load(memoryStream)
- .AddQueryString(queryString)
- .Format(ImageUtils.GetImageFormat(imageName))
- .AutoProcess().Save(cache.CachedPath);
+ imageFactory.Load(memoryStream)
+ .AddQueryString(queryString)
+ .Format(ImageUtils.GetImageFormat(imageName))
+ .AutoProcess().Save(cache.CachedPath);
- // Ensure that the LastWriteTime property of the source and cached file match.
- DateTime dateTime = await cache.SetCachedLastWriteTimeAsync();
+ // Ensure that the LastWriteTime property of the source and cached file match.
+ DateTime dateTime = await cache.SetCachedLastWriteTimeAsync();
- // Add to the cache.
- await cache.AddImageToCacheAsync(dateTime);
+ // Add to the cache.
+ await cache.AddImageToCacheAsync(dateTime);
+ }
}
}
}
}
- }
- else
- {
- // Trim the cache.
- await cache.TrimCachedFoldersAsync();
+ else
+ {
+ // Trim the cache.
+ await cache.TrimCachedFoldersAsync();
- imageFactory.Load(fullPath).AutoProcess().Save(cache.CachedPath);
+ imageFactory.Load(fullPath).AutoProcess().Save(cache.CachedPath);
- // Ensure that the LastWriteTime property of the source and cached file match.
- DateTime dateTime = await cache.SetCachedLastWriteTimeAsync();
+ // Ensure that the LastWriteTime property of the source and cached file match.
+ DateTime dateTime = await cache.SetCachedLastWriteTimeAsync();
- // Add to the cache.
- await cache.AddImageToCacheAsync(dateTime);
+ // Add to the cache.
+ await cache.AddImageToCacheAsync(dateTime);
+ }
}
}
- }
- // Store the response type in the context for later retrieval.
- context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(fullPath).ToDescription();
+ // Store the response type in the context for later retrieval.
+ context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(fullPath).ToDescription();
- // The cached file is valid so just rewrite the path.
- context.RewritePath(cache.GetVirtualCachedPath(), false);
+ // The cached file is valid so just rewrite the path.
+ context.RewritePath(cache.GetVirtualCachedPath(), false);
+ }
+ else
+ {
+ throw new HttpException(403, "Access denied");
+ }
}
}
diff --git a/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs
index 210cf2a6c..475842401 100644
--- a/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs
@@ -31,5 +31,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("2.3.0.1")]
-[assembly: AssemblyFileVersion("2.3.0.1")]
+[assembly: AssemblyVersion("2.3.0.2")]
+[assembly: AssemblyFileVersion("2.3.0.2")]
diff --git a/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs b/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs
index 47bd57bd4..6b3c1a5be 100644
--- a/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs
+++ b/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs
@@ -8,9 +8,8 @@
namespace ImageProcessor.Helpers.Extensions
{
#region Using
- using System.Diagnostics.Contracts;
+ using System;
using System.Globalization;
- using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
@@ -116,7 +115,10 @@ namespace ImageProcessor.Helpers.Extensions
/// An array of integers scraped from the String.
public static int[] ToPositiveIntegerArray(this string expression)
{
- Contract.Requires(!string.IsNullOrWhiteSpace(expression));
+ if (string.IsNullOrWhiteSpace(expression))
+ {
+ throw new ArgumentNullException("expression");
+ }
Regex regex = new Regex(@"\d+", RegexOptions.Compiled);
@@ -144,33 +146,9 @@ namespace ImageProcessor.Helpers.Extensions
/// True if the given string is a valid virtual path name
public static bool IsValidVirtualPathName(this string expression)
{
- // Check the start of the string.
- if (expression.StartsWith("~/"))
- {
- // Trim the first two characters and test the path.
- expression = expression.Substring(2);
- return expression.IsValidPathName();
- }
-
- return false;
- }
-
- ///
- /// Checks the string to see whether the value is a valid path name.
- ///
- ///
- /// For an explanation
- ///
- ///
- /// The String instance that this method extends.
- /// True if the given string is a valid path name
- public static bool IsValidPathName(this string expression)
- {
- // Create a regex of invalid characters and test it.
- string invalidPathNameChars = new string(Path.GetInvalidFileNameChars());
- Regex regFixPathName = new Regex("[" + Regex.Escape(invalidPathNameChars) + "]");
+ Uri uri;
- return !regFixPathName.IsMatch(expression);
+ return Uri.TryCreate(expression, UriKind.Relative, out uri) && uri.IsWellFormedOriginalString();
}
#endregion
}
diff --git a/src/ImageProcessor/Imaging/ImageUtils.cs b/src/ImageProcessor/Imaging/ImageUtils.cs
index fdfb0ca83..f8e69233c 100644
--- a/src/ImageProcessor/Imaging/ImageUtils.cs
+++ b/src/ImageProcessor/Imaging/ImageUtils.cs
@@ -17,7 +17,6 @@ namespace ImageProcessor.Imaging
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
- using System.Threading.Tasks;
#endregion
///
@@ -28,7 +27,7 @@ namespace ImageProcessor.Imaging
///
/// The image format regex.
///
- private static readonly Regex FormatRegex = new Regex(@"(\.?)(j(pg|peg)|bmp|png|gif|ti(f|ff))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
+ private static readonly Regex FormatRegex = new Regex(@"(\.?)(j(pg|peg)|bmp|png|gif|ti(f|ff))", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
///
/// Returns the correct response type based on the given request path.
@@ -41,25 +40,27 @@ namespace ImageProcessor.Imaging
///
public static ResponseType GetResponseType(string request)
{
- foreach (Match match in FormatRegex.Matches(request))
+ Match match = FormatRegex.Matches(request)[0];
+
+ switch (match.Value.ToUpperInvariant())
{
- switch (match.Value.ToUpperInvariant())
- {
- case "PNG":
- return ResponseType.Png;
- case "BMP":
- return ResponseType.Bmp;
- case "GIF":
- return ResponseType.Gif;
- case "TIF":
- case "TIFF":
- return ResponseType.Tiff;
- default:
- return ResponseType.Jpeg;
- }
+ case "PNG":
+ case ".PNG":
+ return ResponseType.Png;
+ case "BMP":
+ case ".BMP":
+ return ResponseType.Bmp;
+ case "GIF":
+ case ".GIF":
+ return ResponseType.Gif;
+ case "TIF":
+ case "TIFF":
+ case ".TIF":
+ case ".TIFF":
+ return ResponseType.Tiff;
+ default:
+ return ResponseType.Jpeg;
}
-
- return ResponseType.Jpeg;
}
///
@@ -91,7 +92,7 @@ namespace ImageProcessor.Imaging
}
}
- // TODO: Show custom exception??
+ // TODO: Show custom exception?
return null;
}
@@ -115,7 +116,6 @@ namespace ImageProcessor.Imaging
case "Png":
return ".png";
case "Tif":
- return ".tif";
case "Tiff":
return ".tif";
default:
@@ -197,9 +197,26 @@ namespace ImageProcessor.Imaging
/// True the value contains a valid image extension, otherwise false.
public static bool IsValidImageExtension(string fileName)
{
+
return FormatRegex.IsMatch(fileName);
}
+ ///
+ /// Returns the correct file extension for the given string input
+ ///
+ ///
+ /// The string to parse.
+ ///
+ ///
+ /// The correct file extension for the given string input if it can find one; otherwise an empty string.
+ ///
+ public static string GetExtension(string input)
+ {
+ Match match = FormatRegex.Matches(input)[0];
+
+ return match.Success ? match.Value : string.Empty;
+ }
+
/// Returns a value indicating whether or not the given bitmap is indexed.
/// The image to check
/// Whether or not the given bitmap is indexed.
diff --git a/src/ImageProcessor/Processors/Format.cs b/src/ImageProcessor/Processors/Format.cs
index 42efc8bd8..16fc08973 100644
--- a/src/ImageProcessor/Processors/Format.cs
+++ b/src/ImageProcessor/Processors/Format.cs
@@ -25,7 +25,7 @@ namespace ImageProcessor.Processors
///
/// The regular expression to search strings for.
///
- private static readonly Regex QueryRegex = new Regex(@"format=(jpeg|png|png8|bmp|gif|tif)", RegexOptions.Compiled);
+ private static readonly Regex QueryRegex = new Regex(@"format=(j(pg|peg)|png|png8|bmp|gif|tif)", RegexOptions.Compiled);
#region IGraphicsProcessor Members
///
diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs
index d25387498..68075c37d 100644
--- a/src/ImageProcessor/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor/Properties/AssemblyInfo.cs
@@ -32,6 +32,6 @@ using System.Security;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.7.0.0")]
-[assembly: AssemblyFileVersion("1.7.0.0")]
+[assembly: AssemblyVersion("1.7.0.1")]
+[assembly: AssemblyFileVersion("1.7.0.1")]
diff --git a/src/Nuget/ImageProcessor.1.6.0.1.nupkg b/src/Nuget/ImageProcessor.1.6.0.1.nupkg
deleted file mode 100644
index 9a61f73a9..000000000
Binary files a/src/Nuget/ImageProcessor.1.6.0.1.nupkg and /dev/null differ
diff --git a/src/Nuget/ImageProcessor.1.7.0.1.nupkg b/src/Nuget/ImageProcessor.1.7.0.1.nupkg
new file mode 100644
index 000000000..3d5bdf876
Binary files /dev/null and b/src/Nuget/ImageProcessor.1.7.0.1.nupkg differ
diff --git a/src/Nuget/ImageProcessor.Web.2.2.3.3.nupkg.REMOVED.git-id b/src/Nuget/ImageProcessor.Web.2.2.3.3.nupkg.REMOVED.git-id
deleted file mode 100644
index 9e9ad0766..000000000
--- a/src/Nuget/ImageProcessor.Web.2.2.3.3.nupkg.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-01e1999a7804bb48ba37f247dfdb1bf01f05fa62
\ No newline at end of file
diff --git a/src/Nuget/ImageProcessor.Web.2.3.0.0.nupkg.REMOVED.git-id b/src/Nuget/ImageProcessor.Web.2.3.0.0.nupkg.REMOVED.git-id
deleted file mode 100644
index b2911f9c5..000000000
--- a/src/Nuget/ImageProcessor.Web.2.3.0.0.nupkg.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-8b33cb0b4f13802b62d2511239e212680ad67158
\ No newline at end of file
diff --git a/src/Nuget/ImageProcessor.Web.2.3.0.2.nupkg.REMOVED.git-id b/src/Nuget/ImageProcessor.Web.2.3.0.2.nupkg.REMOVED.git-id
new file mode 100644
index 000000000..10b435c4e
--- /dev/null
+++ b/src/Nuget/ImageProcessor.Web.2.3.0.2.nupkg.REMOVED.git-id
@@ -0,0 +1 @@
+8c5a374f583194706fa94a269f7ab4543dc4ece6
\ No newline at end of file
diff --git a/src/Nuget/ImageProcessor.Web.2.3.0.3.nupkg.REMOVED.git-id b/src/Nuget/ImageProcessor.Web.2.3.0.3.nupkg.REMOVED.git-id
new file mode 100644
index 000000000..a026a9cf9
--- /dev/null
+++ b/src/Nuget/ImageProcessor.Web.2.3.0.3.nupkg.REMOVED.git-id
@@ -0,0 +1 @@
+0a367af8c6588fe2be54ef5950820a7f06f7b0f1
\ No newline at end of file
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.config b/src/TestWebsites/NET45/Test_Website_NET45/Web.config
index 093761644..fb3bbb368 100644
--- a/src/TestWebsites/NET45/Test_Website_NET45/Web.config
+++ b/src/TestWebsites/NET45/Test_Website_NET45/Web.config
@@ -5,79 +5,80 @@
-->
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
+
-
-
-
-
-
-
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+