From a6adc2d737e437728bf89f61857af4394c3312fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20DONNART?= Date: Wed, 8 Jul 2026 19:02:34 +0200 Subject: [PATCH] Show onward replication status on replicas Report the onward status (PENDING/PROCESSING/FAILED) instead of always REPLICA, and add x-amz-meta-replica to keep the replica flag visible. Issue: CLDSRV-931 --- lib/utilities/collectResponseHeaders.js | 8 +++-- tests/unit/utils/collectResponseHeaders.js | 38 ++++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/lib/utilities/collectResponseHeaders.js b/lib/utilities/collectResponseHeaders.js index 8480cf8d9f..99f3b6bba3 100644 --- a/lib/utilities/collectResponseHeaders.js +++ b/lib/utilities/collectResponseHeaders.js @@ -91,8 +91,12 @@ function collectResponseHeaders(objectMD, corsHeaders, versioningCfg, returnTagC } if (objectMD.replicationInfo) { const { isReplica, status } = objectMD.replicationInfo; - if (isReplica || status) { - responseMetaHeaders['x-amz-replication-status'] = isReplica ? 'REPLICA' : status; + if (isReplica) { + const hasReplicated = !status || status === 'COMPLETED'; + responseMetaHeaders['x-amz-replication-status'] = hasReplicated ? 'REPLICA' : status; + responseMetaHeaders['x-amz-meta-scal-replica'] = 'true'; + } else if (status) { + responseMetaHeaders['x-amz-replication-status'] = status; } } if (Array.isArray(objectMD?.replicationInfo?.backends)) { diff --git a/tests/unit/utils/collectResponseHeaders.js b/tests/unit/utils/collectResponseHeaders.js index de17b64321..5dd59103ba 100644 --- a/tests/unit/utils/collectResponseHeaders.js +++ b/tests/unit/utils/collectResponseHeaders.js @@ -8,12 +8,46 @@ describe('Middleware: Collect Response Headers', () => { assert.deepStrictEqual(headers['x-amz-replication-status'], 'REPLICA'); }); - it('should set REPLICA header from isReplica even when status is PENDING', () => { + it('should mark a replica with x-amz-meta-scal-replica', () => { const objectMD = { - replicationInfo: { status: 'PENDING', isReplica: true }, + replicationInfo: { status: 'REPLICA', isReplica: true }, }; const headers = collectResponseHeaders(objectMD); assert.deepStrictEqual(headers['x-amz-replication-status'], 'REPLICA'); + assert.deepStrictEqual(headers['x-amz-meta-scal-replica'], 'true'); + }); + + it('should default to REPLICA when isReplica is true and status is absent', () => { + const objectMD = { replicationInfo: { isReplica: true } }; + const headers = collectResponseHeaders(objectMD); + assert.deepStrictEqual(headers['x-amz-replication-status'], 'REPLICA'); + assert.deepStrictEqual(headers['x-amz-meta-scal-replica'], 'true'); + }); + + ['PENDING', 'PROCESSING', 'FAILED'].forEach(status => { + it(`should expose onward status ${status} on a cascaded replica`, () => { + const objectMD = { replicationInfo: { status, isReplica: true } }; + const headers = collectResponseHeaders(objectMD); + assert.deepStrictEqual(headers['x-amz-replication-status'], status); + assert.deepStrictEqual(headers['x-amz-meta-scal-replica'], 'true'); + }); + }); + + it('should report REPLICA once onward replication is COMPLETED', () => { + const objectMD = { + replicationInfo: { status: 'COMPLETED', isReplica: true }, + }; + const headers = collectResponseHeaders(objectMD); + assert.deepStrictEqual(headers['x-amz-replication-status'], 'REPLICA'); + assert.deepStrictEqual(headers['x-amz-meta-scal-replica'], 'true'); + }); + + it('should not mark x-amz-meta-scal-replica when not a replica', () => { + const objectMD = { + replicationInfo: { status: 'PENDING', isReplica: false }, + }; + const headers = collectResponseHeaders(objectMD); + assert.deepStrictEqual(headers['x-amz-meta-scal-replica'], undefined); }); it('should use replicationInfo.status when isReplica is false', () => {