@@ -293,7 +293,7 @@ namespace AppInstaller::CLI::Workflow
293293
294294 AICLI_LOG (CLI, Info, << " Existing installer file hash matches. Will use existing installer." );
295295 context.Add <Execution::Data::InstallerPath>(installerPath / installerFilename);
296- context.Add <Execution::Data::HashPair >(std::make_pair (installer.Sha256 , fileHash));
296+ context.Add <Execution::Data::DownloadHashInfo >(std::make_pair (installer.Sha256 , DownloadResult{ fileHash } ));
297297 }
298298
299299 void GetInstallerDownloadPath (Execution::Context& context)
@@ -325,7 +325,7 @@ namespace AppInstaller::CLI::Workflow
325325
326326 context.Reporter .Info () << Resource::String::Downloading << ' ' << Execution::UrlEmphasis << installer.Url << std::endl;
327327
328- std::optional<std::vector<BYTE>> hash ;
328+ DownloadResult downloadResult ;
329329
330330 constexpr int MaxRetryCount = 2 ;
331331 constexpr std::chrono::seconds maximumWaitTimeAllowed = 60s;
@@ -334,15 +334,22 @@ namespace AppInstaller::CLI::Workflow
334334 bool success = false ;
335335 try
336336 {
337- hash = context.Reporter .ExecuteWithProgress (std::bind (Utility::Download,
337+ downloadResult = context.Reporter .ExecuteWithProgress (std::bind (Utility::Download,
338338 installer.Url ,
339339 installerPath,
340340 Utility::DownloadType::Installer,
341341 std::placeholders::_1,
342- true ,
343342 downloadInfo));
344343
345- success = true ;
344+ if (downloadResult.SizeInBytes == 0 )
345+ {
346+ AICLI_LOG (CLI, Info, << " Got zero byte file; retrying download after a short wait..." );
347+ std::this_thread::sleep_for (5s);
348+ }
349+ else
350+ {
351+ success = true ;
352+ }
346353 }
347354 catch (const ServiceUnavailableException& sue)
348355 {
@@ -388,13 +395,13 @@ namespace AppInstaller::CLI::Workflow
388395 }
389396 }
390397
391- if (!hash )
398+ if (downloadResult. Sha256Hash . empty () )
392399 {
393400 context.Reporter .Info () << Resource::String::Cancelled << std::endl;
394401 AICLI_TERMINATE_CONTEXT (E_ABORT);
395402 }
396403
397- context.Add <Execution::Data::HashPair >(std::make_pair (installer.Sha256 , hash. value () ));
404+ context.Add <Execution::Data::DownloadHashInfo >(std::make_pair (installer.Sha256 , downloadResult ));
398405 }
399406
400407 void GetMsixSignatureHash (Execution::Context& context)
@@ -410,7 +417,7 @@ namespace AppInstaller::CLI::Workflow
410417 Msix::MsixInfo msixInfo (installer.Url );
411418 auto signatureHash = msixInfo.GetSignatureHash ();
412419
413- context.Add <Execution::Data::HashPair >(std::make_pair (installer.SignatureSha256 , signatureHash));
420+ context.Add <Execution::Data::DownloadHashInfo >(std::make_pair (installer.SignatureSha256 , DownloadResult{ signatureHash } ));
414421 context.Add <Execution::Data::MsixDigests>({ std::make_pair (installer.Url , msixInfo.GetDigest ()) });
415422 }
416423 catch (...)
@@ -427,17 +434,23 @@ namespace AppInstaller::CLI::Workflow
427434
428435 void VerifyInstallerHash (Execution::Context& context)
429436 {
430- const auto & hashPair = context.Get <Execution::Data::HashPair >();
437+ const auto & [expectedHash, downloadResult] = context.Get <Execution::Data::DownloadHashInfo >();
431438
432439 if (!std::equal (
433- hashPair. first .begin (),
434- hashPair. first .end (),
435- hashPair. second .begin ()))
440+ expectedHash .begin (),
441+ expectedHash .end (),
442+ downloadResult. Sha256Hash .begin ()))
436443 {
437444 bool overrideHashMismatch = context.Args .Contains (Execution::Args::Type::HashOverride);
438445
439446 const auto & manifest = context.Get <Execution::Data::Manifest>();
440- Logging::Telemetry ().LogInstallerHashMismatch (manifest.Id , manifest.Version , manifest.Channel , hashPair.first , hashPair.second , overrideHashMismatch);
447+ Logging::Telemetry ().LogInstallerHashMismatch (manifest.Id , manifest.Version , manifest.Channel , expectedHash, downloadResult.Sha256Hash , overrideHashMismatch, downloadResult.SizeInBytes , downloadResult.ContentType );
448+
449+ if (downloadResult.SizeInBytes == 0 )
450+ {
451+ context.Reporter .Error () << Resource::String::InstallerZeroByteFile << std::endl;
452+ AICLI_TERMINATE_CONTEXT (APPINSTALLER_CLI_ERROR_INSTALLER_ZERO_BYTE_FILE);
453+ }
441454
442455 // If running as admin, do not allow the user to override the hash failure.
443456 if (Runtime::IsRunningAsAdmin ())
@@ -527,7 +540,7 @@ namespace AppInstaller::CLI::Workflow
527540 const auto & installerPath = context.Get <Execution::Data::InstallerPath>();
528541 std::ifstream inStream{ installerPath, std::ifstream::binary };
529542 auto existingFileHash = SHA256::ComputeHash (inStream);
530- context.Add <Execution::Data::HashPair >(std::make_pair (installer.Sha256 , existingFileHash));
543+ context.Add <Execution::Data::DownloadHashInfo >(std::make_pair (installer.Sha256 , DownloadResult{ existingFileHash } ));
531544 }
532545 else if (installer.EffectiveInstallerType () == InstallerTypeEnum::MSStore)
533546 {
0 commit comments