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 4db786bc94ad..3ee2577abcdb 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 @@ -141,6 +141,9 @@ public List getClientPlugins() { HAS_MIDDLEWARE) .servicePredicate((m, s) -> testServiceId(s, "Route 53")) .operationPredicate((m, s, o) -> testInputContainsMember(m, o, ROUTE_53_ID_MEMBERS)) + .build(), + RuntimeClientPlugin.builder() + .withConventions(AwsDependency.MIDDLEWARE_HOST_HEADER.dependency, "HostHeader") .build() ); } 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 baf3cc48602f..bef09f453e1e 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 @@ -43,7 +43,8 @@ public enum AwsDependency implements SymbolDependencyContainer { 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"); + BODY_CHECKSUM(NORMAL_DEPENDENCY, "@aws-sdk/middleware-apply-body-checksum", "^0.1.0-preview.5"), + MIDDLEWARE_HOST_HEADER(NORMAL_DEPENDENCY, "@aws-sdk/middleware-host-header", "^0.1.0-preview.1"); public final String packageName; public final String version; diff --git a/packages/middleware-host-header/.gitignore b/packages/middleware-host-header/.gitignore new file mode 100644 index 000000000000..3d1714c9806e --- /dev/null +++ b/packages/middleware-host-header/.gitignore @@ -0,0 +1,8 @@ +/node_modules/ +/build/ +/coverage/ +/docs/ +*.tsbuildinfo +*.tgz +*.log +package-lock.json diff --git a/packages/middleware-host-header/.npmignore b/packages/middleware-host-header/.npmignore new file mode 100644 index 000000000000..4b9fe3abf33a --- /dev/null +++ b/packages/middleware-host-header/.npmignore @@ -0,0 +1,13 @@ +/src/ +/coverage/ +/docs/ +tsconfig.test.json +*.tsbuildinfo + +*.spec.js +*.spec.d.ts +*.spec.js.map + +*.fixture.js +*.fixture.d.ts +*.fixture.js.map diff --git a/packages/middleware-host-header/LICENSE b/packages/middleware-host-header/LICENSE new file mode 100644 index 000000000000..e907b58668da --- /dev/null +++ b/packages/middleware-host-header/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/middleware-host-header/README.md b/packages/middleware-host-header/README.md new file mode 100644 index 000000000000..b274294e574d --- /dev/null +++ b/packages/middleware-host-header/README.md @@ -0,0 +1,4 @@ +# @aws-sdk/@aws-sdk/middleware-host-header + +[![NPM version](https://img.shields.io/npm/v/@aws-sdk/@aws-sdk/middleware-host-header/preview.svg)](https://www.npmjs.com/package/@aws-sdk/@aws-sdk/middleware-host-header) +[![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/@aws-sdk/middleware-host-header.svg)](https://www.npmjs.com/package/@aws-sdk/@aws-sdk/middleware-host-header) diff --git a/packages/middleware-host-header/package.json b/packages/middleware-host-header/package.json new file mode 100644 index 000000000000..d37b23d27d7b --- /dev/null +++ b/packages/middleware-host-header/package.json @@ -0,0 +1,26 @@ +{ + "name": "@aws-sdk/middleware-host-header", + "version": "0.1.0-preview.1", + "scripts": { + "prepublishOnly": "tsc", + "pretest": "tsc -p tsconfig.test.json", + "test": "jest" + }, + "main": "./build/index.js", + "types": "./build/index.d.ts", + "author": { + "name": "AWS SDK for JavaScript Team", + "url": "https://aws.amazon.com/javascript/" + }, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.8.0", + "@aws-sdk/types": "^0.1.0-preview.5", + "@aws-sdk/protocol-http": "^0.1.0-preview.1" + }, + "devDependencies": { + "@types/jest": "^24.0.12", + "typescript": "~3.4.0", + "jest": "^24.7.1" + } +} diff --git a/packages/middleware-host-header/src/index.ts b/packages/middleware-host-header/src/index.ts new file mode 100644 index 000000000000..d5a30f5cc9ea --- /dev/null +++ b/packages/middleware-host-header/src/index.ts @@ -0,0 +1,61 @@ +import { HttpRequest } from "@aws-sdk/protocol-http"; +import { + RequestHandler, + BuildMiddleware, + Provider, + Endpoint, + BuildHandlerOptions, + AbsoluteLocation, + Pluggable +} from "@aws-sdk/types"; + +export interface HostHeaderInputConfig {} +interface PreviouslyResolved { + requestHandler: RequestHandler; + endpoint: Provider; +} +export interface HostHeaderResolvedConfig { + requestHandler: RequestHandler; + endpoint: Provider; +} +export function resolveHostHeaderConfig( + input: T & PreviouslyResolved & HostHeaderInputConfig +): T & HostHeaderResolvedConfig { + return input; +} + +export const hostHeaderMiddleware = < + Input extends object, + Output extends object +>( + options: HostHeaderResolvedConfig +): BuildMiddleware => next => async args => { + if (!HttpRequest.isInstance(args.request)) return next(args); + const { request } = args; + const { handlerProtocol = "" } = options.requestHandler.metadata || {}; + //For H2 request, remove 'host' header and use ':authority' header instead + //reference: https://nodejs.org/dist/latest-v13.x/docs/api/errors.html#ERR_HTTP2_INVALID_CONNECTION_HEADERS + if (handlerProtocol.indexOf("h2") >= 0 && !request.headers[":authority"]) { + delete request.headers["host"]; + request.headers[":authority"] = ""; + //non-H2 request and 'host' header is not set, set the 'host' header to request's hostname. + } else if (!request.headers["host"]) { + request.headers["host"] = (await options.endpoint()).hostname; + } + return next(args); +}; + +export const hostHeaderMiddlewareOptions: BuildHandlerOptions & + AbsoluteLocation = { + name: "hostHeaderMiddleware", + step: "build", + tags: ["HOST"] +}; + +export const getHostHeaderPlugin = ( + options: HostHeaderResolvedConfig +): Pluggable => ({ + applyToStack: clientStack => { + clientStack.add(hostHeaderMiddleware(options), hostHeaderMiddlewareOptions); + } +}); diff --git a/packages/middleware-host-header/tsconfig.json b/packages/middleware-host-header/tsconfig.json new file mode 100644 index 000000000000..38b94cda274e --- /dev/null +++ b/packages/middleware-host-header/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "declaration": true, + "strict": true, + "sourceMap": true, + "downlevelIteration": true, + "importHelpers": true, + "noEmitHelpers": true, + "lib": [ + "es5", + "es2015.promise", + "es2015.collection", + "es2015.iterable", + "es2015.symbol.wellknown" + ], + "rootDir": "./src", + "outDir": "./build", + "incremental": true + } +} diff --git a/packages/middleware-host-header/tsconfig.test.json b/packages/middleware-host-header/tsconfig.test.json new file mode 100644 index 000000000000..17d0f1b7321f --- /dev/null +++ b/packages/middleware-host-header/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": false, + "inlineSourceMap": true, + "inlineSources": true, + "rootDir": "./src", + "outDir": "./build", + "incremental": true + } +} diff --git a/packages/node-http-handler/src/node-http-handler.spec.ts b/packages/node-http-handler/src/node-http-handler.spec.ts index 9f11af14e3ae..61e5727aa97f 100644 --- a/packages/node-http-handler/src/node-http-handler.spec.ts +++ b/packages/node-http-handler/src/node-http-handler.spec.ts @@ -41,6 +41,10 @@ describe("NodeHttpHandler", () => { afterAll(() => { mockHttpServer.close(); }); + it("has metadata", () => { + const nodeHttpHandler = new NodeHttpHandler(); + expect(nodeHttpHandler.metadata.handlerProtocol).toContain("http/1.1"); + }); it("can send http requests", async () => { const mockResponse = { statusCode: 200, diff --git a/packages/node-http-handler/src/node-http-handler.ts b/packages/node-http-handler/src/node-http-handler.ts index cac49daed570..e0d7dc50ce93 100644 --- a/packages/node-http-handler/src/node-http-handler.ts +++ b/packages/node-http-handler/src/node-http-handler.ts @@ -33,6 +33,8 @@ export class NodeHttpHandler implements HttpHandler { private readonly httpsAgent: https.Agent; private readonly connectionTimeout?: number; private readonly socketTimeout?: number; + // Node http handler is hard-coded to http/1.1: https://github.com/nodejs/node/blob/ff5664b83b89c55e4ab5d5f60068fb457f1f5872/lib/_http_server.js#L286 + public readonly metadata = { handlerProtocol: "http/1.1" }; constructor({ connectionTimeout, diff --git a/packages/node-http-handler/src/node-http2-handler.spec.ts b/packages/node-http-handler/src/node-http2-handler.spec.ts index 1e82d5e73987..b54c4663ec7b 100644 --- a/packages/node-http-handler/src/node-http2-handler.spec.ts +++ b/packages/node-http-handler/src/node-http2-handler.spec.ts @@ -44,6 +44,10 @@ describe("NodeHttp2Handler", () => { mockH2Server.close(); }); + it("has metadata", () => { + expect(nodeH2Handler.metadata.handlerProtocol).toContain("h2"); + }); + describe("connectionPool", () => { it("is empty on initialization", () => { // @ts-ignore: access private property diff --git a/packages/node-http-handler/src/node-http2-handler.ts b/packages/node-http-handler/src/node-http2-handler.ts index 42db5b2bba51..0f302ebb2844 100644 --- a/packages/node-http-handler/src/node-http2-handler.ts +++ b/packages/node-http-handler/src/node-http2-handler.ts @@ -27,6 +27,7 @@ export interface NodeHttp2Options { export class NodeHttp2Handler implements HttpHandler { private readonly connectionPool: Map; + public readonly metadata = { handlerProtocol: "h2" }; constructor(private readonly http2Options: NodeHttp2Options = {}) { this.connectionPool = new Map(); diff --git a/packages/smithy-client/src/client.ts b/packages/smithy-client/src/client.ts index 696975e896e1..fefa4cf12ab3 100644 --- a/packages/smithy-client/src/client.ts +++ b/packages/smithy-client/src/client.ts @@ -70,7 +70,7 @@ export class Client< optionsOrCb?: HandlerOptions | ((err: any, data?: OutputType) => void), cb?: (err: any, data?: OutputType) => void ): Promise | void { - const options = typeof optionsOrCb !== "function" ? optionsOrCb : {}; + const options = typeof optionsOrCb !== "function" ? optionsOrCb : undefined; const callback = typeof optionsOrCb === "function" ? (optionsOrCb as ((err: any, data?: OutputType) => void)) diff --git a/packages/types/src/transfer.ts b/packages/types/src/transfer.ts index 2f630eadf1a9..2c673247bd5f 100644 --- a/packages/types/src/transfer.ts +++ b/packages/types/src/transfer.ts @@ -5,9 +5,21 @@ export interface RequestHandler< ResponseType, HandlerOptions = {} > { + /** + * metadata contains information of a handler. For example + * 'h2' refers this handler is for handling HTTP/2 requests, + * whereas 'h1' refers handling HTTP1 requests + */ + metadata?: RequestHandlerMetadata; destroy?: () => void; handle: ( request: RequestType, handlerOptions: HandlerOptions ) => Promise>; } + +export interface RequestHandlerMetadata { + // This infers request handler's protocol + // valid values are stated: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids + handlerProtocol: string; +}