Skip to content

Commit 556e915

Browse files
authored
Add cache control for nupkgs/snupks in public containers (#6634)
1 parent 95cbe09 commit 556e915

2 files changed

Lines changed: 86 additions & 12 deletions

File tree

src/NuGetGallery.Core/Services/CloudBlobCoreFileStorageService.cs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ public async Task<bool> FileExistsAsync(string folderName, string fileName)
7171

7272
public async Task<Stream> GetFileAsync(string folderName, string fileName)
7373
{
74-
if (String.IsNullOrWhiteSpace(folderName))
74+
if (string.IsNullOrWhiteSpace(folderName))
7575
{
7676
throw new ArgumentNullException(nameof(folderName));
7777
}
7878

79-
if (String.IsNullOrWhiteSpace(fileName))
79+
if (string.IsNullOrWhiteSpace(fileName))
8080
{
8181
throw new ArgumentNullException(nameof(fileName));
8282
}
@@ -86,12 +86,12 @@ public async Task<Stream> GetFileAsync(string folderName, string fileName)
8686

8787
public async Task<IFileReference> GetFileReferenceAsync(string folderName, string fileName, string ifNoneMatch = null)
8888
{
89-
if (String.IsNullOrWhiteSpace(folderName))
89+
if (string.IsNullOrWhiteSpace(folderName))
9090
{
9191
throw new ArgumentNullException(nameof(folderName));
9292
}
9393

94-
if (String.IsNullOrWhiteSpace(fileName))
94+
if (string.IsNullOrWhiteSpace(fileName))
9595
{
9696
throw new ArgumentNullException(nameof(fileName));
9797
}
@@ -243,7 +243,7 @@ await destBlob.StartCopyAsync(
243243
catch (StorageException ex) when (ex.IsFileAlreadyExistsException())
244244
{
245245
throw new FileAlreadyExistsException(
246-
String.Format(
246+
string.Format(
247247
CultureInfo.CurrentCulture,
248248
"There is already a blob with name {0} in container {1}.",
249249
destFileName,
@@ -276,6 +276,17 @@ await destBlob.StartCopyAsync(
276276
throw new StorageException($"The blob copy operation had copy status {destBlob.CopyState.Status} ({destBlob.CopyState.StatusDescription}).");
277277
}
278278

279+
var cacheControl = GetCacheControlForCopy(destFolderName);
280+
if (!string.IsNullOrEmpty(cacheControl))
281+
{
282+
await destBlob.FetchAttributesAsync();
283+
if (string.IsNullOrEmpty(destBlob.Properties.CacheControl))
284+
{
285+
destBlob.Properties.CacheControl = cacheControl;
286+
await destBlob.SetPropertiesAsync();
287+
}
288+
}
289+
279290
return srcBlob.ETag;
280291
}
281292

@@ -316,7 +327,7 @@ public async Task SaveFileAsync(string folderName, string fileName, string conte
316327
catch (StorageException ex) when (ex.IsFileAlreadyExistsException())
317328
{
318329
throw new FileAlreadyExistsException(
319-
String.Format(
330+
string.Format(
320331
CultureInfo.CurrentCulture,
321332
"There is already a blob with name {0} in container {1}.",
322333
fileName,
@@ -349,7 +360,7 @@ public async Task SaveFileAsync(string folderName, string fileName, Stream file,
349360
catch (StorageException ex) when (ex.IsFileAlreadyExistsException())
350361
{
351362
throw new FileAlreadyExistsException(
352-
String.Format(
363+
string.Format(
353364
CultureInfo.CurrentCulture,
354365
"There is already a blob with name {0} in container {1}.",
355366
fileName,
@@ -508,7 +519,7 @@ private bool IsPublicContainer(string folderName)
508519
}
509520

510521
throw new InvalidOperationException(
511-
String.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName));
522+
string.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName));
512523
}
513524

514525
private async Task<StorageResult> GetBlobContentAsync(string folderName, string fileName, string ifNoneMatch = null)
@@ -591,7 +602,20 @@ private static string GetContentType(string folderName)
591602

592603
default:
593604
throw new InvalidOperationException(
594-
String.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName));
605+
string.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName));
606+
}
607+
}
608+
609+
private static string GetCacheControlForCopy(string folderName)
610+
{
611+
switch (folderName)
612+
{
613+
case CoreConstants.PackagesFolderName:
614+
case CoreConstants.SymbolPackagesFolderName:
615+
return CoreConstants.DefaultCacheControl;
616+
617+
default:
618+
return null;
595619
}
596620
}
597621

@@ -602,11 +626,11 @@ private static string GetCacheControl(string folderName)
602626
case CoreConstants.PackagesFolderName:
603627
case CoreConstants.SymbolPackagesFolderName:
604628
case CoreConstants.PackagesContentFolderName:
629+
case CoreConstants.ValidationFolderName:
605630
return CoreConstants.DefaultCacheControl;
606631

607632
case CoreConstants.PackageBackupsFolderName:
608633
case CoreConstants.UploadsFolderName:
609-
case CoreConstants.ValidationFolderName:
610634
case CoreConstants.SymbolPackageBackupsFolderName:
611635
case CoreConstants.DownloadsFolderName:
612636
case CoreConstants.PackageReadMesFolderName:
@@ -618,7 +642,7 @@ private static string GetCacheControl(string folderName)
618642

619643
default:
620644
throw new InvalidOperationException(
621-
String.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName));
645+
string.Format(CultureInfo.CurrentCulture, "The folder name {0} is not supported.", folderName));
622646
}
623647
}
624648

tests/NuGetGallery.Core.Facts/Services/CloudBlobCoreFileStorageServiceFacts.cs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,9 @@ public async Task WillSetTheBlobControlCacheOnPackagesFolder(string folderName)
536536

537537
fakeBlob.Verify();
538538

539-
if (folderName == CoreConstants.PackagesFolderName || folderName == CoreConstants.SymbolPackagesFolderName)
539+
if (folderName == CoreConstants.PackagesFolderName
540+
|| folderName == CoreConstants.SymbolPackagesFolderName
541+
|| folderName == CoreConstants.ValidationFolderName)
540542
{
541543
Assert.Equal(CoreConstants.DefaultCacheControl, fakeBlob.Object.Properties.CacheControl);
542544
}
@@ -1065,6 +1067,54 @@ await _target.CopyFileAsync(
10651067
Times.Once);
10661068
}
10671069

1070+
[Theory]
1071+
[InlineData(CoreConstants.PackagesFolderName)]
1072+
[InlineData(CoreConstants.SymbolPackagesFolderName)]
1073+
public async Task WillCopyAndSetCacheControlOnCopyForFolder(string folderName)
1074+
{
1075+
// Arrange
1076+
var instance = new TheCopyFileAsyncMethod();
1077+
instance._blobClient
1078+
.Setup(x => x.GetBlobFromUri(It.IsAny<Uri>()))
1079+
.Returns(instance._srcBlobMock.Object);
1080+
instance._blobClient
1081+
.Setup(x => x.GetContainerReference(folderName))
1082+
.Returns(() => instance._destContainer.Object);
1083+
1084+
instance._destBlobMock
1085+
.Setup(x => x.StartCopyAsync(It.IsAny<ISimpleCloudBlob>(), It.IsAny<AccessCondition>(), It.IsAny<AccessCondition>()))
1086+
.Returns(Task.FromResult(0))
1087+
.Callback<ISimpleCloudBlob, AccessCondition, AccessCondition>((_, __, ___) =>
1088+
{
1089+
SetDestCopyStatus(CopyStatus.Success);
1090+
});
1091+
1092+
// Act
1093+
await instance._target.CopyFileAsync(
1094+
instance._srcUri,
1095+
folderName,
1096+
instance._destFileName,
1097+
AccessConditionWrapper.GenerateIfNotExistsCondition());
1098+
1099+
// Assert
1100+
instance._destBlobMock.Verify(
1101+
x => x.StartCopyAsync(instance._srcBlobMock.Object, It.IsAny<AccessCondition>(), It.IsAny<AccessCondition>()),
1102+
Times.Once);
1103+
instance._destBlobMock.Verify(
1104+
x => x.StartCopyAsync(It.IsAny<ISimpleCloudBlob>(), It.IsAny<AccessCondition>(), It.IsAny<AccessCondition>()),
1105+
Times.Once);
1106+
instance._destBlobMock.Verify(
1107+
x => x.SetPropertiesAsync(),
1108+
Times.Once);
1109+
instance._destBlobMock.Verify(
1110+
x => x.StartCopyAsync(It.IsAny<ISimpleCloudBlob>(), It.IsAny<AccessCondition>(), It.IsAny<AccessCondition>()),
1111+
Times.Once);
1112+
Assert.NotNull(instance._destProperties.CacheControl);
1113+
instance._blobClient.Verify(
1114+
x => x.GetBlobFromUri(instance._srcUri),
1115+
Times.Once);
1116+
}
1117+
10681118
[Fact]
10691119
public async Task WillCopyTheFileIfDestinationDoesNotExist()
10701120
{

0 commit comments

Comments
 (0)