Skip to content

Commit

Permalink
fix: correctly populate ListObjectsResponse.commonPrefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
lionel-rowe committed Feb 17, 2023
1 parent 0af082b commit 6885f3c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 10 deletions.
16 changes: 7 additions & 9 deletions src/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ export class S3Bucket {
if (options?.maxKeys) {
params["max-keys"] = options.maxKeys.toString();
}
if (options?.prefix) {
if (options?.prefix != null) {
params["prefix"] = options.prefix;
}
if (options?.continuationToken) {
Expand Down Expand Up @@ -360,14 +360,8 @@ export class S3Bucket {
prefix: extractContent(root, "Prefix"),
delimiter: extractContent(root, "Delimiter"),
maxKeys: maxkeys,
commonPrefixes: extractField(
root,
"CommonPrefixes",
)?.children.map<CommonPrefix>((prefix) => {
return {
prefix: extractContent(prefix, "Prefix"),
};
}),
commonPrefixes: extractMultipleFields(root, "CommonPrefixes")
.map((node) => ({ prefix: extractContent(node, "Prefix") })),
encodingType: extractContent(root, "EncodingType"),
keyCount: keycount,
continuationToken: extractContent(root, "ContinuationToken"),
Expand Down Expand Up @@ -653,6 +647,10 @@ function extractField(node: Xml, name: string): Xml | undefined {
return node.children.find((node) => node.name === name);
}

function extractMultipleFields(node: Xml, name: string): Xml[] {
return node.children.filter((node) => node.name === name);
}

function extractContent(node: Xml, name: string): string | undefined {
const field = extractField(node, name);
const content = field?.content;
Expand Down
51 changes: 51 additions & 0 deletions src/response_parsing_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { assertEquals } from "../test_deps.ts";
import { S3Bucket } from "./bucket.ts";

const bucket: S3Bucket = Object.create(S3Bucket.prototype)

Deno.test("[response parsing]", async (t) => {
await t.step("parseListObjectResponseXml", async (t) => {
await t.step("commonPrefixes", () => {
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html#API_ListObjectsV2_Example_8
const xml = `<?xml version='1.0' encoding='utf-8' ?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>example-bucket</Name>
<Prefix>photos/2006/</Prefix>
<Marker></Marker>
<MaxKeys>1000</MaxKeys>
<Delimiter>/</Delimiter>
<IsTruncated>false</IsTruncated>
<CommonPrefixes>
<Prefix>photos/2006/February/</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>photos/2006/January/</Prefix>
</CommonPrefixes>
</ListBucketResult>`;

assertEquals(bucket["parseListObjectResponseXml"](xml).commonPrefixes, [
{ prefix: "photos/2006/February/" },
{ prefix: "photos/2006/January/" },
]);
});

await t.step("commonPrefixes with entity escapes", () => {
const xml = `<?xml version='1.0' encoding='utf-8' ?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>example-bucket</Name>
<Prefix>photos/2006/</Prefix>
<Marker></Marker>
<MaxKeys>1000</MaxKeys>
<Delimiter>/</Delimiter>
<IsTruncated>false</IsTruncated>
<CommonPrefixes>
<Prefix>photos/2006/a&amp;b/</Prefix>
</CommonPrefixes>
</ListBucketResult>`;

assertEquals(bucket["parseListObjectResponseXml"](xml).commonPrefixes, [
{ prefix: "photos/2006/a&b/" },
]);
});
});
});
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export interface ListObjectsResponse {
/**
* All of the keys rolled up into a common prefix count as a single return when calculating the number of returns. A response can contain CommonPrefixes only if you specify a delimiter. CommonPrefixes contains all (if there are any) keys between Prefix and the next occurrence of the string specified by a delimiter. CommonPrefixes lists keys that act like subdirectories in the directory specified by Prefix. For example, if the prefix is notes/ and the delimiter is a slash (/) as in notes/summer/july, the common prefix is notes/summer/. All of the keys that roll up into a common prefix count as a single return when calculating the number of returns.
*/
commonPrefixes?: CommonPrefix[];
commonPrefixes: CommonPrefix[];
/**
* Encoding type used by Amazon S3 to encode object key names in the XML response. If you specify the encoding-type request parameter, Amazon S3 includes this element in the response, and returns encoded key name values in the following response elements: Delimiter, Prefix, Key, and StartAfter.
*/
Expand Down

0 comments on commit 6885f3c

Please sign in to comment.