Skip to content

Commit 2eefc85

Browse files
committed
Handle single Contents element in ListObjectsV2 XML parsing
Issue: CLDSRVCLT-12
1 parent 2fe8683 commit 2eefc85

2 files changed

Lines changed: 57 additions & 1 deletion

File tree

src/commands/s3Extended/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function parseListObjectsUserMetadataMiddleware(captured: { xml: string }
7575
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7676
return (next: any) => async (args: any) => {
7777
const result = await next(args);
78-
const parsed = new XMLParser().parse(captured.xml);
78+
const parsed = new XMLParser({ isArray: name => name === 'Contents' }).parse(captured.xml);
7979
const xmlContents = parsed?.ListBucketResult?.Contents;
8080
if (result.output.Contents && xmlContents) {
8181
for (let i = 0; i < result.output.Contents.length; i++) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { parseListObjectsUserMetadataMiddleware } from '../../../src/commands/s3Extended/utils';
2+
3+
describe('parseListObjectsUserMetadataMiddleware', () => {
4+
function buildXml(contents: Record<string, string>[]): string {
5+
const inner = contents.map(obj => `<Contents>${
6+
Object.entries(obj).map(([k, v]) => `<${k}>${v}</${k}>`).join('')
7+
}</Contents>`).join('');
8+
return `<ListBucketResult>${inner}</ListBucketResult>`;
9+
}
10+
11+
function createNext(output: unknown) {
12+
return async () => ({ output });
13+
}
14+
15+
it('should extract user metadata when XML contains a single Contents element', async () => {
16+
const captured = {
17+
xml: buildXml([
18+
{ 'Key': 'obj1', 'x-amz-meta-foo': 'bar' },
19+
]),
20+
};
21+
22+
const middleware = parseListObjectsUserMetadataMiddleware(captured);
23+
const result = await middleware(createNext({
24+
Contents: [{ Key: 'obj1' }],
25+
}))({ request: {} });
26+
expect(result.output.Contents[0]['x-amz-meta-foo']).toBe('bar');
27+
});
28+
29+
it('should extract user metadata when XML contains multiple Contents elements', async () => {
30+
const captured = {
31+
xml: buildXml([
32+
{ 'Key': 'obj1', 'x-amz-meta-foo': 'bar' },
33+
{ 'Key': 'obj2', 'x-amz-meta-foo': 'baz' },
34+
]),
35+
};
36+
37+
const middleware = parseListObjectsUserMetadataMiddleware(captured);
38+
const result = await middleware(createNext({
39+
Contents: [{ Key: 'obj1' }, { Key: 'obj2' }],
40+
}))({ request: {} });
41+
expect(result.output.Contents[0]['x-amz-meta-foo']).toBe('bar');
42+
expect(result.output.Contents[1]['x-amz-meta-foo']).toBe('baz');
43+
});
44+
45+
it('should handle empty Contents gracefully', async () => {
46+
const captured = {
47+
xml: buildXml([]),
48+
};
49+
50+
const middleware = parseListObjectsUserMetadataMiddleware(captured);
51+
const result = await middleware(createNext({
52+
Contents: undefined,
53+
}))({ request: {} });
54+
expect(result.output.Contents).toBeUndefined();
55+
});
56+
});

0 commit comments

Comments
 (0)