@@ -21,6 +21,7 @@ use anyhow::Result;
2121use base64:: engine:: { Engine , general_purpose:: STANDARD } ;
2222use futures:: { StreamExt , TryFutureExt , TryStreamExt , stream} ;
2323use rattler_conda_types:: { ChannelInfo , PackageRecord , Platform , RepoData , package:: ArchiveType } ;
24+ use rattler_digest:: { HashingWriter , Md5 , Sha256 } ;
2425use rattler_lock:: {
2526 CondaBinaryData , CondaPackageData , LockFile , LockedPackageRef , PypiPackageData , UrlOrPath ,
2627} ;
@@ -433,6 +434,16 @@ fn reqwest_client_from_options(options: &PackOptions) -> Result<ClientWithMiddle
433434 Ok ( client)
434435}
435436
437+ async fn write_all_chunk < W > ( response : & mut reqwest:: Response , dest : & mut W ) -> anyhow:: Result < ( ) >
438+ where
439+ W : tokio:: io:: AsyncWrite + Unpin ,
440+ {
441+ while let Some ( chunk) = response. chunk ( ) . await ? {
442+ dest. write_all ( & chunk) . await ?;
443+ }
444+ Ok ( ( ) )
445+ }
446+
436447/// Download a conda package to a given output directory.
437448async fn download_package (
438449 client : & ClientWithMiddleware ,
@@ -475,8 +486,23 @@ async fn download_package(
475486
476487 tracing:: debug!( "Fetching package {}" , package. location) ;
477488 let mut response = client. get ( url. clone ( ) ) . send ( ) . await ?. error_for_status ( ) ?;
478- while let Some ( chunk) = response. chunk ( ) . await ? {
479- dest. write_all ( & chunk) . await ?;
489+
490+ if let Some ( expected_sha) = package. package_record . sha256 {
491+ let mut dest = HashingWriter :: < _ , Sha256 > :: new ( dest) ;
492+ write_all_chunk ( & mut response, & mut dest) . await ?;
493+ let ( _f, hash) = dest. finalize ( ) ;
494+ if hash != expected_sha {
495+ anyhow:: bail!( "Download {file_name} failed, checksum mismatch" ) ;
496+ }
497+ } else if let Some ( expected_md5) = package. package_record . md5 {
498+ let mut dest = HashingWriter :: < _ , Md5 > :: new ( dest) ;
499+ write_all_chunk ( & mut response, & mut dest) . await ?;
500+ let ( _f, hash) = dest. finalize ( ) ;
501+ if hash != expected_md5 {
502+ anyhow:: bail!( "Download {file_name} failed, checksum mismatch" ) ;
503+ }
504+ } else {
505+ write_all_chunk ( & mut response, & mut dest) . await ?;
480506 }
481507 }
482508 }
0 commit comments