Browse Source

prefixed requests no longer require a querystring

Former-commit-id: 20431e2c1072865a5e352fc0a4fb0d0e1c33a164
Former-commit-id: 75ad92152d9d586fc88efe27bebc7c3044f1edc0
af/merge-core
James South 11 years ago
parent
commit
dfa7b8ca5d
  1. 10
      src/ImageProcessor.Playground/Program.cs
  2. 232
      src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs

10
src/ImageProcessor.Playground/Program.cs

@ -53,7 +53,7 @@ namespace ImageProcessor.PlayGround
Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask.png")); Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask.png"));
Image overlay = Image.FromFile(Path.Combine(resolvedPath, "imageprocessor.128.png")); Image overlay = Image.FromFile(Path.Combine(resolvedPath, "imageprocessor.128.png"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "monster.png")); //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "monster.png"));
IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".jpg"); IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif"); //IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif");
foreach (FileInfo fileInfo in files) foreach (FileInfo fileInfo in files)
@ -88,11 +88,10 @@ namespace ImageProcessor.PlayGround
//.Resize(new Size((int)(size.Width * 1.1), 0)) //.Resize(new Size((int)(size.Width * 1.1), 0))
//.ContentAwareResize(layer) //.ContentAwareResize(layer)
//.Constrain(size) //.Constrain(size)
//.Rotate(-64)
//.Mask(mask) //.Mask(mask)
//.Format(new PngFormat()) //.Format(new PngFormat())
//.BackgroundColor(Color.Cyan) //.BackgroundColor(Color.Cyan)
.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128) //.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128)
//.Resize(size) //.Resize(size)
// .Resize(new ResizeLayer(size, ResizeMode.Max)) // .Resize(new ResizeLayer(size, ResizeMode.Max))
// .Resize(new ResizeLayer(size, ResizeMode.Stretch)) // .Resize(new ResizeLayer(size, ResizeMode.Stretch))
@ -104,9 +103,10 @@ namespace ImageProcessor.PlayGround
//.Filter(MatrixFilters.Comic) //.Filter(MatrixFilters.Comic)
//.Flip() //.Flip()
//.Filter(MatrixFilters.HiSatch) //.Filter(MatrixFilters.HiSatch)
//.Pixelate(8) .Pixelate(8)
.Rotate(45)
//.GaussianSharpen(10) //.GaussianSharpen(10)
.Format(new PngFormat()) //.Format(new PngFormat() { IsIndexed = true })
//.Format(new PngFormat() { IsIndexed = true }) //.Format(new PngFormat() { IsIndexed = true })
//.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); //.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".png"))); .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".png")));

232
src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs

@ -316,151 +316,161 @@ namespace ImageProcessor.Web.HttpModules
} }
else else
{ {
requestPath = HostingEnvironment.MapPath(request.Path); if (string.IsNullOrWhiteSpace(currentService.Prefix))
queryString = HttpUtility.UrlDecode(request.QueryString.ToString());
}
// Only process requests that pass our sanitizing filter.
if (!string.IsNullOrWhiteSpace(queryString))
{
// Replace any presets in the querystring with the actual value.
queryString = this.ReplacePresetsInQueryString(queryString);
string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty;
string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString);
object resourcePath;
if (hasMultiParams)
{ {
resourcePath = string.IsNullOrWhiteSpace(urlParameters) requestPath = HostingEnvironment.MapPath(request.Path);
? new Uri(requestPath, UriKind.RelativeOrAbsolute) queryString = HttpUtility.UrlDecode(request.QueryString.ToString());
: new Uri(requestPath + "?" + urlParameters, UriKind.RelativeOrAbsolute);
} }
else else
{ {
resourcePath = requestPath; requestPath = HttpUtility.UrlDecode(request.QueryString.ToString());
} }
}
// Check whether the path is valid for other requests. // If the current service doesn't require a prefix, don't fetch it.
if (resourcePath == null || !currentService.IsValidRequest(resourcePath.ToString())) // Let the static file handler take over.
{ if (string.IsNullOrWhiteSpace(currentService.Prefix) && string.IsNullOrWhiteSpace(queryString))
return; {
} return;
}
// Replace any presets in the querystring with the actual value.
queryString = this.ReplacePresetsInQueryString(queryString);
string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty;
string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString);
object resourcePath;
if (hasMultiParams)
{
resourcePath = string.IsNullOrWhiteSpace(urlParameters)
? new Uri(requestPath, UriKind.RelativeOrAbsolute)
: new Uri(requestPath + "?" + urlParameters, UriKind.RelativeOrAbsolute);
}
else
{
resourcePath = requestPath;
}
// Create a new cache to help process and cache the request. // Check whether the path is valid for other requests.
DiskCache cache = new DiskCache(requestPath, fullPath, queryString); if (resourcePath == null || !currentService.IsValidRequest(resourcePath.ToString()))
string cachedPath = cache.CachedPath; {
return;
}
// Since we are now rewriting the path we need to check again that the current user has access // Create a new cache to help process and cache the request.
// to the rewritten path. DiskCache cache = new DiskCache(requestPath, fullPath, queryString);
// Get the user for the current request string cachedPath = cache.CachedPath;
// 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.VirtualCachedPath;
IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); // 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.VirtualCachedPath;
// Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal? IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);
PermissionSet permission = new PermissionSet(PermissionState.None);
permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted));
bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet);
bool isAllowed = true; // 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);
// Run the rewritten path past the authorization system again. bool isAllowed = true;
// We can then use the result as the default "AllowAccess" value
if (hasPermission && !context.SkipAuthorization)
{
isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET");
}
if (isAllowed) // Run the rewritten path past the authorization system again.
{ // We can then use the result as the default "AllowAccess" value
// Is the file new or updated? if (hasPermission && !context.SkipAuthorization)
bool isNewOrUpdated = cache.IsNewOrUpdatedFile(cachedPath); {
isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET");
}
// Only process if the file has been updated. if (isAllowed)
if (isNewOrUpdated) {
// Is the file new or updated?
bool isNewOrUpdated = cache.IsNewOrUpdatedFile(cachedPath);
// Only process if the file has been updated.
if (isNewOrUpdated)
{
// Process the image.
using (ImageFactory imageFactory = new ImageFactory(preserveExifMetaData != null && preserveExifMetaData.Value))
{ {
// Process the image. using (await this.locker.LockAsync(cachedPath))
using (ImageFactory imageFactory = new ImageFactory(preserveExifMetaData != null && preserveExifMetaData.Value))
{ {
using (await this.locker.LockAsync(cachedPath)) byte[] imageBuffer = await currentService.GetImage(resourcePath);
{
byte[] imageBuffer = await currentService.GetImage(resourcePath);
using (MemoryStream memoryStream = new MemoryStream(imageBuffer)) using (MemoryStream memoryStream = new MemoryStream(imageBuffer))
{ {
// Reset the position of the stream to ensure we're reading the correct part. // Reset the position of the stream to ensure we're reading the correct part.
memoryStream.Position = 0; memoryStream.Position = 0;
// Process the Image // Process the Image
imageFactory.Load(memoryStream).AutoProcess(queryString).Save(cachedPath); imageFactory.Load(memoryStream).AutoProcess(queryString).Save(cachedPath);
// Add to the cache. // Add to the cache.
cache.AddImageToCache(cachedPath); cache.AddImageToCache(cachedPath);
// Store the cached path, response type, and cache dependency in the context for later retrieval. // Store the cached path, response type, and cache dependency in the context for later retrieval.
context.Items[CachedPathKey] = cachedPath; context.Items[CachedPathKey] = cachedPath;
context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType;
context.Items[CachedResponseFileDependency] = new List<string> { cachedPath }; context.Items[CachedResponseFileDependency] = new List<string> { cachedPath };
}
} }
} }
} }
}
// Image is from the cache so the mime-type will need to be set. // Image is from the cache so the mime-type will need to be set.
if (context.Items[CachedResponseTypeKey] == null) if (context.Items[CachedResponseTypeKey] == null)
{ {
string mimetype = ImageHelpers.GetMimeType(cachedPath); string mimetype = ImageHelpers.GetMimeType(cachedPath);
if (!string.IsNullOrEmpty(mimetype))
{
context.Items[CachedResponseTypeKey] = mimetype;
}
}
if (context.Items[CachedResponseFileDependency] == null) if (!string.IsNullOrEmpty(mimetype))
{ {
context.Items[CachedResponseFileDependency] = new List<string> { cachedPath }; context.Items[CachedResponseTypeKey] = mimetype;
} }
}
string incomingEtag = context.Request.Headers["If" + "-None-Match"]; if (context.Items[CachedResponseFileDependency] == null)
{
context.Items[CachedResponseFileDependency] = new List<string> { cachedPath };
}
if (incomingEtag != null && !isNewOrUpdated) string incomingEtag = context.Request.Headers["If" + "-None-Match"];
{
// 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;
if (isFileLocal) if (incomingEtag != null && !isNewOrUpdated)
{ {
// Set the headers and quit. // Set the Content-Length header so the client doesn't wait for
// Some services might only provide filename so we can't monitor for the browser. // content but keeps the connection open for other requests.
this.SetHeaders( context.Response.AddHeader("Content-Length", "0");
context, context.Response.StatusCode = (int)HttpStatusCode.NotModified;
(string)context.Items[CachedResponseTypeKey], context.Response.SuppressContent = true;
Path.GetFileName(requestPath) == requestPath ? new List<string> { cachedPath } : new List<string> { requestPath, cachedPath });
}
else
{
this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], new List<string> { cachedPath });
}
// Complete the requests but don't abort the thread. if (isFileLocal)
context.ApplicationInstance.CompleteRequest(); {
return; // Set the headers and quit.
// Some services might only provide filename so we can't monitor for the browser.
this.SetHeaders(
context,
(string)context.Items[CachedResponseTypeKey],
Path.GetFileName(requestPath) == requestPath ? new List<string> { cachedPath } : new List<string> { requestPath, cachedPath });
}
else
{
this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], new List<string> { cachedPath });
} }
// The cached file is valid so just rewrite the path. // Complete the requests but don't abort the thread.
context.RewritePath(virtualCachedPath, false); context.ApplicationInstance.CompleteRequest();
} return;
else
{
throw new HttpException(403, "Access denied");
} }
// The cached file is valid so just rewrite the path.
context.RewritePath(virtualCachedPath, false);
}
else
{
throw new HttpException(403, "Access denied");
} }
} }
} }

Loading…
Cancel
Save