/// <summary> /// Processes the image. /// </summary> /// <param name="context"> /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides /// references to the intrinsic server objects /// </param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task"/>. /// </returns> private async Task ProcessImageAsync(HttpContext context) { HttpRequest request = context.Request; // Fixes issue 10. bool isRemote = request.Path.EndsWith(RemotePrefix, StringComparison.OrdinalIgnoreCase); string requestPath = string.Empty; string queryString = string.Empty; if (isRemote) { // We need to split the querystring to get the actual values we want. string urlDecode = HttpUtility.UrlDecode(request.QueryString.ToString()); if (!string.IsNullOrWhiteSpace(urlDecode)) { // UrlDecode seems to mess up in some circumstance. if (urlDecode.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1) { urlDecode = urlDecode.Replace(":/", "://"); } string[] paths = urlDecode.Split('?'); requestPath = paths[0]; if (paths.Length > 1) { queryString = paths[1]; } } } else { requestPath = HostingEnvironment.MapPath(request.Path); queryString = HttpUtility.UrlDecode(request.QueryString.ToString()); } // Only process requests that pass our sanitizing filter. if (ImageUtils.IsValidImageExtension(requestPath) && !string.IsNullOrWhiteSpace(queryString)) { string fullPath = string.Format("{0}?{1}", requestPath, queryString); string imageName = Path.GetFileName(requestPath); // Create a new cache to help process and cache the request. DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName, isRemote); // 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; // Run the rewritten path past the auth system again, using the result as the default "AllowAccess" value if (hasPermission && !context.SkipAuthorization) { 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) { // Process the image. using (ImageFactory imageFactory = new ImageFactory()) { if (isRemote) { Uri uri = new Uri(requestPath); RemoteFile remoteFile = new RemoteFile(uri, false); // Prevent response blocking. WebResponse webResponse = await remoteFile.GetWebResponseAsync().ConfigureAwait(false); using (MemoryStream memoryStream = new MemoryStream()) { using (WebResponse response = webResponse) { using (Stream responseStream = response.GetResponseStream()) { if (responseStream != null) { // Trim the cache. await cache.TrimCachedFoldersAsync(); responseStream.CopyTo(memoryStream); 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(); // Add to the cache. await cache.AddImageToCacheAsync(dateTime); } } } } } else { // Trim the cache. await cache.TrimCachedFoldersAsync(); imageFactory.Load(fullPath).AutoProcess().Save(cache.CachedPath); // 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); } } } // 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); } else { throw new HttpException(403, "Access denied"); } } }