Skip to content

Commit 81c5b0a

Browse files
committed
chore: add utility hasHeaderWithPrefix
1 parent 5893fb7 commit 81c5b0a

File tree

4 files changed

+63
-23
lines changed

4 files changed

+63
-23
lines changed

packages/middleware-flexible-checksums/src/flexibleChecksumsMiddleware.spec.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { setFeature } from "@aws-sdk/core";
21
import { HttpRequest } from "@smithy/protocol-http";
32
import { BuildHandlerArguments } from "@smithy/types";
43
import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest";
@@ -9,6 +8,7 @@ import { flexibleChecksumsMiddleware } from "./flexibleChecksumsMiddleware";
98
import { getChecksumAlgorithmForRequest } from "./getChecksumAlgorithmForRequest";
109
import { getChecksumLocationName } from "./getChecksumLocationName";
1110
import { hasHeader } from "./hasHeader";
11+
import { hasHeaderWithPrefix } from "./hasHeaderWithPrefix";
1212
import { isStreaming } from "./isStreaming";
1313
import { selectChecksumAlgorithmFunction } from "./selectChecksumAlgorithmFunction";
1414
import { stringHasher } from "./stringHasher";
@@ -18,6 +18,7 @@ vi.mock("@smithy/protocol-http");
1818
vi.mock("./getChecksumAlgorithmForRequest");
1919
vi.mock("./getChecksumLocationName");
2020
vi.mock("./hasHeader");
21+
vi.mock("./hasHeaderWithPrefix");
2122
vi.mock("./isStreaming");
2223
vi.mock("./selectChecksumAlgorithmFunction");
2324
vi.mock("./stringHasher");
@@ -43,11 +44,11 @@ describe(flexibleChecksumsMiddleware.name, () => {
4344

4445
beforeEach(() => {
4546
mockNext.mockResolvedValueOnce(mockResult);
46-
const { isInstance } = HttpRequest;
47-
(isInstance as unknown as any).mockReturnValue(true);
47+
vi.mocked(HttpRequest.isInstance).mockReturnValue(true);
4848
vi.mocked(getChecksumAlgorithmForRequest).mockReturnValue(ChecksumAlgorithm.CRC32);
4949
vi.mocked(getChecksumLocationName).mockReturnValue(mockChecksumLocationName);
5050
vi.mocked(hasHeader).mockReturnValue(true);
51+
vi.mocked(hasHeaderWithPrefix).mockReturnValue(false);
5152
vi.mocked(isStreaming).mockReturnValue(false);
5253
vi.mocked(selectChecksumAlgorithmFunction).mockReturnValue(mockChecksumAlgorithmFunction);
5354
});
@@ -59,8 +60,7 @@ describe(flexibleChecksumsMiddleware.name, () => {
5960

6061
describe("skips", () => {
6162
it("if not an instance of HttpRequest", async () => {
62-
const { isInstance } = HttpRequest;
63-
(isInstance as unknown as any).mockReturnValue(false);
63+
vi.mocked(HttpRequest.isInstance).mockReturnValue(false);
6464
const handler = flexibleChecksumsMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {});
6565
await handler(mockArgs);
6666
expect(getChecksumAlgorithmForRequest).not.toHaveBeenCalled();
@@ -71,35 +71,32 @@ describe(flexibleChecksumsMiddleware.name, () => {
7171
vi.mocked(getChecksumAlgorithmForRequest).mockReturnValue(undefined);
7272
const handler = flexibleChecksumsMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {});
7373
await handler(mockArgs);
74+
expect(hasHeaderWithPrefix).toHaveBeenCalledTimes(1);
7475
expect(getChecksumLocationName).not.toHaveBeenCalled();
7576
expect(mockNext).toHaveBeenCalledWith(mockArgs);
7677
expect(selectChecksumAlgorithmFunction).not.toHaveBeenCalled();
7778
expect(getChecksumAlgorithmForRequest).toHaveBeenCalledTimes(1);
7879
});
7980

80-
it.each([
81-
...Object.values(ChecksumAlgorithm).map((val) => `x-amz-checksum-${val.toLowerCase()}`), // all current checksum locations
82-
...Object.values(ChecksumAlgorithm).map((val) => `X-AMZ-CHECKSUM-${val}`), // all current checksum locations in uppercase
83-
`x-amz-checksum-emoji`, // any checksum post prefix
84-
`X-AMZ-CHECKSUM-EMOJI`, // any checksum post prefix in uppercase
85-
])("skip if header '%s' is already present", async (headerName) => {
81+
it("skip if header is already present", async () => {
8682
const handler = flexibleChecksumsMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {});
87-
const mockHeadersWithChecksumHeader = { ...mockHeaders, [headerName]: "mockHeaderValue" };
88-
const mockArgsWithChecksumHeader = {
89-
...mockArgs,
90-
request: { ...mockRequest, headers: mockHeadersWithChecksumHeader },
91-
};
92-
await handler(mockArgsWithChecksumHeader);
83+
vi.mocked(hasHeaderWithPrefix).mockReturnValue(true);
84+
85+
await handler(mockArgs);
86+
87+
expect(hasHeaderWithPrefix).toHaveBeenCalledTimes(1);
9388
expect(getChecksumLocationName).not.toHaveBeenCalled();
9489
expect(selectChecksumAlgorithmFunction).not.toHaveBeenCalled();
9590
expect(hasHeader).not.toHaveBeenCalled();
96-
expect(mockNext).toHaveBeenCalledWith(mockArgsWithChecksumHeader);
91+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
9792
});
9893
});
9994
});
10095

10196
describe("adds checksum in the request header", () => {
10297
afterEach(() => {
98+
expect(HttpRequest.isInstance).toHaveBeenCalledTimes(1);
99+
expect(hasHeaderWithPrefix).toHaveBeenCalledTimes(1);
103100
expect(getChecksumAlgorithmForRequest).toHaveBeenCalledTimes(1);
104101
expect(getChecksumLocationName).toHaveBeenCalledTimes(1);
105102
expect(selectChecksumAlgorithmFunction).toHaveBeenCalledTimes(1);

packages/middleware-flexible-checksums/src/flexibleChecksumsMiddleware.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ import {
1111
} from "@smithy/types";
1212

1313
import { PreviouslyResolved } from "./configuration";
14-
import { ChecksumAlgorithm, RequestChecksumCalculation } from "./constants";
14+
import { ChecksumAlgorithm } from "./constants";
1515
import { getChecksumAlgorithmForRequest } from "./getChecksumAlgorithmForRequest";
1616
import { getChecksumLocationName } from "./getChecksumLocationName";
1717
import { hasHeader } from "./hasHeader";
18+
import { hasHeaderWithPrefix } from "./hasHeaderWithPrefix";
1819
import { isStreaming } from "./isStreaming";
1920
import { selectChecksumAlgorithmFunction } from "./selectChecksumAlgorithmFunction";
2021
import { stringHasher } from "./stringHasher";
@@ -64,10 +65,8 @@ export const flexibleChecksumsMiddleware =
6465
return next(args);
6566
}
6667

67-
for (const header of Object.keys(args.request.headers)) {
68-
if (header.toLowerCase().startsWith("x-amz-checksum-")) {
69-
return next(args);
70-
}
68+
if (hasHeaderWithPrefix("x-amz-checksum-", args.request.headers)) {
69+
return next(args);
7170
}
7271

7372
const { request, input } = args;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { HeaderBag } from "@smithy/types";
2+
import { describe, expect, test as it } from "vitest";
3+
4+
import { hasHeaderWithPrefix } from "./hasHeaderWithPrefix";
5+
6+
describe(hasHeaderWithPrefix.name, () => {
7+
const mockHeaders: HeaderBag = {
8+
"header-prefix-lowercase-1": "header-value-1",
9+
"HEADER-PREFIX-UPPERCASE-2": "header-value-2",
10+
};
11+
12+
describe("contains header prefix", () => {
13+
it("when headerPrefix is exact", () => {
14+
expect(hasHeaderWithPrefix("header-prefix-lowercase-", mockHeaders)).toBe(true);
15+
});
16+
17+
it("when headerPrefix is in different case", () => {
18+
expect(hasHeaderWithPrefix("HEADER-PREFIX-LOWERCASE-", mockHeaders)).toBe(true);
19+
});
20+
21+
it("when headerPrefix in headers is in different case", () => {
22+
expect(hasHeaderWithPrefix("header-prefix-uppercase-", mockHeaders)).toBe(true);
23+
});
24+
});
25+
26+
it("doesn't contain header with headerPrefix", () => {
27+
expect(hasHeaderWithPrefix("header-prefix-3", mockHeaders)).toBe(false);
28+
});
29+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { HeaderBag } from "@smithy/types";
2+
3+
/**
4+
* Returns true if header with headerPrefix is present in headers.
5+
* Comparisons are case-insensitive.
6+
*/
7+
export const hasHeaderWithPrefix = (headerPrefix: string, headers: HeaderBag): boolean => {
8+
const soughtHeaderPrefix = headerPrefix.toLowerCase();
9+
for (const headerName of Object.keys(headers)) {
10+
if (headerName.toLowerCase().startsWith(soughtHeaderPrefix)) {
11+
return true;
12+
}
13+
}
14+
return false;
15+
};

0 commit comments

Comments
 (0)