Skip to content

Commit 779ef3f

Browse files
committed
Reject broken ZIPs on API push with better message (#7859)
Address NuGet/Engineering#3046
1 parent d855bce commit 779ef3f

6 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/NuGetGallery/Controllers/ApiController.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,21 @@ private async Task<ActionResult> CreatePackageInternal()
549549
Strings.PackageEntryFromTheFuture,
550550
entryInTheFuture.Name));
551551
}
552+
}
553+
catch (Exception ex)
554+
{
555+
// This is not very elegant to catch every Exception type here. However, the types of exceptions
556+
// that could be thrown when reading a garbage ZIP is undocumented. We've seen ArgumentOutOfRangeException
557+
// get thrown from HttpInputStream and InvalidDataException thrown from ZipArchive.
558+
ex.Log();
559+
560+
return new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, string.Format(
561+
CultureInfo.CurrentCulture,
562+
Strings.FailedToReadUploadFile));
563+
}
552564

565+
try
566+
{
553567
using (var packageToPush = new PackageArchiveReader(packageStream, leaveStreamOpen: false))
554568
{
555569
try

src/NuGetGallery/Controllers/PackagesController.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ public virtual async Task<JsonResult> UploadPackage(HttpPostedFileBase uploadFil
396396
}
397397
catch (Exception ex)
398398
{
399+
// This is not very elegant to catch every Exception type here. However, the types of exceptions
400+
// that could be thrown when reading a garbage ZIP is undocumented. We've seen ArgumentOutOfRangeException
401+
// get thrown from HttpInputStream and InvalidDataException thrown from ZipArchive.
399402
return FailedToReadFile(ex);
400403
}
401404
finally

tests/NuGetGallery.Facts/Controllers/ApiControllerFacts.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,25 @@ public async Task CreatePackageReturns400IfEnsureValidThrowsExceptionMessage(Typ
696696
Assert.Equal(expectExceptionMessageInResponse ? EnsureValidExceptionMessage : Strings.FailedToReadUploadFile, (result as HttpStatusCodeWithBodyResult).StatusDescription);
697697
}
698698

699+
[Fact]
700+
public async Task WillRejectBrokenZipFiles()
701+
{
702+
// Arrange
703+
var package = new MemoryStream(TestDataResourceUtility.GetResourceBytes("Zip64Package.Corrupted.1.0.0.nupkg"));
704+
705+
var user = new User() { EmailAddress = "[email protected]" };
706+
var controller = new TestableApiController(GetConfigurationService());
707+
controller.SetCurrentUser(user);
708+
controller.SetupPackageFromInputStream(package);
709+
710+
// Act
711+
ActionResult result = await controller.CreatePackagePut();
712+
713+
// Assert
714+
ResultAssert.IsStatusCode(result, HttpStatusCode.BadRequest);
715+
Assert.Equal(Strings.FailedToReadUploadFile, (result as HttpStatusCodeWithBodyResult).StatusDescription);
716+
}
717+
699718
[Fact]
700719
public async Task CreatePackageReturns400IfMinClientVersionIsTooHigh()
701720
{

tests/NuGetGallery.Facts/Controllers/PackagesControllerFacts.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ private static PackagesController CreateController(
263263
fakeNuGetPackage = TestPackage.CreateTestPackageStream("thePackageId", "1.0.0");
264264
}
265265

266-
controller.Setup(x => x.CreatePackage(It.IsAny<Stream>())).Returns(new PackageArchiveReader(fakeNuGetPackage, true));
266+
controller.Setup(x => x.CreatePackage(It.IsAny<Stream>())).Returns(() => new PackageArchiveReader(fakeNuGetPackage, true));
267267
}
268268

269269
return controller.Object;
@@ -5585,6 +5585,26 @@ public async Task WillShowViewWithErrorsIfEnsureValidThrowsExceptionMessage(Type
55855585
(result.Data as JsonValidationMessage[])[0].PlainTextMessage);
55865586
}
55875587

5588+
[Fact]
5589+
public async Task WillRejectBrokenZipFiles()
5590+
{
5591+
// Arrange
5592+
var fakeUploadedFile = new Mock<HttpPostedFileBase>();
5593+
fakeUploadedFile.Setup(x => x.FileName).Returns("file.nupkg");
5594+
var fakeFileStream = new MemoryStream(TestDataResourceUtility.GetResourceBytes("Zip64Package.Corrupted.1.0.0.nupkg"));
5595+
fakeUploadedFile.Setup(x => x.InputStream).Returns(fakeFileStream);
5596+
5597+
var controller = CreateController(
5598+
GetConfigurationService(),
5599+
fakeNuGetPackage: fakeFileStream);
5600+
controller.SetCurrentUser(TestUtility.FakeUser);
5601+
5602+
var result = await controller.UploadPackage(fakeUploadedFile.Object) as JsonResult;
5603+
5604+
Assert.NotNull(result);
5605+
Assert.Equal("Central Directory corrupt.", (result.Data as JsonValidationMessage[])[0].PlainTextMessage);
5606+
}
5607+
55885608
[Theory]
55895609
[InlineData("ILike*Asterisks")]
55905610
[InlineData("I_.Like.-Separators")]

tests/NuGetGallery.Facts/NuGetGallery.Facts.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@
315315
<EmbeddedResource Include="TestData\certificate.cer" />
316316
<EmbeddedResource Include="TestData\icon.png" />
317317
<EmbeddedResource Include="TestData\icon.jpg" />
318+
<EmbeddedResource Include="TestData\Zip64Package.Corrupted.1.0.0.nupkg" />
318319
</ItemGroup>
319320
<ItemGroup>
320321
<ProjectReference Include="..\..\src\NuGet.Services.Entities\NuGet.Services.Entities.csproj">
Binary file not shown.

0 commit comments

Comments
 (0)