public void HttpStreamValidation_ValidateNupkg_RejectsPartialNupkg() { // Arrange using (var zipStream = new MemoryStream()) using (var stream = new MemoryStream()) { using (var zip = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true)) { zip.AddEntry("package.nuspec", new byte[0]); } zipStream.Seek(0, SeekOrigin.Begin); var partialLength = (int)zipStream.Length - 1; stream.Write(zipStream.ToArray(), 0, partialLength); stream.Seek(0, SeekOrigin.Begin); // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateNupkg( Uri, stream); }); Assert.IsType <InvalidDataException>(actual.InnerException); } }
public void HttpStreamValidation_ValidateNupkg_RejectsNupkgWithBadPrefix() { // Arrange using (var zipStream = new MemoryStream()) using (var stream = new MemoryStream()) { using (var zip = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true)) { zip.AddEntry("package.nuspec", new byte[0]); } zipStream.Seek(0, SeekOrigin.Begin); var badPrefix = Encoding.ASCII.GetBytes("bad!!!"); stream.Write(badPrefix, 0, badPrefix.Length); zipStream.CopyTo(stream); stream.Seek(0, SeekOrigin.Begin); // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateNupkg( Uri, stream); }); Assert.IsType <InvalidDataException>(actual.InnerException); } }
private async Task <SortedDictionary <NuGetVersion, PackageInfo> > FindPackagesByIdAsync(string id, CancellationToken cancellationToken) { for (var retry = 0; retry != 3; ++retry) { var baseUri = _baseUris[retry % _baseUris.Count].OriginalString; var uri = baseUri + id.ToLowerInvariant() + "/index.json"; try { using (var result = await _httpSource.GetAsync( uri, $"list_{id}", CreateCacheContext(retry), Logger, ignoreNotFounds: true, ensureValidContents: stream => HttpStreamValidation.ValidateJObject(uri, stream), cancellationToken: cancellationToken)) { if (result.Status == HttpSourceResultStatus.NotFound) { return(new SortedDictionary <NuGetVersion, PackageInfo>()); } try { return(ConsumeFlatContainerIndex(result.Stream, id, baseUri)); } catch { Logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_FileIsCorrupt, result.CacheFileName)); throw; } } } catch (Exception ex) when(retry < 2) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_RetryingFindPackagesById, nameof(FindPackagesByIdAsync), uri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); Logger.LogMinimal(message); } catch (Exception ex) when(retry == 2) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToRetrievePackage, uri); Logger.LogError(message + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex)); throw new FatalProtocolException(message, ex); } } return(null); }
public void HttpStreamValidation_ValidateJObject_AcceptsMinimal() { // Arrange var stream = new MemoryStream(Encoding.UTF8.GetBytes(@" { ""foo"": 1, ""bar"": 2 }")); // Act & Assert HttpStreamValidation.ValidateJObject(Uri, stream); }
public void HttpStreamValidation_ValidateJObject_RejectsJsonArray() { // Arrange var stream = new MemoryStream(Encoding.UTF8.GetBytes("[1, 2]")); // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateJObject(Uri, stream); }); Assert.IsType <JsonReaderException>(actual.InnerException); }
public void HttpStreamValidation_ValidateXml_AcceptsMinimal() { // Arrange using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?> <entry> </entry> "))) { // Act & Assert HttpStreamValidation.ValidateXml( Uri, stream); } }
public void HttpStreamValidation_ValidateNupkg_RejectsCompletelyInvalidZipNupkg() { // Arrange using (var stream = new MemoryStream(Encoding.ASCII.GetBytes("not a zip!"))) { // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateNupkg( Uri, stream); }); Assert.IsType <InvalidDataException>(actual.InnerException); } }
public void HttpStreamValidation_ValidateJObject_RejectsIncompleteJsonObjects() { // Arrange var stream = new MemoryStream(Encoding.UTF8.GetBytes(@" { ""foo"": 1, ""bar"": 2")); // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateJObject(Uri, stream); }); Assert.IsType <JsonReaderException>(actual.InnerException); }
private async Task <NupkgEntry> OpenNupkgStreamAsyncCore(PackageInfo package, CancellationToken cancellationToken) { for (var retry = 0; retry != 3; ++retry) { try { using (var data = await _httpSource.GetAsync( package.ContentUri, "nupkg_" + package.Id + "." + package.Version, CreateCacheContext(retry), Logger, ignoreNotFounds: false, ensureValidContents: stream => HttpStreamValidation.ValidateNupkg(package.ContentUri, stream), cancellationToken: cancellationToken)) { return(new NupkgEntry { TempFileName = data.CacheFileName }); } } catch (TaskCanceledException) when(retry < 2) { // Requests can get cancelled if we got the data from elsewhere, no reason to warn. string message = string.Format(CultureInfo.CurrentCulture, Strings.Log_CanceledNupkgDownload, package.ContentUri); Logger.LogMinimal(message); } catch (Exception ex) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, package.ContentUri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); if (retry == 2) { Logger.LogError(message); } else { Logger.LogMinimal(message); } } } return(null); }
public void HttpStreamValidation_ValidateXml_RejectsIncompleteBroken() { // Arrange using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?> <entry> <another> "))) { // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateXml( Uri, stream); }); Assert.IsType <XmlException>(actual.InnerException); } }
public void HttpStreamValidation_ValidateNupkg_AcceptsMinimalNupkg() { // Arrange using (var stream = new MemoryStream()) { using (var zip = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true)) { zip.AddEntry("package.nuspec", @"<?xml version=""1.0"" encoding=""utf-8""?> <package> </package>"); } stream.Seek(0, SeekOrigin.Begin); // Act & Assert HttpStreamValidation.ValidateNupkg( Uri, stream); } }
private async Task <NupkgEntry> OpenNupkgStreamAsyncCore(RemoteSourceDependencyInfo package, CancellationToken cancellationToken) { for (var retry = 0; retry != 3; ++retry) { try { using (var data = await _httpSource.GetAsync( package.ContentUri, "nupkg_" + package.Identity.Id + "." + package.Identity.Version.ToNormalizedString(), CreateCacheContext(retry), Logger, ignoreNotFounds: false, ensureValidContents: stream => HttpStreamValidation.ValidateNupkg(package.ContentUri, stream), cancellationToken: cancellationToken)) { return(new NupkgEntry { TempFileName = data.CacheFileName }); } } catch (Exception ex) when(retry < 2) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, package.ContentUri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); Logger.LogMinimal(message); } catch (Exception ex) when(retry == 2) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, package.ContentUri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); Logger.LogError(message); } } return(null); }
public void HttpStreamValidation_ValidateNupkg_RejectsBrokenNuspec() { // Arrange using (var stream = new MemoryStream()) { using (var zip = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true)) { zip.AddEntry("package.nuspec", new byte[0]); } stream.Seek(0, SeekOrigin.Begin); // Act & Assert var actual = Assert.Throws <InvalidDataException>(() => { HttpStreamValidation.ValidateNupkg( Uri, stream); }); Assert.IsType <XmlException>(actual.InnerException); } }
private async Task <IEnumerable <PackageInfo> > FindPackagesByIdAsyncCore(string id, CancellationToken cancellationToken) { for (var retry = 0; retry != 3; ++retry) { var uri = _baseUri + "FindPackagesById()?id='" + id + "'"; try { var results = new List <PackageInfo>(); var page = 1; while (true) { // TODO: Pages for a package Id are cached separately. // So we will get inaccurate data when a page shrinks. // However, (1) In most cases the pages grow rather than shrink; // (2) cache for pages is valid for only 30 min. // So we decide to leave current logic and observe. using (var data = await _httpSource.GetAsync( uri, new[] { new MediaTypeWithQualityHeaderValue("application/atom+xml"), new MediaTypeWithQualityHeaderValue("application/xml") }, $"list_{id}_page{page}", CreateCacheContext(retry), Logger, ignoreNotFounds: false, ensureValidContents: stream => HttpStreamValidation.ValidateXml(uri, stream), cancellationToken: cancellationToken)) { if (data.Status == HttpSourceResultStatus.NoContent) { // Team city returns 204 when no versions of the package exist // This should result in an empty list and we should not try to // read the stream as xml. break; } var doc = V2FeedParser.LoadXml(data.Stream); var result = doc.Root .Elements(_xnameEntry) .Select(x => BuildModel(id, x)) .Where(x => x != null); results.AddRange(result); // Find the next url for continuation var nextUri = V2FeedParser.GetNextUrl(doc); // Stop if there's nothing else to GET if (string.IsNullOrEmpty(nextUri)) { break; } uri = nextUri; page++; } } return(results); } catch (Exception ex) when(retry < 2) { string message = string.Format(CultureInfo.CurrentCulture, Strings.Log_RetryingFindPackagesById, nameof(FindPackagesByIdAsyncCore), uri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); Logger.LogMinimal(message); } catch (Exception ex) when(retry == 2) { // Fail silently by returning empty result list var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToRetrievePackage, uri); Logger.LogError(message + Environment.NewLine + ex.Message); throw new FatalProtocolException(message, ex); } } return(null); }