private string GetCachePath() { string cachedPath = string.Empty; if (AbsoluteCachePath != null) { // Use an sha1 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 characters of that hash as subfolders. string parsedExtension = ImageHelpers.GetExtension(this.fullPath); string fallbackExtension = this.imageName.Substring(this.imageName.LastIndexOf(".", StringComparison.Ordinal) + 1); string encryptedName = this.fullPath.ToSHA1Fingerprint(); // Collision rate of about 1 in 10000 for the folder structure. string pathFromKey = string.Join("\\", encryptedName.ToCharArray().Take(6)); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : fallbackExtension); cachedPath = Path.Combine(AbsoluteCachePath, pathFromKey, cachedFileName); } return(cachedPath); }
/// <summary> /// Gets a string identifying the cached file name. /// </summary> /// <returns> /// The asynchronous <see cref="Task"/> returning the value. /// </returns> public override async Task <string> CreateCachedFileNameAsync() { string streamHash = string.Empty; try { if (new Uri(this.RequestPath).IsFile) { // Get the hash for the filestream. That way we can ensure that if the image is // updated but has the same name we will know. FileInfo imageFileInfo = new FileInfo(this.RequestPath); if (imageFileInfo.Exists) { // Pull the latest info. imageFileInfo.Refresh(); // Checking the stream itself is far too processor intensive so we make a best guess. string creation = imageFileInfo.CreationTimeUtc.ToString(CultureInfo.InvariantCulture); string length = imageFileInfo.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } else { // Try and get the headers for the file, this should allow cache busting for remote files. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.RequestPath); request.Method = "HEAD"; using (HttpWebResponse response = (HttpWebResponse)(await request.GetResponseAsync())) { string lastModified = response.LastModified.ToUniversalTime().ToString(CultureInfo.InvariantCulture); string length = response.ContentLength.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", lastModified, length); } } // TODO: Pull from other cloud folder/bucket to match the AzureBlobCache behaviour. } catch { streamHash = string.Empty; } // Use an sha1 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 characters of that hash as sub-folders. string parsedExtension = ImageHelpers.GetExtension(this.FullPath, this.Querystring); string encryptedName = (streamHash + this.FullPath).ToSHA1Fingerprint(); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); return(cachedFileName); }
/// <summary> /// Gets the full transformed cached paths for the image. /// The images are stored in paths that are based upon the SHA1 of their full request path /// taking the individual characters of the hash to determine their location. /// This allows us to store millions of images. /// </summary> private void GetCachePaths() { string streamHash = string.Empty; if (AbsoluteCachePath != null) { try { if (new Uri(this.requestPath).IsFile) { // Get the hash for the filestream. That way we can ensure that if the image is // updated but has the same name we will know. FileInfo imageFileInfo = new FileInfo(this.requestPath); if (imageFileInfo.Exists) { // Pull the latest info. imageFileInfo.Refresh(); // Checking the stream itself is far too processor intensive so we make a best guess. string creation = imageFileInfo.CreationTimeUtc.ToString(CultureInfo.InvariantCulture); string length = imageFileInfo.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } } catch { streamHash = string.Empty; } // Use an sha1 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 characters of that hash as sub-folders. string parsedExtension = ImageHelpers.GetExtension(this.fullPath, this.querystring); string encryptedName = (streamHash + this.fullPath).ToSHA1Fingerprint(); // Collision rate of about 1 in 10000 for the folder structure. string pathFromKey = string.Join("\\", encryptedName.ToCharArray().Take(6)); string virtualPathFromKey = pathFromKey.Replace(@"\", "/"); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); this.physicalCachedPath = Path.Combine(AbsoluteCachePath, pathFromKey, cachedFileName); this.virtualCachedPath = Path.Combine(VirtualCachePath, virtualPathFromKey, cachedFileName).Replace(@"\", "/"); } }
/// <summary> /// Gets a string identifying the cached file name. /// </summary> /// <returns> /// The asynchronous <see cref="Task"/> returning the value. /// </returns> public virtual async Task <string> CreateCachedFileNameAsync() { string streamHash = string.Empty; try { if (new Uri(this.RequestPath).IsFile) { // Get the hash for the filestream. That way we can ensure that if the image is // updated but has the same name we will know. FileInfo imageFileInfo = new FileInfo(this.RequestPath); if (imageFileInfo.Exists) { // Pull the latest info. imageFileInfo.Refresh(); // Checking the stream itself is far too processor intensive so we make a best guess. string creation = imageFileInfo.CreationTimeUtc.ToString(CultureInfo.InvariantCulture); string length = imageFileInfo.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } } catch { streamHash = string.Empty; } // Use an sha1 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 characters of that hash as sub-folders. string parsedExtension = ImageHelpers.GetExtension(this.FullPath, this.Querystring); string encryptedName = (streamHash + this.FullPath).ToSHA1Fingerprint(); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); return(await Task.FromResult(cachedFileName)); }
/// <summary> /// Gets a string identifying the cached file name. /// </summary> /// <returns> /// The asynchronous <see cref="Task"/> returning the value. /// </returns> public override async Task <string> CreateCachedFileNameAsync() { string streamHash = string.Empty; try { if (new Uri(this.RequestPath).IsFile) { // Get the hash for the filestream. That way we can ensure that if the image is // updated but has the same name we will know. FileInfo imageFileInfo = new FileInfo(this.RequestPath); if (imageFileInfo.Exists) { // Pull the latest info. imageFileInfo.Refresh(); // Checking the stream itself is far too processor intensive so we make a best guess. string creation = imageFileInfo.CreationTimeUtc.ToString(CultureInfo.InvariantCulture); string length = imageFileInfo.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } else if (this.cloudSourceBlobContainer != null) { string container = RemoteRegex.Replace(this.cloudSourceBlobContainer.Uri.ToString(), string.Empty); string blobPath = RemoteRegex.Replace(this.RequestPath, string.Empty); blobPath = blobPath.Replace(container, string.Empty).TrimStart('/'); CloudBlockBlob blockBlob = this.cloudSourceBlobContainer.GetBlockBlobReference(blobPath); if (await blockBlob.ExistsAsync()) { // Pull the latest info. await blockBlob.FetchAttributesAsync(); if (blockBlob.Properties.LastModified.HasValue) { string creation = blockBlob.Properties .LastModified.Value.UtcDateTime .ToString(CultureInfo.InvariantCulture); string length = blockBlob.Properties.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } } else { // Try and get the headers for the file, this should allow cache busting for remote files. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.RequestPath); request.Method = "HEAD"; using (HttpWebResponse response = (HttpWebResponse)(await request.GetResponseAsync())) { string lastModified = response.LastModified.ToUniversalTime().ToString(CultureInfo.InvariantCulture); string length = response.ContentLength.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", lastModified, length); } } } catch { streamHash = string.Empty; } // Use an sha1 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 characters of that hash as sub-folders. string parsedExtension = ImageHelpers.GetExtension(this.FullPath, this.Querystring); string encryptedName = (streamHash + this.FullPath).ToSHA1Fingerprint(); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); return(cachedFileName); }