diff --git a/src/S3Client.ts b/src/S3Client.ts index 0e5f42f..b409ca1 100644 --- a/src/S3Client.ts +++ b/src/S3Client.ts @@ -59,7 +59,12 @@ const xmlParser = new XMLParser({ jPath === "ListBucketResult.Contents" || jPath === "ListPartsResult.Part" || jPath === "DeleteResult.Deleted" || - jPath === "DeleteResult.Error", + jPath === "DeleteResult.Error" || + jPath === "CORSConfiguration.CORSRule" || + jPath === "CORSConfiguration.CORSRule.AllowedMethod" || + jPath === "CORSConfiguration.CORSRule.AllowedOrigin" || + jPath === "CORSConfiguration.CORSRule.AllowedHeader" || + jPath === "CORSConfiguration.CORSRule.ExposeHeader", }); const xmlBuilder = new XMLBuilder({ attributeNamePrefix: "$", @@ -1450,10 +1455,31 @@ export default class S3Client { throw fromStatusCode(response.statusCode, ""); } - // const text = await response.body.text(); - // console.log(text) + const text = await response.body.text(); + const root = ensureParsedXml(text).CORSConfiguration ?? {}; + + const rulesArray = root.CORSRule ?? []; - throw new Error("Not implemented"); + return { + rules: rulesArray + .filter(Boolean) + // biome-ignore lint/suspicious/noExplicitAny: parsing code + .map((r: any) => ({ + allowedMethods: (r.AllowedMethod ?? []) as HttpMethod[], + allowedOrigins: (r.AllowedOrigin ?? []) as string[], + allowedHeaders: r.AllowedHeader + ? (r.AllowedHeader as string[]) + : undefined, + exposeHeaders: r.ExposeHeader + ? (r.ExposeHeader as string[]) + : undefined, + id: r.ID ?? undefined, + maxAgeSeconds: + typeof r.MaxAgeSeconds !== "undefined" && r.MaxAgeSeconds !== null + ? Number(r.MaxAgeSeconds) + : undefined, + })), + }; } /** diff --git a/src/test/common.ts b/src/test/common.ts index b131f3c..c57f0d6 100644 --- a/src/test/common.ts +++ b/src/test/common.ts @@ -1296,11 +1296,9 @@ export function runTests( test("put", async t => { if ( implementation === "minio" || - implementation === "garage" || implementation === "ceph" || - implementation === "localstack" || - implementation === "rustfs" || implementation === "s3mock" || + implementation === "rustfs" || implementation === "backblaze" || implementation === "cloudflare" ) { @@ -1312,8 +1310,6 @@ export function runTests( return; } - t.todo("Not yet implemented"); - await client.putBucketCors([ { allowedMethods: ["GET"], @@ -1322,18 +1318,60 @@ export function runTests( }, ]); - const { rules } = await client.getBucketCors(); + let { rules } = await client.getBucketCors(); expect(rules).toStrictEqual([ { allowedMethods: ["GET"], allowedOrigins: ["https://example.com"], - allowedHeaders: undefined, + allowedHeaders: ["*"], exposeHeaders: undefined, id: undefined, maxAgeSeconds: undefined, }, ]); + await client.putBucketCors([ + { + allowedMethods: ["GET"], + allowedOrigins: ["https://example.com"], + allowedHeaders: ["*"], + exposeHeaders: ["Content-Type"], + }, + ]); + + rules = (await client.getBucketCors()).rules; + expect(rules).toStrictEqual([ + { + allowedMethods: ["GET"], + allowedOrigins: ["https://example.com"], + allowedHeaders: ["*"], + exposeHeaders: ["Content-Type"], + id: undefined, + maxAgeSeconds: undefined, + }, + ]); + + await client.putBucketCors([ + { + allowedMethods: ["GET"], + allowedOrigins: ["https://example.com"], + allowedHeaders: ["*"], + exposeHeaders: ["Content-Type"], + id: "fancy-id", + }, + ]); + + rules = (await client.getBucketCors()).rules; + expect(rules).toStrictEqual([ + { + allowedMethods: ["GET"], + allowedOrigins: ["https://example.com"], + allowedHeaders: ["*"], + exposeHeaders: ["Content-Type"], + id: "fancy-id", + maxAgeSeconds: undefined, + }, + ]); await client.deleteBucketCors(); expect(client.getBucketCors()).rejects.toThrow();