Skip to content

Commit 47c6599

Browse files
feat(client-s3): use regional endpoint by default and support aws-global region (#1552)
* feat(client-s3): use regional endpoint by default * feat(client-s3): use global endpoint if region is set to aws-global Co-authored-by: Trivikram Kamat <[email protected]>
1 parent 0439946 commit 47c6599

File tree

7 files changed

+116
-3
lines changed

7 files changed

+116
-3
lines changed

clients/client-s3/S3Client.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ import {
240240
} from "@aws-sdk/middleware-host-header";
241241
import { getLoggerPlugin } from "@aws-sdk/middleware-logger";
242242
import { RetryInputConfig, RetryResolvedConfig, getRetryPlugin, resolveRetryConfig } from "@aws-sdk/middleware-retry";
243-
import { getValidateBucketNamePlugin } from "@aws-sdk/middleware-sdk-s3";
243+
import { getUseRegionalEndpointPlugin, getValidateBucketNamePlugin } from "@aws-sdk/middleware-sdk-s3";
244244
import {
245245
AwsAuthInputConfig,
246246
AwsAuthResolvedConfig,
@@ -621,6 +621,7 @@ export class S3Client extends __Client<
621621
this.middlewareStack.use(getUserAgentPlugin(this.config));
622622
this.middlewareStack.use(getContentLengthPlugin(this.config));
623623
this.middlewareStack.use(getValidateBucketNamePlugin(this.config));
624+
this.middlewareStack.use(getUseRegionalEndpointPlugin(this.config));
624625
this.middlewareStack.use(getAddExpectContinuePlugin(this.config));
625626
this.middlewareStack.use(getHostHeaderPlugin(this.config));
626627
this.middlewareStack.use(getLoggerPlugin(this.config));

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,12 @@ public List<RuntimeClientPlugin> getClientPlugins() {
100100
.servicePredicate((m, s) -> testServiceId(s, "API Gateway"))
101101
.build(),
102102
RuntimeClientPlugin.builder()
103-
.withConventions(AwsDependency.VALIDATE_BUCKET_NAME.dependency, "ValidateBucketName",
103+
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "ValidateBucketName",
104+
HAS_MIDDLEWARE)
105+
.servicePredicate((m, s) -> testServiceId(s, "S3"))
106+
.build(),
107+
RuntimeClientPlugin.builder()
108+
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "UseRegionalEndpoint",
104109
HAS_MIDDLEWARE)
105110
.servicePredicate((m, s) -> testServiceId(s, "S3"))
106111
.build(),

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsDependency.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public enum AwsDependency implements SymbolDependencyContainer {
3232
MIDDLEWARE_SIGNING(NORMAL_DEPENDENCY, "@aws-sdk/middleware-signing", "^1.0.0-beta.1"),
3333
CREDENTIAL_PROVIDER_NODE(NORMAL_DEPENDENCY, "@aws-sdk/credential-provider-node", "^1.0.0-beta.1"),
3434
ACCEPT_HEADER(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-api-gateway", "^1.0.0-beta.1"),
35-
VALIDATE_BUCKET_NAME(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-s3", "^1.0.0-beta.1"),
35+
S3_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-s3", "^1.0.0-beta.1"),
3636
ADD_EXPECT_CONTINUE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-expect-continue", "^1.0.0-beta.1"),
3737
GLACIER_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-glacier", "^1.0.0-beta.1"),
3838
MACHINELEARNING_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-machinelearning", "^1.0.0-beta.1"),

packages/middleware-sdk-s3/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"license": "Apache-2.0",
2020
"dependencies": {
2121
"@aws-sdk/util-arn-parser": "1.0.0-gamma.3",
22+
"@aws-sdk/protocol-http": "1.0.0-gamma.7",
2223
"tslib": "^1.8.0"
2324
},
2425
"devDependencies": {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from "./validate-bucket-name";
2+
export * from "./use-regional-endpoint";
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { HttpRequest } from "@aws-sdk/protocol-http";
2+
3+
import { useRegionalEndpointMiddleware } from "./use-regional-endpoint";
4+
5+
describe("useRegionalEndpointMiddleware", () => {
6+
const mockNextHandler = jest.fn();
7+
beforeEach(() => {
8+
jest.clearAllMocks();
9+
});
10+
11+
it("should accept any endpoint if set by customer", async () => {
12+
const config = { isCustomEndpoint: true, region: async () => "foo-region" };
13+
const handler = useRegionalEndpointMiddleware(config)(mockNextHandler, {} as any);
14+
await handler({
15+
input: {},
16+
request: new HttpRequest({
17+
hostname: "s3.us-east-1.amazonaws.com",
18+
}),
19+
});
20+
expect(mockNextHandler.mock.calls.length).toBe(1);
21+
expect(mockNextHandler.mock.calls[0][0].request.hostname).toEqual("s3.us-east-1.amazonaws.com");
22+
});
23+
24+
it("should modify the hostname if it's global endpoint", async () => {
25+
const config = { isCustomEndpoint: false, region: async () => "foo-region" };
26+
const handler = useRegionalEndpointMiddleware(config)(mockNextHandler, {} as any);
27+
await handler({
28+
input: {},
29+
request: new HttpRequest({
30+
hostname: "s3.amazonaws.com",
31+
}),
32+
});
33+
expect(mockNextHandler.mock.calls.length).toBe(1);
34+
expect(mockNextHandler.mock.calls[0][0].request.hostname).toEqual("s3.us-east-1.amazonaws.com");
35+
});
36+
37+
it("should not modify the hostname if it's regional endpoint", async () => {
38+
const config = { isCustomEndpoint: false, region: async () => "foo-region" };
39+
const handler = useRegionalEndpointMiddleware(config)(mockNextHandler, {} as any);
40+
await handler({
41+
input: {},
42+
request: new HttpRequest({
43+
hostname: "s3.us-west-2.amazonaws.com",
44+
}),
45+
});
46+
expect(mockNextHandler.mock.calls.length).toBe(1);
47+
expect(mockNextHandler.mock.calls[0][0].request.hostname).toEqual("s3.us-west-2.amazonaws.com");
48+
});
49+
50+
it("should use global endpoint if region is set to 'aws-global'", async () => {
51+
const config = { isCustomEndpoint: false, region: async () => "aws-global" };
52+
const handler = useRegionalEndpointMiddleware(config)(mockNextHandler, {} as any);
53+
await handler({
54+
input: {},
55+
request: new HttpRequest({
56+
hostname: "s3.aws-global.amazonaws.com",
57+
}),
58+
});
59+
expect(mockNextHandler.mock.calls.length).toBe(1);
60+
expect(mockNextHandler.mock.calls[0][0].request.hostname).toEqual("s3.amazonaws.com");
61+
});
62+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { HttpRequest } from "@aws-sdk/protocol-http";
2+
import {
3+
BuildHandler,
4+
BuildHandlerArguments,
5+
BuildHandlerOptions,
6+
BuildHandlerOutput,
7+
BuildMiddleware,
8+
MetadataBearer,
9+
Pluggable,
10+
Provider,
11+
} from "@aws-sdk/types";
12+
13+
type PreviouslyResolved = {
14+
region: Provider<string>;
15+
isCustomEndpoint: boolean;
16+
};
17+
18+
export const useRegionalEndpointMiddleware = (config: PreviouslyResolved): BuildMiddleware<any, any> => <
19+
Output extends MetadataBearer
20+
>(
21+
next: BuildHandler<any, Output>
22+
): BuildHandler<any, Output> => async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> => {
23+
const { request } = args;
24+
if (!HttpRequest.isInstance(request) || config.isCustomEndpoint) return next({ ...args });
25+
if (request.hostname === "s3.amazonaws.com") {
26+
request.hostname = "s3.us-east-1.amazonaws.com";
27+
} else if ("aws-global" === (await config.region())) {
28+
request.hostname = "s3.amazonaws.com";
29+
}
30+
return next({ ...args });
31+
};
32+
33+
export const useRegionalEndpointMiddlewareOptions: BuildHandlerOptions = {
34+
step: "build",
35+
tags: ["USE_REGIONAL_ENDPOINT", "S3"],
36+
name: "useRegionalEndpointMiddleware",
37+
};
38+
39+
export const getUseRegionalEndpointPlugin = (config: PreviouslyResolved): Pluggable<any, any> => ({
40+
applyToStack: (clientStack) => {
41+
clientStack.add(useRegionalEndpointMiddleware(config), useRegionalEndpointMiddlewareOptions);
42+
},
43+
});

0 commit comments

Comments
 (0)