@@ -14,7 +14,17 @@ const {
1414 UploadPartCommand,
1515 CompleteMultipartUploadCommand,
1616} = require ( '@aws-sdk/client-s3' ) ;
17+ // In older versions of @aws -sdk/middleware-flexible-checksums (<3.972), the
18+ // CRC64NVME implementation must be patched in manually from the CRT package.
19+ // Newer versions handle this internally via @aws -sdk/crc64-nvme, so the export
20+ // no longer exists and no registration is needed.
21+ const { crc64NvmeCrtContainer } = require ( '@aws-sdk/middleware-flexible-checksums' ) ;
22+ if ( crc64NvmeCrtContainer ) {
23+ const { CrtCrc64Nvme } = require ( '@aws-sdk/crc64-nvme-crt' ) ;
24+ crc64NvmeCrtContainer . CrtCrc64Nvme = CrtCrc64Nvme ;
25+ }
1726
27+ const { algorithms } = require ( '../../../../../lib/api/apiUtils/integrity/validateChecksums' ) ;
1828const changeObjectLock = require ( '../../../../utilities/objectLock-util' ) ;
1929const withV4 = require ( '../support/withV4' ) ;
2030const BucketUtility = require ( '../../lib/utility/bucket-util' ) ;
@@ -538,6 +548,100 @@ describe('HEAD object, conditions', () => {
538548 } ) ;
539549} ) ;
540550
551+ describe ( 'HEAD object checksum mode' , ( ) => {
552+ withV4 ( sigCfg => {
553+ let bucketUtil ;
554+ let s3 ;
555+ const checksumBucket = 'checksum-headobject-test' ;
556+ const checksumKey = 'checksum-test-object' ;
557+ const body = Buffer . from ( 'checksum test body' ) ;
558+
559+ // Expected base64-encoded digests of `body` for each algorithm,
560+ // computed once in the before hook (crc64nvme digest is async).
561+ const expectedDigests = { } ;
562+
563+ before ( async ( ) => {
564+ bucketUtil = new BucketUtility ( 'default' , sigCfg ) ;
565+ s3 = bucketUtil . s3 ;
566+ await s3 . send ( new CreateBucketCommand ( { Bucket : checksumBucket } ) ) ;
567+
568+ for ( const { internalName } of checksumAlgorithms ) {
569+ // algorithms[internalName].digest() returns a base64 string
570+ expectedDigests [ internalName ] =
571+ await algorithms [ internalName ] . digest ( body ) ;
572+ }
573+ } ) ;
574+
575+ after ( async ( ) => {
576+ await bucketUtil . empty ( checksumBucket ) ;
577+ await s3 . send ( new DeleteBucketCommand ( { Bucket : checksumBucket } ) ) ;
578+ } ) ;
579+
580+ const checksumAlgorithms = [
581+ { algorithm : 'SHA256' , responseField : 'ChecksumSHA256' , internalName : 'sha256' } ,
582+ { algorithm : 'SHA1' , responseField : 'ChecksumSHA1' , internalName : 'sha1' } ,
583+ { algorithm : 'CRC32' , responseField : 'ChecksumCRC32' , internalName : 'crc32' } ,
584+ { algorithm : 'CRC32C' , responseField : 'ChecksumCRC32C' , internalName : 'crc32c' } ,
585+ { algorithm : 'CRC64NVME' , responseField : 'ChecksumCRC64NVME' , internalName : 'crc64nvme' } ,
586+ ] ;
587+
588+ checksumAlgorithms . forEach ( ( { algorithm, responseField, internalName } ) => {
589+ it ( `should return ${ responseField } and ChecksumType when ChecksumMode is ENABLED` , async ( ) => {
590+ const putRes = await s3 . send ( new PutObjectCommand ( {
591+ Bucket : checksumBucket ,
592+ Key : checksumKey ,
593+ Body : body ,
594+ ChecksumAlgorithm : algorithm ,
595+ } ) ) ;
596+ const storedChecksum = putRes [ responseField ] ;
597+ assert ( storedChecksum , `Expected ${ responseField } in PutObject response` ) ;
598+
599+ const headRes = await s3 . send ( new HeadObjectCommand ( {
600+ Bucket : checksumBucket ,
601+ Key : checksumKey ,
602+ ChecksumMode : 'ENABLED' ,
603+ } ) ) ;
604+ assert . strictEqual ( headRes [ responseField ] , expectedDigests [ internalName ] ,
605+ `${ responseField } value mismatch` ) ;
606+ assert . strictEqual ( headRes [ responseField ] , storedChecksum ) ;
607+ assert . strictEqual ( headRes . ChecksumType , 'FULL_OBJECT' ) ;
608+ } ) ;
609+ } ) ;
610+
611+ it ( 'should not return checksum headers when ChecksumMode is not set' , async ( ) => {
612+ await s3 . send ( new PutObjectCommand ( {
613+ Bucket : checksumBucket ,
614+ Key : checksumKey ,
615+ Body : body ,
616+ ChecksumAlgorithm : 'SHA256' ,
617+ } ) ) ;
618+
619+ const headRes = await s3 . send ( new HeadObjectCommand ( {
620+ Bucket : checksumBucket ,
621+ Key : checksumKey ,
622+ } ) ) ;
623+ assert . strictEqual ( headRes . ChecksumSHA256 , undefined ) ;
624+ assert . strictEqual ( headRes . ChecksumType , undefined ) ;
625+ } ) ;
626+
627+ it ( 'should return an error when ChecksumMode is not ENABLED' , async ( ) => {
628+ await s3 . send ( new PutObjectCommand ( {
629+ Bucket : checksumBucket ,
630+ Key : checksumKey ,
631+ Body : body ,
632+ } ) ) ;
633+
634+ await assert . rejects (
635+ s3 . send ( new HeadObjectCommand ( {
636+ Bucket : checksumBucket ,
637+ Key : checksumKey ,
638+ ChecksumMode : 'DISABLED' ,
639+ } ) ) ,
640+ ) ;
641+ } ) ;
642+ } ) ;
643+ } ) ;
644+
541645const isCEPH = process . env . CI_CEPH !== undefined ;
542646const describeSkipIfCeph = isCEPH ? describe . skip : describe ;
543647
0 commit comments