diff --git a/src/NuGetGallery.Core/CoreConstants.cs b/src/NuGetGallery.Core/CoreConstants.cs index 0271f29cb2..8a341558e5 100644 --- a/src/NuGetGallery.Core/CoreConstants.cs +++ b/src/NuGetGallery.Core/CoreConstants.cs @@ -23,6 +23,8 @@ public static class CoreConstants public const string CertificateContentType = "application/pkix-cert"; public const string JsonContentType = "application/json"; + public const string DefaultCacheControl = "max-age=120"; + public const string UserCertificatesFolderName = "user-certificates"; public const string ContentFolderName = "content"; public const string DownloadsFolderName = "downloads"; diff --git a/src/NuGetGallery.Core/Services/CloudBlobCoreFileStorageService.cs b/src/NuGetGallery.Core/Services/CloudBlobCoreFileStorageService.cs index 55831779b0..dfb0672bd8 100644 --- a/src/NuGetGallery.Core/Services/CloudBlobCoreFileStorageService.cs +++ b/src/NuGetGallery.Core/Services/CloudBlobCoreFileStorageService.cs @@ -318,6 +318,7 @@ public async Task SaveFileAsync(string folderName, string fileName, Stream file, } blob.Properties.ContentType = GetContentType(folderName); + blob.Properties.CacheControl = GetCacheControl(folderName); await blob.SetPropertiesAsync(); } @@ -549,6 +550,7 @@ private static string GetContentType(string folderName) case CoreConstants.PackageReadMesFolderName: return CoreConstants.TextContentType; + case CoreConstants.ContentFolderName: case CoreConstants.RevalidationFolderName: case CoreConstants.StatusFolderName: return CoreConstants.JsonContentType; @@ -562,6 +564,32 @@ private static string GetContentType(string folderName) } } + private static string GetCacheControl(string folderName) + { + switch (folderName) + { + case CoreConstants.PackagesFolderName: + return CoreConstants.DefaultCacheControl; + + case CoreConstants.PackageBackupsFolderName: + case CoreConstants.UploadsFolderName: + case CoreConstants.ValidationFolderName: + case CoreConstants.SymbolPackagesFolderName: + case CoreConstants.SymbolPackageBackupsFolderName: + case CoreConstants.DownloadsFolderName: + case CoreConstants.PackageReadMesFolderName: + case CoreConstants.ContentFolderName: + case CoreConstants.RevalidationFolderName: + case CoreConstants.StatusFolderName: + case CoreConstants.UserCertificatesFolderName: + return null; + + default: + throw new InvalidOperationException( + String.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName)); + } + } + private async Task PrepareContainer(string folderName, bool isPublic) { var container = _client.GetContainerReference(folderName); diff --git a/tests/NuGetGallery.Core.Facts/Services/CloudBlobCoreFileStorageServiceFacts.cs b/tests/NuGetGallery.Core.Facts/Services/CloudBlobCoreFileStorageServiceFacts.cs index 27fba0ba76..6df9fb09cd 100644 --- a/tests/NuGetGallery.Core.Facts/Services/CloudBlobCoreFileStorageServiceFacts.cs +++ b/tests/NuGetGallery.Core.Facts/Services/CloudBlobCoreFileStorageServiceFacts.cs @@ -48,7 +48,7 @@ public override IEnumerable GetData(MethodInfo testMethod) { var folderNames = new List { - new object[] { CoreConstants.ContentFolderName, false, null, }, + new object[] { CoreConstants.ContentFolderName, false, CoreConstants.JsonContentType, }, new object[] { CoreConstants.DownloadsFolderName, true, CoreConstants.OctetStreamContentType }, new object[] { CoreConstants.PackageBackupsFolderName, true, CoreConstants.PackageContentType }, new object[] { CoreConstants.PackageReadMesFolderName, false, CoreConstants.TextContentType }, @@ -73,7 +73,6 @@ public override IEnumerable GetData(MethodInfo testMethod) else if (!IncludePermissions && IncludeContentTypes) { folderNames = folderNames - .Where(fn => fn[2] != null) .Select(fn => new[] { fn[0], fn[2] }) .ToList(); } @@ -512,6 +511,41 @@ public async Task WillSetTheBlobContentType(string folderName, string contentTyp Assert.Equal(contentType, fakeBlob.Object.Properties.ContentType); fakeBlob.Verify(x => x.SetPropertiesAsync()); } + + [Theory] + [FolderNamesData] + public async Task WillSetTheBlobControlCacheOnPackagesFolder(string folderName) + { + var fakeBlobClient = new Mock(); + var fakeBlobContainer = new Mock(); + fakeBlobContainer.Setup(x => x.CreateIfNotExistAsync()).Returns(Task.FromResult(0)); + fakeBlobContainer.Setup(x => x.SetPermissionsAsync(It.IsAny())).Returns(Task.FromResult(0)); + var fakeBlob = new Mock(); + fakeBlobClient.Setup(x => x.GetContainerReference(It.IsAny())).Returns(fakeBlobContainer.Object); + fakeBlobContainer.Setup(x => x.GetBlobReference(It.IsAny())).Returns(fakeBlob.Object); + fakeBlob.Setup(x => x.Properties).Returns(new BlobProperties()); + fakeBlob.Setup(x => x.Uri).Returns(new Uri("http://theUri")); + fakeBlob.Setup(x => x.DeleteIfExistsAsync()).Returns(Task.FromResult(0)); + fakeBlob.Setup(x => x.SetPropertiesAsync()).Returns(Task.FromResult(0)); + var service = CreateService(fakeBlobClient: fakeBlobClient); + var fakePackageFile = new MemoryStream(); + fakeBlob.Setup(x => x.UploadFromStreamAsync(fakePackageFile, true)).Returns(Task.FromResult(0)).Verifiable(); + + await service.SaveFileAsync(folderName, "theFileName", fakePackageFile); + + fakeBlob.Verify(); + + if (folderName == CoreConstants.PackagesFolderName) + { + Assert.Equal(CoreConstants.DefaultCacheControl, fakeBlob.Object.Properties.CacheControl); + } + else + { + Assert.Null(fakeBlob.Object.Properties.CacheControl); + } + + fakeBlob.Verify(x => x.SetPropertiesAsync()); + } } public class TheSaveFileWithAccessConditionMethod