Skip to content

Commit bb9e455

Browse files
authored
fix(middleware-sdk-s3): handle cross-region redirects for HeadBucket with 400 status (#7313)
1 parent 2481519 commit bb9e455

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

packages/middleware-sdk-s3/src/region-redirect-middleware.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ describe(regionRedirectMiddleware.name, () => {
3131
return null as any;
3232
};
3333

34+
const nextHeadBucket400 = (arg: any) => {
35+
if (call === 0) {
36+
call++;
37+
throw Object.assign(new Error(), {
38+
$metadata: { httpStatusCode: 400 },
39+
$response: { headers: { "x-amz-bucket-region": redirectRegion } },
40+
});
41+
}
42+
return null as any;
43+
};
44+
3445
beforeEach(() => {
3546
call = 0;
3647
});
@@ -51,6 +62,14 @@ describe(regionRedirectMiddleware.name, () => {
5162
expect(context.__s3RegionRedirect).toEqual(redirectRegion);
5263
});
5364

65+
it("set S3 region redirect on context for HeadBucket with 400 status and x-amz-bucket-region header", async () => {
66+
const middleware = regionRedirectMiddleware({ region, followRegionRedirects: true });
67+
const context = { commandName: "HeadBucketCommand" } as HandlerExecutionContext;
68+
const handler = middleware(nextHeadBucket400, context);
69+
await handler({ input: null });
70+
expect(context.__s3RegionRedirect).toEqual(redirectRegion);
71+
});
72+
5473
it("does not follow the redirect when followRegionRedirects is false", async () => {
5574
const middleware = regionRedirectMiddleware({ region, followRegionRedirects: false });
5675
const context = {} as HandlerExecutionContext;

packages/middleware-sdk-s3/src/region-redirect-middleware.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,23 @@ export function regionRedirectMiddleware(clientConfig: PreviouslyResolved): Init
3636
return await next(args);
3737
} catch (err) {
3838
if (clientConfig.followRegionRedirects) {
39-
if (
40-
err?.$metadata?.httpStatusCode === 301 ||
41-
// err.name === "PermanentRedirect" && --> removing the error name check, as that allows for HEAD operations (which have the 301 status code, but not the same error name) to be covered for region redirection as well
42-
(err?.$metadata?.httpStatusCode === 400 && err?.name === "IllegalLocationConstraintException")
43-
) {
44-
try {
45-
const actualRegion = err.$response.headers["x-amz-bucket-region"];
46-
context.logger?.debug(`Redirecting from ${await clientConfig.region()} to ${actualRegion}`);
47-
context.__s3RegionRedirect = actualRegion;
48-
} catch (e) {
49-
throw new Error("Region redirect failed: " + e);
39+
const statusCode = err?.$metadata?.httpStatusCode;
40+
const isHeadBucket = context.commandName === "HeadBucketCommand";
41+
const bucketRegionHeader = err?.$response?.headers?.["x-amz-bucket-region"];
42+
if (bucketRegionHeader) {
43+
if (
44+
statusCode === 301 ||
45+
(statusCode === 400 && (err?.name === "IllegalLocationConstraintException" || isHeadBucket))
46+
) {
47+
try {
48+
const actualRegion = bucketRegionHeader;
49+
context.logger?.debug(`Redirecting from ${await clientConfig.region()} to ${actualRegion}`);
50+
context.__s3RegionRedirect = actualRegion;
51+
} catch (e) {
52+
throw new Error("Region redirect failed: " + e);
53+
}
54+
return next(args);
5055
}
51-
return next(args);
5256
}
5357
}
5458
throw err;

0 commit comments

Comments
 (0)