From f0c32224455fd3e3be78bfeeeba6f3520f5ea0e9 Mon Sep 17 00:00:00 2001 From: Chase Coalwell Date: Thu, 19 Dec 2019 11:42:33 -0800 Subject: [PATCH] feat: migrate bucketEndpointMiddleware (#552) feat: name package feat: migrate and apply middleware feat: remove $ input options feat: remove preformedBucket option --- .../typescript/codegen/AddBuiltinPlugins.java | 12 + .../aws/typescript/codegen/AwsDependency.java | 1 + packages/bucket-endpoint-middleware/README.md | 4 - .../src/bucketEndpointMiddleware.spec.ts | 222 ------------------ .../src/bucketEndpointMiddleware.ts | 73 ------ .../.gitignore | 0 .../.npmignore | 0 .../CHANGELOG.md | 0 .../LICENSE | 0 packages/middleware-bucket-endpoint/README.md | 4 + .../jest.config.js | 0 .../package.json | 6 +- .../src/bucketEndpointMiddleware.spec.ts | 132 +++++++++++ .../src/bucketEndpointMiddleware.ts | 69 ++++++ .../src/bucketHostname.spec.ts | 2 +- .../src/bucketHostname.ts | 6 +- .../src/configurations.ts | 43 ++++ .../src/index.ts | 0 .../tsconfig.json | 0 .../tsconfig.test.json | 0 20 files changed, 268 insertions(+), 306 deletions(-) delete mode 100644 packages/bucket-endpoint-middleware/README.md delete mode 100644 packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.spec.ts delete mode 100644 packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.ts rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/.gitignore (100%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/.npmignore (100%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/CHANGELOG.md (100%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/LICENSE (100%) create mode 100644 packages/middleware-bucket-endpoint/README.md rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/jest.config.js (100%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/package.json (86%) create mode 100644 packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts create mode 100644 packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/src/bucketHostname.spec.ts (99%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/src/bucketHostname.ts (95%) create mode 100644 packages/middleware-bucket-endpoint/src/configurations.ts rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/src/index.ts (100%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/tsconfig.json (100%) rename packages/{bucket-endpoint-middleware => middleware-bucket-endpoint}/tsconfig.test.json (100%) diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java index 341a98247406b..4db786bc94ad5 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java @@ -51,6 +51,12 @@ public class AddBuiltinPlugins implements TypeScriptIntegration { "PutBucketReplication" ); + private static final Set NON_BUCKET_ENDPOINT_OPERATIONS = SetUtils.of( + "CreateBucket", + "DeleteBucket", + "ListBuckets" + ); + @Override public List getClientPlugins() { // Note that order is significant because configurations might @@ -112,6 +118,12 @@ public List getClientPlugins() { .servicePredicate((m, s) -> testServiceId(s, "Machine Learning")) .operationPredicate((m, s, o) -> o.getId().getName().equals("Predict")) .build(), + RuntimeClientPlugin.builder() + .withConventions(AwsDependency.BUCKET_ENDPOINT_MIDDLEWARE.dependency, "BucketEndpoint", + HAS_MIDDLEWARE) + .servicePredicate((m, s) -> testServiceId(s, "S3")) + .operationPredicate((m, s, o) -> !NON_BUCKET_ENDPOINT_OPERATIONS.contains(o.getId().getName())) + .build(), RuntimeClientPlugin.builder() .withConventions(AwsDependency.BODY_CHECKSUM.dependency, "ApplyMd5BodyChecksum", HAS_MIDDLEWARE) diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsDependency.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsDependency.java index 3e9fe4571bd10..baf3cc48602f4 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsDependency.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsDependency.java @@ -42,6 +42,7 @@ public enum AwsDependency implements SymbolDependencyContainer { STREAM_HASHER_NODE(NORMAL_DEPENDENCY, "@aws-sdk/hash-stream-node", "^0.1.0-preview.4"), STREAM_HASHER_BROWSER(NORMAL_DEPENDENCY, "@aws-sdk/hash-blob-browser", "^0.1.0-preview.4"), ROUTE53_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-route53", "^0.1.0-preview.1"), + BUCKET_ENDPOINT_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-bucket-endpoint", "^0.1.0-preview.5"), BODY_CHECKSUM(NORMAL_DEPENDENCY, "@aws-sdk/middleware-apply-body-checksum", "^0.1.0-preview.5"); public final String packageName; diff --git a/packages/bucket-endpoint-middleware/README.md b/packages/bucket-endpoint-middleware/README.md deleted file mode 100644 index 59d69b8411050..0000000000000 --- a/packages/bucket-endpoint-middleware/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# @aws-sdk/bucket-endpoint-middleware - -[![NPM version](https://img.shields.io/npm/v/@aws-sdk/bucket-endpoint-middleware/preview.svg)](https://www.npmjs.com/package/@aws-sdk/bucket-endpoint-middleware) -[![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/bucket-endpoint-middleware.svg)](https://www.npmjs.com/package/@aws-sdk/bucket-endpoint-middleware) diff --git a/packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.spec.ts b/packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.spec.ts deleted file mode 100644 index 9d5838c366db6..0000000000000 --- a/packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.spec.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { - BucketEndpointAwareInput, - bucketEndpointMiddleware -} from "./bucketEndpointMiddleware"; -import { HttpRequest } from "@aws-sdk/types"; - -describe("bucketEndpointMiddleware", () => { - const input: BucketEndpointAwareInput = { Bucket: "bucket" }; - const request: HttpRequest = { - method: "GET", - headers: {}, - protocol: "https:", - hostname: "s3.us-west-2.amazonaws.com", - path: "/bucket" - }; - const next = jest.fn(); - - beforeEach(() => { - next.mockClear(); - }); - - it("should convert the request provided into one directed to a virtual hosted-style endpoint", async () => { - const handler = bucketEndpointMiddleware()(next, {} as any); - await handler({ input, request }); - - const { - input: forwardedInput, - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(forwardedInput).toBe(input); - expect(hostname).toBe("bucket.s3.us-west-2.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should not convert the request provided into one directed to a virtual hosted-style endpoint if so configured", async () => { - const handler = bucketEndpointMiddleware({ - forcePathStyle: true - })(next, {} as any); - await handler({ input, request }); - - const { - input: forwardedInput, - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(forwardedInput).toBe(input); - expect(hostname).toBe("s3.us-west-2.amazonaws.com"); - expect(path).toBe("/bucket"); - }); - - it("should not convert the request provided into one directed to a virtual hosted-style endpoint if so directed on the input", async () => { - const handler = bucketEndpointMiddleware()(next, {} as any); - await handler({ input: { ...input, $forcePathStyle: true }, request }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("s3.us-west-2.amazonaws.com"); - expect(path).toBe("/bucket"); - }); - - it("should convert the request provided into one directed to a virtual hosted-style endpoint if path-style is disabled on the input", async () => { - const handler = bucketEndpointMiddleware({ - forcePathStyle: true - })(next, {} as any); - await handler({ input: { ...input, $forcePathStyle: false }, request }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("bucket.s3.us-west-2.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should not convert the request provided into one without the bucket in the path if so configured", async () => { - const handler = bucketEndpointMiddleware({ - preformedBucketEndpoint: true - })(next, {} as any); - await handler({ - input, - request: { ...request, hostname: "example.com" } - }); - - const { - input: forwardedInput, - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(forwardedInput).toBe(input); - expect(hostname).toBe("example.com"); - expect(path).toBe("/"); - }); - - it("should use the bucket name as a virtual hosted-style endpoint if so configured on the input", async () => { - const handler = bucketEndpointMiddleware()(next, {} as any); - await handler({ - input: { Bucket: "files.domain.com", $bucketEndpoint: true }, - request: { ...request, path: "/files.domain.com/path/to/key.ext" } - }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("files.domain.com"); - expect(path).toBe("/path/to/key.ext"); - }); - - it("should use a transfer acceleration endpoint if so configured", async () => { - const handler = bucketEndpointMiddleware({ - useAccelerateEndpoint: true - })(next, {} as any); - await handler({ input, request }); - - const { - input: forwardedInput, - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(forwardedInput).toBe(input); - expect(hostname).toBe("bucket.s3-accelerate.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should use a transfer acceleration endpoint if so directed on the input", async () => { - const handler = bucketEndpointMiddleware()(next, {} as any); - await handler({ - input: { ...input, $useAccelerateEndpoint: true }, - request - }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("bucket.s3-accelerate.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should not use a transfer acceleration endpoint if disabled on the input", async () => { - const handler = bucketEndpointMiddleware({ - useAccelerateEndpoint: true - })(next, {} as any); - await handler({ - input: { ...input, $useAccelerateEndpoint: false }, - request - }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("bucket.s3.us-west-2.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should use a dualstack endpoint if so configured", async () => { - const handler = bucketEndpointMiddleware({ - useDualstackEndpoint: true - })(next, {} as any); - await handler({ input, request }); - - const { - input: forwardedInput, - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(forwardedInput).toBe(input); - expect(hostname).toBe("bucket.s3.dualstack.us-west-2.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should use a dualstack endpoint if so directed on the input", async () => { - const handler = bucketEndpointMiddleware()(next, {} as any); - await handler({ - input: { ...input, $useDualstackEndpoint: true }, - request - }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("bucket.s3.dualstack.us-west-2.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should not use a dualstack endpoint if disabled on the input", async () => { - const handler = bucketEndpointMiddleware({ - useDualstackEndpoint: true - })(next, {} as any); - await handler({ - input: { ...input, $useDualstackEndpoint: false }, - request - }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("bucket.s3.us-west-2.amazonaws.com"); - expect(path).toBe("/"); - }); - - it("should use an accelerate dualstack endpoint if so directed on the input", async () => { - const handler = bucketEndpointMiddleware({ - useAccelerateEndpoint: true, - useDualstackEndpoint: true - })(next, {} as any); - await handler({ input, request }); - - const { - request: { hostname, path } - } = next.mock.calls[0][0]; - - expect(hostname).toBe("bucket.s3-accelerate.dualstack.amazonaws.com"); - expect(path).toBe("/"); - }); -}); diff --git a/packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.ts b/packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.ts deleted file mode 100644 index c88a64d3fac02..0000000000000 --- a/packages/bucket-endpoint-middleware/src/bucketEndpointMiddleware.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { bucketHostname } from "./bucketHostname"; -import { - BuildHandler, - BuildHandlerArguments, - BuildMiddleware, - MetadataBearer -} from "@aws-sdk/types"; - -export interface BucketEndpointAwareInput { - Bucket: string; - $bucketEndpoint?: boolean; - $forcePathStyle?: boolean; - $useAccelerateEndpoint?: boolean; - $useDualstackEndpoint?: boolean; -} - -export interface bucketEndpointMiddlewareConfiguration { - forcePathStyle?: boolean; - preformedBucketEndpoint?: boolean; - useAccelerateEndpoint?: boolean; - useDualstackEndpoint?: boolean; -} - -export function bucketEndpointMiddleware({ - forcePathStyle = false, - preformedBucketEndpoint = false, - useAccelerateEndpoint = false, - useDualstackEndpoint = false -}: bucketEndpointMiddlewareConfiguration = {}): BuildMiddleware { - return < - Input extends BucketEndpointAwareInput, - Output extends MetadataBearer - >( - next: BuildHandler - ): BuildHandler => async ( - args: BuildHandlerArguments - ): Promise => { - const { - Bucket: bucketName, - $bucketEndpoint, - $forcePathStyle = forcePathStyle, - $useAccelerateEndpoint = useAccelerateEndpoint, - $useDualstackEndpoint = useDualstackEndpoint - } = args.input; - let replaceBucketInPath = preformedBucketEndpoint || $bucketEndpoint; - const request = { ...args.request }; - - if ($bucketEndpoint) { - request.hostname = bucketName; - } else if (!preformedBucketEndpoint) { - const { hostname, bucketEndpoint } = bucketHostname({ - bucketName, - baseHostname: request.hostname, - accelerateEndpoint: $useAccelerateEndpoint, - dualstackEndpoint: $useDualstackEndpoint, - pathStyleEndpoint: $forcePathStyle, - sslCompatible: request.protocol === "https:" - }); - - request.hostname = hostname; - replaceBucketInPath = bucketEndpoint; - } - - if (replaceBucketInPath) { - request.path = request.path.replace(/^(\/)?[^\/]+/, ""); - if (request.path === "") { - request.path = "/"; - } - } - - return next({ ...args, request }); - }; -} diff --git a/packages/bucket-endpoint-middleware/.gitignore b/packages/middleware-bucket-endpoint/.gitignore similarity index 100% rename from packages/bucket-endpoint-middleware/.gitignore rename to packages/middleware-bucket-endpoint/.gitignore diff --git a/packages/bucket-endpoint-middleware/.npmignore b/packages/middleware-bucket-endpoint/.npmignore similarity index 100% rename from packages/bucket-endpoint-middleware/.npmignore rename to packages/middleware-bucket-endpoint/.npmignore diff --git a/packages/bucket-endpoint-middleware/CHANGELOG.md b/packages/middleware-bucket-endpoint/CHANGELOG.md similarity index 100% rename from packages/bucket-endpoint-middleware/CHANGELOG.md rename to packages/middleware-bucket-endpoint/CHANGELOG.md diff --git a/packages/bucket-endpoint-middleware/LICENSE b/packages/middleware-bucket-endpoint/LICENSE similarity index 100% rename from packages/bucket-endpoint-middleware/LICENSE rename to packages/middleware-bucket-endpoint/LICENSE diff --git a/packages/middleware-bucket-endpoint/README.md b/packages/middleware-bucket-endpoint/README.md new file mode 100644 index 0000000000000..1a866140af6d7 --- /dev/null +++ b/packages/middleware-bucket-endpoint/README.md @@ -0,0 +1,4 @@ +# @aws-sdk/middleware-bucket-endpoint + +[![NPM version](https://img.shields.io/npm/v/@aws-sdk/middleware-bucket-endpoint/preview.svg)](https://www.npmjs.com/package/@aws-sdk/middleware-bucket-endpoint) +[![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/middleware-bucket-endpoint.svg)](https://www.npmjs.com/package/@aws-sdk/middleware-bucket-endpoint) diff --git a/packages/bucket-endpoint-middleware/jest.config.js b/packages/middleware-bucket-endpoint/jest.config.js similarity index 100% rename from packages/bucket-endpoint-middleware/jest.config.js rename to packages/middleware-bucket-endpoint/jest.config.js diff --git a/packages/bucket-endpoint-middleware/package.json b/packages/middleware-bucket-endpoint/package.json similarity index 86% rename from packages/bucket-endpoint-middleware/package.json rename to packages/middleware-bucket-endpoint/package.json index c4a67c46e658c..b14354f45883a 100644 --- a/packages/bucket-endpoint-middleware/package.json +++ b/packages/middleware-bucket-endpoint/package.json @@ -1,6 +1,6 @@ { - "name": "@aws-sdk/bucket-endpoint-middleware", - "version": "0.1.0-preview.7", + "name": "@aws-sdk/middleware-bucket-endpoint", + "version": "0.1.0-preview.5", "scripts": { "prepublishOnly": "tsc", "pretest": "tsc -p tsconfig.test.json", @@ -22,4 +22,4 @@ "jest": "^24.7.1", "typescript": "~3.4.0" } -} +} \ No newline at end of file diff --git a/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts new file mode 100644 index 0000000000000..8abc22e174e35 --- /dev/null +++ b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts @@ -0,0 +1,132 @@ +import { bucketEndpointMiddleware } from "./bucketEndpointMiddleware"; +import { HttpRequest } from "@aws-sdk/protocol-http"; +import { resolveBucketEndpointConfig } from "./configurations"; + +describe("bucketEndpointMiddleware", () => { + const input = { Bucket: "bucket" }; + const requestInput = { + method: "GET", + headers: {}, + protocol: "https:", + hostname: "s3.us-west-2.amazonaws.com", + path: "/bucket" + }; + const next = jest.fn(); + + beforeEach(() => { + next.mockClear(); + }); + + it("should convert the request provided into one directed to a virtual hosted-style endpoint", async () => { + const request = new HttpRequest(requestInput); + const handler = bucketEndpointMiddleware(resolveBucketEndpointConfig({}))( + next, + {} as any + ); + await handler({ input, request }); + + const { + input: forwardedInput, + request: { hostname, path } + } = next.mock.calls[0][0]; + + expect(forwardedInput).toBe(input); + expect(hostname).toBe("bucket.s3.us-west-2.amazonaws.com"); + expect(path).toBe("/"); + }); + + it("should not convert the request provided into one directed to a virtual hosted-style endpoint if so configured", async () => { + const request = new HttpRequest(requestInput); + const handler = bucketEndpointMiddleware( + resolveBucketEndpointConfig({ + forcePathStyle: true + }) + )(next, {} as any); + await handler({ input, request }); + + const { + input: forwardedInput, + request: { hostname, path } + } = next.mock.calls[0][0]; + + expect(forwardedInput).toBe(input); + expect(hostname).toBe("s3.us-west-2.amazonaws.com"); + expect(path).toBe("/bucket"); + }); + + it("should use the bucket name as a virtual hosted-style endpoint if so configured", async () => { + const request = new HttpRequest(requestInput); + const handler = bucketEndpointMiddleware( + resolveBucketEndpointConfig({ + bucketEndpoint: true + }) + )(next, {} as any); + await handler({ + input: { Bucket: "files.domain.com" }, + request: { ...request, path: "/files.domain.com/path/to/key.ext" } + }); + + const { + request: { hostname, path } + } = next.mock.calls[0][0]; + + expect(hostname).toBe("files.domain.com"); + expect(path).toBe("/path/to/key.ext"); + }); + + it("should use a transfer acceleration endpoint if so configured", async () => { + const request = new HttpRequest(requestInput); + const handler = bucketEndpointMiddleware( + resolveBucketEndpointConfig({ + useAccelerateEndpoint: true + }) + )(next, {} as any); + await handler({ input, request }); + + const { + input: forwardedInput, + request: { hostname, path } + } = next.mock.calls[0][0]; + + expect(forwardedInput).toBe(input); + expect(hostname).toBe("bucket.s3-accelerate.amazonaws.com"); + expect(path).toBe("/"); + }); + + it("should use a dualstack endpoint if so configured", async () => { + const request = new HttpRequest(requestInput); + const handler = bucketEndpointMiddleware( + resolveBucketEndpointConfig({ + useDualstackEndpoint: true + }) + )(next, {} as any); + await handler({ input, request }); + + const { + input: forwardedInput, + request: { hostname, path } + } = next.mock.calls[0][0]; + + expect(forwardedInput).toBe(input); + expect(hostname).toBe("bucket.s3.dualstack.us-west-2.amazonaws.com"); + expect(path).toBe("/"); + }); + + it("should use an accelerate dualstack endpoint if configured", async () => { + const request = new HttpRequest(requestInput); + const handler = bucketEndpointMiddleware( + resolveBucketEndpointConfig({ + useAccelerateEndpoint: true, + useDualstackEndpoint: true + }) + )(next, {} as any); + await handler({ input, request }); + + const { + request: { hostname, path } + } = next.mock.calls[0][0]; + + expect(hostname).toBe("bucket.s3-accelerate.dualstack.amazonaws.com"); + expect(path).toBe("/"); + }); +}); diff --git a/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts new file mode 100644 index 0000000000000..64a70c7d4cc3d --- /dev/null +++ b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts @@ -0,0 +1,69 @@ +import { bucketHostname } from "./bucketHostname"; +import { BucketEndpointResolvedConfig } from "./configurations"; +import { + BuildHandler, + BuildHandlerArguments, + BuildHandlerOptions, + BuildHandlerOutput, + BuildMiddleware, + MetadataBearer, + Pluggable +} from "@aws-sdk/types"; +import { HttpRequest } from "@aws-sdk/protocol-http"; + +export function bucketEndpointMiddleware( + options: BucketEndpointResolvedConfig +): BuildMiddleware { + return ( + next: BuildHandler + ): BuildHandler => async ( + args: BuildHandlerArguments + ): Promise> => { + const { Bucket: bucketName } = args.input; + let replaceBucketInPath = options.bucketEndpoint; + let request = args.request; + if (HttpRequest.isInstance(request)) { + if (options.bucketEndpoint) { + request.hostname = bucketName; + } else { + const { hostname, bucketEndpoint } = bucketHostname({ + bucketName, + baseHostname: request.hostname, + accelerateEndpoint: options.useAccelerateEndpoint, + dualstackEndpoint: options.useDualstackEndpoint, + pathStyleEndpoint: options.forcePathStyle, + tlsCompatible: request.protocol === "https:" + }); + + request.hostname = hostname; + replaceBucketInPath = bucketEndpoint; + } + + if (replaceBucketInPath) { + request.path = request.path.replace(/^(\/)?[^\/]+/, ""); + if (request.path === "") { + request.path = "/"; + } + } + } + + return next({ ...args, request }); + }; +} + +export const bucketEndpointMiddlewareOptions: BuildHandlerOptions = { + step: "build", + tags: ["BUCKET_ENDPOINT"], + name: "bucketEndpointMiddleware" +}; + +export const getBucketEndpointPlugin = ( + options: BucketEndpointResolvedConfig +): Pluggable => ({ + applyToStack: clientStack => { + clientStack.add( + bucketEndpointMiddleware(options), + bucketEndpointMiddlewareOptions + ); + } +}); diff --git a/packages/bucket-endpoint-middleware/src/bucketHostname.spec.ts b/packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts similarity index 99% rename from packages/bucket-endpoint-middleware/src/bucketHostname.spec.ts rename to packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts index 2db4297c31663..970c33021a4de 100644 --- a/packages/bucket-endpoint-middleware/src/bucketHostname.spec.ts +++ b/packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts @@ -53,7 +53,7 @@ describe("bucketHostname", () => { const { bucketEndpoint, hostname } = bucketHostname({ bucketName: "foo.bar", baseHostname, - sslCompatible: false + tlsCompatible: false }); expect(bucketEndpoint).toBe(true); diff --git a/packages/bucket-endpoint-middleware/src/bucketHostname.ts b/packages/middleware-bucket-endpoint/src/bucketHostname.ts similarity index 95% rename from packages/bucket-endpoint-middleware/src/bucketHostname.ts rename to packages/middleware-bucket-endpoint/src/bucketHostname.ts index 3e71ab4803929..86568a28242df 100644 --- a/packages/bucket-endpoint-middleware/src/bucketHostname.ts +++ b/packages/middleware-bucket-endpoint/src/bucketHostname.ts @@ -12,7 +12,7 @@ export interface BucketHostnameParameters { bucketName: string; dualstackEndpoint?: boolean; pathStyleEndpoint?: boolean; - sslCompatible?: boolean; + tlsCompatible?: boolean; } export interface BucketHostname { @@ -26,7 +26,7 @@ export function bucketHostname({ bucketName, dualstackEndpoint = false, pathStyleEndpoint = false, - sslCompatible = true + tlsCompatible = true }: BucketHostnameParameters): BucketHostname { if (!S3_HOSTNAME_PATTERN.test(baseHostname)) { return { @@ -44,7 +44,7 @@ export function bucketHostname({ if ( pathStyleEndpoint || !isDnsCompatibleBucketName(bucketName) || - (sslCompatible && DOT_PATTERN.test(bucketName)) + (tlsCompatible && DOT_PATTERN.test(bucketName)) ) { return { bucketEndpoint: false, diff --git a/packages/middleware-bucket-endpoint/src/configurations.ts b/packages/middleware-bucket-endpoint/src/configurations.ts new file mode 100644 index 0000000000000..f339534c68acc --- /dev/null +++ b/packages/middleware-bucket-endpoint/src/configurations.ts @@ -0,0 +1,43 @@ +export interface BucketEndpointInputConfig { + /** + * Whether the provided endpoint addresses an individual bucket. + */ + bucketEndpoint?: boolean; + /** + * Whether to force path style URLs for S3 objects (e.g., https://s3.amazonaws.com// instead of https://.s3.amazonaws.com/ + */ + forcePathStyle?: boolean; + /** + * Whether to use the S3 Transfer Acceleration endpoint by default + */ + useAccelerateEndpoint?: boolean; + /** + * Enables IPv6/IPv4 dualstack endpoint. When a DNS lookup is performed on an endpoint of this type, it returns an “A” record with an IPv4 address and an “AAAA” record with an IPv6 address. In most cases the network stack in the client environment will automatically prefer the AAAA record and make a connection using the IPv6 address. Note, however, that currently on Windows, the IPv4 address will be preferred. + */ + useDualstackEndpoint?: boolean; +} + +export interface BucketEndpointResolvedConfig { + bucketEndpoint: boolean; + forcePathStyle: boolean; + useAccelerateEndpoint: boolean; + useDualstackEndpoint: boolean; +} + +export function resolveBucketEndpointConfig( + input: T & BucketEndpointInputConfig +): T & BucketEndpointResolvedConfig { + const { + bucketEndpoint = false, + forcePathStyle = false, + useAccelerateEndpoint = false, + useDualstackEndpoint = false + } = input; + return { + ...input, + bucketEndpoint, + forcePathStyle, + useAccelerateEndpoint, + useDualstackEndpoint + }; +} diff --git a/packages/bucket-endpoint-middleware/src/index.ts b/packages/middleware-bucket-endpoint/src/index.ts similarity index 100% rename from packages/bucket-endpoint-middleware/src/index.ts rename to packages/middleware-bucket-endpoint/src/index.ts diff --git a/packages/bucket-endpoint-middleware/tsconfig.json b/packages/middleware-bucket-endpoint/tsconfig.json similarity index 100% rename from packages/bucket-endpoint-middleware/tsconfig.json rename to packages/middleware-bucket-endpoint/tsconfig.json diff --git a/packages/bucket-endpoint-middleware/tsconfig.test.json b/packages/middleware-bucket-endpoint/tsconfig.test.json similarity index 100% rename from packages/bucket-endpoint-middleware/tsconfig.test.json rename to packages/middleware-bucket-endpoint/tsconfig.test.json