From 1b2292357f183e8fa744d0458e4e779dad98b5d6 Mon Sep 17 00:00:00 2001 From: George Fu Date: Mon, 30 Sep 2024 16:34:14 +0000 Subject: [PATCH] fix(signature-v4): add hoistable headers config --- .changeset/happy-emus-crash.md | 6 ++++ packages/signature-v4/src/SignatureV4.ts | 3 +- .../src/moveHeadersToQuery.spec.ts | 32 +++++++++++++++++++ .../signature-v4/src/moveHeadersToQuery.ts | 7 ++-- packages/types/src/signature.ts | 6 ++++ 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 .changeset/happy-emus-crash.md diff --git a/.changeset/happy-emus-crash.md b/.changeset/happy-emus-crash.md new file mode 100644 index 00000000000..014120e3f05 --- /dev/null +++ b/.changeset/happy-emus-crash.md @@ -0,0 +1,6 @@ +--- +"@smithy/signature-v4": minor +"@smithy/types": minor +--- + +configurable hoisted headers diff --git a/packages/signature-v4/src/SignatureV4.ts b/packages/signature-v4/src/SignatureV4.ts index 11a27d77c96..fdcad4b4825 100644 --- a/packages/signature-v4/src/SignatureV4.ts +++ b/packages/signature-v4/src/SignatureV4.ts @@ -131,6 +131,7 @@ export class SignatureV4 implements RequestPresigner, RequestSigner, StringSigne unsignableHeaders, unhoistableHeaders, signableHeaders, + hoistableHeaders, signingRegion, signingService, } = options; @@ -146,7 +147,7 @@ export class SignatureV4 implements RequestPresigner, RequestSigner, StringSigne } const scope = createScope(shortDate, region, signingService ?? this.service); - const request = moveHeadersToQuery(prepareRequest(originalRequest), { unhoistableHeaders }); + const request = moveHeadersToQuery(prepareRequest(originalRequest), { unhoistableHeaders, hoistableHeaders }); if (credentials.sessionToken) { request.query[TOKEN_QUERY_PARAM] = credentials.sessionToken; diff --git a/packages/signature-v4/src/moveHeadersToQuery.spec.ts b/packages/signature-v4/src/moveHeadersToQuery.spec.ts index 55c36c5bc5b..855abd98926 100644 --- a/packages/signature-v4/src/moveHeadersToQuery.spec.ts +++ b/packages/signature-v4/src/moveHeadersToQuery.spec.ts @@ -99,4 +99,36 @@ describe("moveHeadersToQuery", () => { SNAP: "crackle, pop", }); }); + + it("should obey hoistableHeaders configuration over unhoistableHeaders", () => { + const req = moveHeadersToQuery( + new HttpRequest({ + ...minimalRequest, + headers: { + Host: "www.example.com", + "X-Amz-Website-Redirect-Location": "/index.html", + Foo: "bar", + fizz: "buzz", + SNAP: "crackle, pop", + "X-Amz-Storage-Class": "STANDARD_IA", + }, + }), + { + hoistableHeaders: new Set(["x-amz-website-redirect-location", "snap"]), + unhoistableHeaders: new Set(["x-amz-website-redirect-location"]), + } + ); + + expect(req.query).toEqual({ + SNAP: "crackle, pop", + "X-Amz-Storage-Class": "STANDARD_IA", + "X-Amz-Website-Redirect-Location": "/index.html", + }); + + expect(req.headers).toEqual({ + Host: "www.example.com", + Foo: "bar", + fizz: "buzz", + }); + }); }); diff --git a/packages/signature-v4/src/moveHeadersToQuery.ts b/packages/signature-v4/src/moveHeadersToQuery.ts index c858bace0fa..6d17556afa3 100644 --- a/packages/signature-v4/src/moveHeadersToQuery.ts +++ b/packages/signature-v4/src/moveHeadersToQuery.ts @@ -6,12 +6,15 @@ import type { HttpRequest as IHttpRequest, QueryParameterBag } from "@smithy/typ */ export const moveHeadersToQuery = ( request: IHttpRequest, - options: { unhoistableHeaders?: Set } = {} + options: { unhoistableHeaders?: Set; hoistableHeaders?: Set } = {} ): IHttpRequest & { query: QueryParameterBag } => { const { headers, query = {} as QueryParameterBag } = HttpRequest.clone(request); for (const name of Object.keys(headers)) { const lname = name.toLowerCase(); - if (lname.slice(0, 6) === "x-amz-" && !options.unhoistableHeaders?.has(lname)) { + if ( + (lname.slice(0, 6) === "x-amz-" && !options.unhoistableHeaders?.has(lname)) || + options.hoistableHeaders?.has(lname) + ) { query[name] = headers[name]; delete headers[name]; } diff --git a/packages/types/src/signature.ts b/packages/types/src/signature.ts index f1a2b3f89f3..8eb82fc6f9a 100644 --- a/packages/types/src/signature.ts +++ b/packages/types/src/signature.ts @@ -75,6 +75,12 @@ export interface RequestPresigningArguments extends RequestSigningArguments { * lower case and then checked for existence in the unhoistableHeaders set. */ unhoistableHeaders?: Set; + + /** + * This overrides any values set by unhoistableHeaders. + * These headers will be hoisted into the query string and signed. + */ + hoistableHeaders?: Set; } /**