using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using Microsoft.WindowsAzure.Storage.Blob.Protocol; using NuGetGallery.Configuration; namespace NuGetGallery { public class CloudBlobFileStorageService : IFileStorageService { private readonly ICloudBlobClient _client; private readonly IAppConfiguration _configuration; private readonly ConcurrentDictionary _containers = new ConcurrentDictionary(); public CloudBlobFileStorageService(ICloudBlobClient client, IAppConfiguration configuration) { _client = client; _configuration = configuration; } public Task CreateDownloadFileActionResult(Uri requestUrl, string folderName, string fileName) { ICloudBlobContainer container = GetContainer(folderName); var blob = container.GetBlobReference(fileName); // obtain the redirect uri var redirectUri = GetRedirectUri(requestUrl, blob.Uri); return new RedirectResult(redirectUri.OriginalString, false); } public Task DeleteFile(string folderName, string fileName) { ICloudBlobContainer container = GetContainer(folderName); var blob = container.GetBlobReference(fileName); blob.DeleteIfExists(); } public Task FileExists(string folderName, string fileName) { ICloudBlobContainer container = GetContainer(folderName); var blob = container.GetBlobReference(fileName); return blob.Exists(); } internal Uri GetRedirectUri(Uri requestUrl, Uri blobUri) { string host = String.IsNullOrEmpty(_configuration.AzureCdnHost) ? blobUri.Host : _configuration.AzureCdnHost; var urlBuilder = new UriBuilder(requestUrl.Scheme, host) { Path = blobUri.LocalPath, Query = blobUri.Query }; return urlBuilder.Uri; } private Task GetContainer(string folderName) { ICloudBlobContainer container; if (_containers.TryGetValue(folderName, out container)) { return container; } Task creationTask; switch (folderName) { case Constants.PackagesFolderName: case Constants.DownloadsFolderName: creationTask = PrepareContainer(folderName, isPublic: true); break; case Constants.ContentFolderName: case Constants.UploadsFolderName: creationTask = PrepareContainer(folderName, isPublic: false); break; default: throw new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported yet.", folderName)); } container = creationTask; _containers[folderName] = container; return container; } private Task PrepareContainer(string folderName, bool isPublic) { var container = _client.GetContainerReference(folderName); container.CreateIfNotExist(); container.SetPermissions( new BlobContainerPermissions { PublicAccess = isPublic ? BlobContainerPublicAccessType.Blob : BlobContainerPublicAccessType.Off }); return container; } } }