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 async Task CreateDownloadFileActionResultAsync(Uri requestUrl, string folderName, string fileName) { ICloudBlobContainer container = await GetContainer(folderName); var blob = container.GetBlobReference(fileName); var redirectUri = GetRedirectUri(requestUrl, blob.Uri); return new RedirectResult(redirectUri.OriginalString, false); } public async Task DeleteFileAsync(string folderName, string fileName) { ICloudBlobContainer container = await GetContainer(folderName); var blob = container.GetBlobReference(fileName); await blob.DeleteIfExistsAsync(); } public async Task FileExistsAsync(string folderName, string fileName) { ICloudBlobContainer container = await GetContainer(folderName); var blob = container.GetBlobReference(fileName); return await blob.ExistsAsync(); } 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 async 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.", folderName)); } container = await creationTask; _containers[folderName] = container; return container; } private async Task PrepareContainer(string folderName, bool isPublic) { var container = _client.GetContainerReference(folderName); await container.CreateIfNotExistAsync(); await container.SetPermissionsAsync( new BlobContainerPermissions { PublicAccess = isPublic ? BlobContainerPublicAccessType.Blob : BlobContainerPublicAccessType.Off }); return container; } } }