Skip to content

Commit e1678f8

Browse files
authored
fix(middleware-flexible-checksums): skip checksum computation if provided (#6745)
1 parent a116e07 commit e1678f8

File tree

4 files changed

+63
-14
lines changed

4 files changed

+63
-14
lines changed

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

+14-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { flexibleChecksumsMiddleware } from "./flexibleChecksumsMiddleware";
88
import { getChecksumAlgorithmForRequest } from "./getChecksumAlgorithmForRequest";
99
import { getChecksumLocationName } from "./getChecksumLocationName";
1010
import { hasHeader } from "./hasHeader";
11+
import { hasHeaderWithPrefix } from "./hasHeaderWithPrefix";
1112
import { isStreaming } from "./isStreaming";
1213
import { selectChecksumAlgorithmFunction } from "./selectChecksumAlgorithmFunction";
1314
import { stringHasher } from "./stringHasher";
@@ -16,6 +17,7 @@ vi.mock("@smithy/protocol-http");
1617
vi.mock("./getChecksumAlgorithmForRequest");
1718
vi.mock("./getChecksumLocationName");
1819
vi.mock("./hasHeader");
20+
vi.mock("./hasHeaderWithPrefix");
1921
vi.mock("./isStreaming");
2022
vi.mock("./selectChecksumAlgorithmFunction");
2123
vi.mock("./stringHasher");
@@ -44,6 +46,7 @@ describe(flexibleChecksumsMiddleware.name, () => {
4446
vi.mocked(getChecksumAlgorithmForRequest).mockReturnValue(ChecksumAlgorithm.MD5);
4547
vi.mocked(getChecksumLocationName).mockReturnValue(mockChecksumLocationName);
4648
vi.mocked(hasHeader).mockReturnValue(true);
49+
vi.mocked(hasHeaderWithPrefix).mockReturnValue(false);
4750
vi.mocked(isStreaming).mockReturnValue(false);
4851
vi.mocked(selectChecksumAlgorithmFunction).mockReturnValue(mockChecksumAlgorithmFunction);
4952
});
@@ -63,31 +66,28 @@ describe(flexibleChecksumsMiddleware.name, () => {
6366
});
6467

6568
describe("request checksum", () => {
66-
afterEach(() => {
67-
expect(getChecksumAlgorithmForRequest).toHaveBeenCalledTimes(1);
68-
});
69-
7069
it("if checksumAlgorithm is not defined", async () => {
7170
vi.mocked(getChecksumAlgorithmForRequest).mockReturnValue(undefined);
7271
const handler = flexibleChecksumsMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {});
7372
await handler(mockArgs);
73+
expect(hasHeaderWithPrefix).toHaveBeenCalledTimes(1);
7474
expect(getChecksumLocationName).not.toHaveBeenCalled();
7575
expect(mockNext).toHaveBeenCalledWith(mockArgs);
7676
expect(selectChecksumAlgorithmFunction).not.toHaveBeenCalled();
77+
expect(getChecksumAlgorithmForRequest).toHaveBeenCalledTimes(1);
7778
});
7879

7980
it("if header is already present", async () => {
8081
const handler = flexibleChecksumsMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {});
81-
const mockHeadersWithChecksumHeader = { ...mockHeaders, [mockChecksumLocationName]: "mockHeaderValue" };
82-
const mockArgsWithChecksumHeader = {
83-
...mockArgs,
84-
request: { ...mockRequest, headers: mockHeadersWithChecksumHeader },
85-
};
86-
await handler(mockArgsWithChecksumHeader);
87-
expect(getChecksumLocationName).toHaveBeenCalledWith(ChecksumAlgorithm.MD5);
88-
expect(selectChecksumAlgorithmFunction).toHaveBeenCalledWith(ChecksumAlgorithm.MD5, mockConfig);
89-
expect(mockNext).toHaveBeenCalledWith(mockArgsWithChecksumHeader);
90-
expect(hasHeader).toHaveBeenCalledWith(mockChecksumLocationName, mockHeadersWithChecksumHeader);
82+
vi.mocked(hasHeaderWithPrefix).mockReturnValue(true);
83+
84+
await handler(mockArgs);
85+
86+
expect(hasHeaderWithPrefix).toHaveBeenCalledTimes(1);
87+
expect(getChecksumLocationName).not.toHaveBeenCalled();
88+
expect(selectChecksumAlgorithmFunction).not.toHaveBeenCalled();
89+
expect(hasHeader).not.toHaveBeenCalled();
90+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
9191
});
9292
});
9393
});

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

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ 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,6 +65,10 @@ export const flexibleChecksumsMiddleware =
6465
return next(args);
6566
}
6667

68+
if (hasHeaderWithPrefix("x-amz-checksum-", args.request.headers)) {
69+
return next(args);
70+
}
71+
6772
const { request, input } = args;
6873
const { body: requestBody, headers } = request;
6974
const { base64Encoder, streamHasher } = config;
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+
});
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)