@@ -874,6 +874,43 @@ namespace Aws
874874 handle->SetContentType (getObjectOutcome.GetResult ().GetContentType ());
875875 handle->ChangePartToCompleted (partState, getObjectOutcome.GetResult ().GetETag ());
876876 getObjectOutcome.GetResult ().GetBody ().flush ();
877+
878+ // Validate full object checksum if available
879+ if (!handle->GetChecksum ().empty ()) {
880+ const auto & getResult = getObjectOutcome.GetResult ();
881+ Aws::String actualChecksum;
882+
883+ // Get the actual checksum from GetObject response
884+ if (!getResult.GetChecksumCRC32 ().empty ()) {
885+ actualChecksum = getResult.GetChecksumCRC32 ();
886+ } else if (!getResult.GetChecksumCRC32C ().empty ()) {
887+ actualChecksum = getResult.GetChecksumCRC32C ();
888+ } else if (!getResult.GetChecksumSHA256 ().empty ()) {
889+ actualChecksum = getResult.GetChecksumSHA256 ();
890+ } else if (!getResult.GetChecksumSHA1 ().empty ()) {
891+ actualChecksum = getResult.GetChecksumSHA1 ();
892+ } else if (!getResult.GetChecksumCRC64NVME ().empty ()) {
893+ actualChecksum = getResult.GetChecksumCRC64NVME ();
894+ }
895+
896+ if (!actualChecksum.empty () && actualChecksum != handle->GetChecksum ()) {
897+ Aws::Client::AWSError<Aws::S3::S3Errors> checksumError (
898+ Aws::S3::S3Errors::INTERNAL_FAILURE,
899+ " ChecksumMismatch" ,
900+ " Full object checksum validation failed" ,
901+ false );
902+ AWS_LOGSTREAM_ERROR (CLASS_TAG, " Transfer handle [" << handle->GetId ()
903+ << " ] Checksum validation failed. Expected: " << handle->GetChecksum ()
904+ << " , Actual: " << actualChecksum);
905+ handle->ChangePartToFailed (partState);
906+ handle->UpdateStatus (TransferStatus::FAILED);
907+ handle->SetError (checksumError);
908+ TriggerErrorCallback (handle, checksumError);
909+ TriggerTransferStatusUpdatedCallback (handle);
910+ return ;
911+ }
912+ }
913+
877914 handle->UpdateStatus (TransferStatus::COMPLETED);
878915 }
879916 else
@@ -936,6 +973,23 @@ namespace Aws
936973 handle->SetContentType (headObjectOutcome.GetResult ().GetContentType ());
937974 handle->SetMetadata (headObjectOutcome.GetResult ().GetMetadata ());
938975 handle->SetEtag (headObjectOutcome.GetResult ().GetETag ());
976+
977+ // Store full object checksum from HeadObject for validation
978+ const auto & headResult = headObjectOutcome.GetResult ();
979+ if (headResult.GetChecksumType () == Aws::S3::Model::ChecksumType::FULL_OBJECT) {
980+ if (!headResult.GetChecksumCRC32 ().empty ()) {
981+ handle->SetChecksum (headResult.GetChecksumCRC32 ());
982+ } else if (!headResult.GetChecksumCRC32C ().empty ()) {
983+ handle->SetChecksum (headResult.GetChecksumCRC32C ());
984+ } else if (!headResult.GetChecksumSHA256 ().empty ()) {
985+ handle->SetChecksum (headResult.GetChecksumSHA256 ());
986+ } else if (!headResult.GetChecksumSHA1 ().empty ()) {
987+ handle->SetChecksum (headResult.GetChecksumSHA1 ());
988+ } else if (!headResult.GetChecksumCRC64NVME ().empty ()) {
989+ handle->SetChecksum (headResult.GetChecksumCRC64NVME ());
990+ }
991+ }
992+
939993 /* When bucket versioning is suspended, head object will return "null" for unversioned object.
940994 * Send following GetObject with "null" as versionId will result in 403 access denied error if your IAM role or policy
941995 * doesn't have GetObjectVersion permission.
@@ -1117,6 +1171,20 @@ namespace Aws
11171171
11181172 Aws::String errMsg{handle->WritePartToDownloadStream (bufferStream, partState->GetRangeBegin ())};
11191173 if (errMsg.empty ()) {
1174+ // Store part checksum for later validation
1175+ const auto & getResult = outcome.GetResult ();
1176+ if (!getResult.GetChecksumCRC32 ().empty ()) {
1177+ partState->SetChecksum (getResult.GetChecksumCRC32 ());
1178+ } else if (!getResult.GetChecksumCRC32C ().empty ()) {
1179+ partState->SetChecksum (getResult.GetChecksumCRC32C ());
1180+ } else if (!getResult.GetChecksumSHA256 ().empty ()) {
1181+ partState->SetChecksum (getResult.GetChecksumSHA256 ());
1182+ } else if (!getResult.GetChecksumSHA1 ().empty ()) {
1183+ partState->SetChecksum (getResult.GetChecksumSHA1 ());
1184+ } else if (!getResult.GetChecksumCRC64NVME ().empty ()) {
1185+ partState->SetChecksum (getResult.GetChecksumCRC64NVME ());
1186+ }
1187+
11201188 handle->ChangePartToCompleted (partState, outcome.GetResult ().GetETag ());
11211189 } else {
11221190 Aws::Client::AWSError<Aws::S3::S3Errors> error (Aws::S3::S3Errors::INTERNAL_FAILURE,
@@ -1153,6 +1221,35 @@ namespace Aws
11531221 if (failedParts.size () == 0 && handle->GetBytesTransferred () == handle->GetBytesTotalSize ())
11541222 {
11551223 outcome.GetResult ().GetBody ().flush ();
1224+
1225+ // Validate full object checksum if available
1226+ if (!handle->GetChecksum ().empty ()) {
1227+ // For now, we'll do a simple validation - in a full implementation,
1228+ // we would combine part checksums using the appropriate algorithm
1229+ bool checksumValid = true ;
1230+
1231+ // TODO: Implement proper checksum combination logic
1232+ // For CRC32, we would need to combine all part checksums
1233+ // For now, we'll just log that validation should happen here
1234+ AWS_LOGSTREAM_DEBUG (CLASS_TAG, " Transfer handle [" << handle->GetId ()
1235+ << " ] Full object checksum validation needed but not yet implemented for multipart downloads" );
1236+
1237+ if (!checksumValid) {
1238+ Aws::Client::AWSError<Aws::S3::S3Errors> checksumError (
1239+ Aws::S3::S3Errors::INTERNAL_FAILURE,
1240+ " ChecksumMismatch" ,
1241+ " Full object checksum validation failed" ,
1242+ false );
1243+ AWS_LOGSTREAM_ERROR (CLASS_TAG, " Transfer handle [" << handle->GetId ()
1244+ << " ] Multipart checksum validation failed" );
1245+ handle->UpdateStatus (TransferStatus::FAILED);
1246+ handle->SetError (checksumError);
1247+ TriggerErrorCallback (handle, checksumError);
1248+ TriggerTransferStatusUpdatedCallback (handle);
1249+ return ;
1250+ }
1251+ }
1252+
11561253 handle->UpdateStatus (TransferStatus::COMPLETED);
11571254 }
11581255 else
0 commit comments