commit 9d30e9f89595c612700d2d959232b1f8b633873e
parent a8a19c76bff9c2be1e394287ebafe23df16501ff
Author: AmirMS <104940545+AmelBawa-msft@users.noreply.github.com>
Date: Tue, 11 Oct 2022 14:25:14 -0700
Download MSIX installer during manifest validation (if necessary) (#2587)
Diffstat:
2 files changed, 105 insertions(+), 20 deletions(-)
diff --git a/src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp
@@ -2,6 +2,8 @@
// Licensed under the MIT License.
#include "pch.h"
#include "AppInstallerLogging.h"
+#include "AppInstallerRuntime.h"
+#include "AppInstallerDownloader.h"
#include "winget/MsixManifestValidation.h"
namespace AppInstaller::Manifest
@@ -12,7 +14,7 @@ namespace AppInstaller::Manifest
{
std::vector<ValidationError> errors;
Msix::PackageVersion packageVersion(manifest.Version);
- auto msixInfo = GetMsixInfo(installer.Url, errors);
+ auto msixInfo = GetMsixInfo(installer.Url);
if (msixInfo)
{
ValidateMsixManifestSignatureHash(msixInfo, installer.SignatureSha256, errors);
@@ -26,37 +28,110 @@ namespace AppInstaller::Manifest
ValidateMsixManifestMinOSVersion(msixManifest.GetMinimumOSVersionForSupportedPlatforms(), installerMinOSVersion, installer.Url, errors);
}
}
+ else
+ {
+ errors.emplace_back(ManifestError::InstallerFailedToProcess, "InstallerUrl", installer.Url);
+ }
return errors;
}
- std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfo(
- std::string installerUrl,
- std::vector<ValidationError> &errors)
+ std::optional<std::filesystem::path> MsixManifestValidation::DownloadInstaller(std::string installerUrl, int retryCount)
+ {
+ while (retryCount-- > 0)
+ {
+ try
+ {
+ AICLI_LOG(Core, Info, << "Start downloading installer");
+ auto tempFile = Runtime::GetNewTempFilePath();
+ ProgressCallback callback;
+ Utility::Download(installerUrl, tempFile, Utility::DownloadType::Installer, callback);
+ return tempFile;
+ }
+ catch (...)
+ {
+ AICLI_LOG(Core, Error, << "Downloading installer failed. Remaining attempts: " << retryCount);
+ }
+ }
+
+ return std::nullopt;
+ }
+
+ std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfoFromUrl(std::string installerUrl)
{
- std::shared_ptr<Msix::MsixInfo> msixInfo;
try
{
- // Cache Msix info for new installer url
- auto findMsixInfo = m_msixInfoCache.find(installerUrl);
- if (findMsixInfo == m_msixInfoCache.end())
+ AICLI_LOG(Core, Info, << "Fetching Msix info from installer url");
+ return std::make_shared<Msix::MsixInfo>(installerUrl);
+ }
+ catch (...)
+ {
+ AICLI_LOG(Core, Error, << "Error fetching Msix info from the installer url.");
+ return nullptr;
+ }
+ }
+
+ std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfoFromLocalPath(std::string installerUrl)
+ {
+ int maxRetry = 3;
+ std::shared_ptr<Msix::MsixInfo> msixInfo;
+ auto installerPath = DownloadInstaller(installerUrl, maxRetry);
+ if (installerPath.has_value())
+ {
+ try
+ {
+ AICLI_LOG(Core, Info, << "Fetching Msix info from installer local path");
+ msixInfo = std::make_shared<Msix::MsixInfo>(installerPath.value());
+ }
+ catch (...)
+ {
+ AICLI_LOG(Core, Error, << "Error fetching Msix info from the installer local path.");
+ }
+
+ AICLI_LOG(Core, Info, << "Removing downloaded installer");
+ if (!std::filesystem::remove(installerPath.value()))
+ {
+ AICLI_LOG(Core, Warning, << "Failed to remove downloaded installer");
+ }
+ }
+ else
+ {
+ AICLI_LOG(Core, Error, << "Failed to download installer.");
+ }
+
+ return msixInfo;
+ }
+
+ std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfo(std::string installerUrl)
+ {
+ std::shared_ptr<Msix::MsixInfo> msixInfo;
+ // Cache Msix info for new installer url
+ auto findMsixInfo = m_msixInfoCache.find(installerUrl);
+ if (findMsixInfo == m_msixInfoCache.end())
+ {
+ msixInfo = GetMsixInfoFromUrl(installerUrl);
+ if (!msixInfo)
+ {
+ AICLI_LOG(Core, Warning, << "Failed to get Msix info directly from the installer url. "
+ << "Downloading installer instead.");
+ msixInfo = GetMsixInfoFromLocalPath(installerUrl);
+ }
+
+ if (msixInfo)
{
- msixInfo = std::make_shared<Msix::MsixInfo>(installerUrl);
m_msixInfoCache.insert({ installerUrl, msixInfo });
}
else
{
- msixInfo = findMsixInfo->second;
+ AICLI_LOG(Core, Error, << "Msix info could not be obtained.");
}
-
- return msixInfo;
}
- catch (...)
+ else
{
- errors.emplace_back(ManifestError::InstallerFailedToProcess, "InstallerUrl", installerUrl);
+ msixInfo = findMsixInfo->second;
}
- return nullptr;
+ return msixInfo;
}
std::optional<Msix::OSVersion> MsixManifestValidation::GetManifestInstallerMinOSVersion(
diff --git a/src/AppInstallerCommonCore/Public/winget/MsixManifestValidation.h b/src/AppInstallerCommonCore/Public/winget/MsixManifestValidation.h
@@ -20,11 +20,21 @@ namespace AppInstaller::Manifest
std::map<std::string, std::shared_ptr<Msix::MsixInfo>> m_msixInfoCache;
ValidationError::Level m_validationErrorLevel;
- // Get Msix info from installer url, or load it from cache. Return null
- // pointer if failed to process installer url.
- std::shared_ptr<Msix::MsixInfo> GetMsixInfo(
- std::string installerUrl,
- std::vector<ValidationError>& errors);
+ // Get Msix info from url/local path, or load it from cache.
+ // Return null pointer if operation failed.
+ std::shared_ptr<Msix::MsixInfo> GetMsixInfo(std::string installerUrl);
+
+ // Get Msix info from installer url.
+ // Return null pointer if operation failed.
+ std::shared_ptr<Msix::MsixInfo> GetMsixInfoFromUrl(std::string installerUrl);
+
+ // Download and get msix info from installer local path.
+ // Return null pointer if operation failed.
+ std::shared_ptr<Msix::MsixInfo> GetMsixInfoFromLocalPath(std::string installerUrl);
+
+ // Download the installer.
+ // If the download was successful, return the destination path.
+ std::optional<std::filesystem::path> DownloadInstaller(std::string installerUrl, int retryCount);
// Get manifest installer minimum OS version or nullopt if failed to
// parse input.