Browse Source

Extended remote file reader to handle extensionless image urls and querystring parameters for remote URLs

New properties for whitelist: <add url="http://maps.googleapis.com"
extensionLess="true" imageFormat="png" />
Sample URL for extensionless/paramter remote image:
http://localhost:49788/remote.axd?http://maps.googleapis.com/maps/api/staticmap?center=52.341055,7.125435&zoom=13&sensor=false&size=600x300&key=AIzaSyCMKi4DyRB2N-j-Sm3LpZkl6rSXWP_G5ZE?width=600
A 3rd querystring part (here: width=600) if the remote image url has url
parameters

Former-commit-id: 7f4f18b44eec578b74e2b02647f5fb6bd54fe29c
af/merge-core
aka Torgon Woodget 13 years ago
parent
commit
37a2ce60e2
  1. 11
      src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs
  2. 16
      src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs
  3. 5
      src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs
  4. 50
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  5. 7
      src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj
  6. 6
      src/ImageProcessor.Web/NET45/packages.config

11
src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs

@ -121,6 +121,17 @@ namespace ImageProcessor.Web.Config
}
}
/// <summary>
///
/// </summary>
public ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions
{
get
{
return GetImageSecuritySection().WhiteList.Cast<ImageSecuritySection.SafeUrl>().ToArray();
}
}
/// <summary>
/// Gets a value indicating whether the current application is allowed to download remote files.
/// </summary>

16
src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs

@ -178,6 +178,22 @@ namespace ImageProcessor.Web.Config
set { this["url"] = value; }
}
[ConfigurationProperty("extensionLess", DefaultValue = false, IsRequired = false)]
public bool ExtensionLess
{
get { return (bool)this["extensionLess"]; }
set { this["extensionLess"] = value; }
}
[ConfigurationProperty("imageFormat", DefaultValue = "", IsRequired = false)]
public string ImageFormat
{
get { return (string)this["imageFormat"]; }
set { this["imageFormat"] = value; }
}
}
}
}

5
src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs

@ -48,6 +48,11 @@ namespace ImageProcessor.Web.Helpers
/// </summary>
private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList;
/// <summary>
/// The white-list of url[s] from which to download remote files.
/// </summary>
public static readonly ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions = ImageProcessorConfig.Instance.RemoteFileWhiteListExtensions;
/// <summary>
/// The length of time, in milliseconds, that a remote file download attempt can last before timing out.
/// </summary>

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

@ -5,6 +5,11 @@
// </copyright>
// -----------------------------------------------------------------------
using System.Linq;
using System.Security.Cryptography;
using System.Security.Policy;
using System.Text;
namespace ImageProcessor.Web.HttpModules
{
#region Using
@ -177,6 +182,10 @@ namespace ImageProcessor.Web.HttpModules
string requestPath = string.Empty;
string queryString = string.Empty;
bool validExtensionLessUrl = false;
string urlParameters = "";
string extensionLessExtension = "";
if (isRemote)
{
// We need to split the querystring to get the actual values we want.
@ -194,10 +203,25 @@ namespace ImageProcessor.Web.HttpModules
requestPath = paths[0];
if (paths.Length > 1)
if (paths.Count() > 2)
{
queryString = paths[2];
urlParameters = paths[1];
}
else if (paths.Length > 1)
{
queryString = paths[1];
}
validExtensionLessUrl = RemoteFile.RemoteFileWhiteListExtensions.Any(
x => x.ExtensionLess == true && requestPath.StartsWith(x.Url.AbsoluteUri));
if (validExtensionLessUrl)
{
extensionLessExtension = RemoteFile.RemoteFileWhiteListExtensions.First(
x => x.ExtensionLess == true && requestPath.StartsWith(x.Url.AbsoluteUri)).ImageFormat;
}
}
}
else
@ -207,11 +231,31 @@ namespace ImageProcessor.Web.HttpModules
}
// Only process requests that pass our sanitizing filter.
if (ImageUtils.IsValidImageExtension(requestPath) && !string.IsNullOrWhiteSpace(queryString))
if ((ImageUtils.IsValidImageExtension(requestPath) || validExtensionLessUrl ) && !string.IsNullOrWhiteSpace(queryString))
{
string fullPath = string.Format("{0}?{1}", requestPath, queryString);
string imageName = Path.GetFileName(requestPath);
if (validExtensionLessUrl && !string.IsNullOrWhiteSpace(extensionLessExtension))
{
fullPath = requestPath;
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();
}
imageName += "." + extensionLessExtension;
fullPath += extensionLessExtension + "?" + queryString;
}
// Create a new cache to help process and cache the request.
DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName, isRemote);
@ -251,7 +295,7 @@ namespace ImageProcessor.Web.HttpModules
{
if (isRemote)
{
Uri uri = new Uri(requestPath);
Uri uri = new Uri(requestPath + "?" + urlParameters);
RemoteFile remoteFile = new RemoteFile(uri, false);

7
src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj

@ -11,6 +11,8 @@
<AssemblyName>ImageProcessor.Web</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\..\..\..\..\..\..\TFS\ActiMeet\ActiMeet2\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -31,10 +33,10 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Community.CsharpSqlite">
<HintPath>..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\..\TFS\ActiMeet\ActiMeet2\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll</HintPath>
</Reference>
<Reference Include="Community.CsharpSqlite.SQLiteClient">
<HintPath>..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\..\TFS\ActiMeet\ActiMeet2\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@ -75,6 +77,7 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

6
src/ImageProcessor.Web/NET45/packages.config

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages >
<package id="Csharp-Sqlite" version="3.7.7.1" targetFramework="net40" />
<package id="sqlite-net" version="1.0.7" targetFramework="net40" />
<packages>
<package id="Csharp-Sqlite" version="3.7.7.1" targetFramework="net45" />
<package id="sqlite-net" version="1.0.7" targetFramework="net45" />
</packages>
Loading…
Cancel
Save