Skip to content

Commit c4d9e62

Browse files
committed
chore(middleware-flexible-checksums): use ResponseChecksumValidation
1 parent 08bec3a commit c4d9e62

File tree

3 files changed

+68
-40
lines changed

3 files changed

+68
-40
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
StreamHasher,
1010
} from "@smithy/types";
1111

12-
import { RequestChecksumCalculation } from "./constants";
12+
import { RequestChecksumCalculation, ResponseChecksumValidation } from "./constants";
1313

1414
export interface PreviouslyResolved {
1515
/**
@@ -39,6 +39,11 @@ export interface PreviouslyResolved {
3939
*/
4040
requestChecksumCalculation: Provider<RequestChecksumCalculation>;
4141

42+
/**
43+
* Determines when a checksum will be calculated for response payloads
44+
*/
45+
responseChecksumValidation: Provider<ResponseChecksumValidation>;
46+
4247
/**
4348
* A constructor for a class implementing the {@link Hash} interface that computes SHA1 hashes.
4449
* @internal

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

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { HttpRequest } from "@smithy/protocol-http";
22
import { DeserializeHandlerArguments } from "@smithy/types";
33

44
import { PreviouslyResolved } from "./configuration";
5-
import { ChecksumAlgorithm } from "./constants";
5+
import { ChecksumAlgorithm, ResponseChecksumValidation } from "./constants";
66
import { flexibleChecksumsResponseMiddleware } from "./flexibleChecksumsResponseMiddleware";
77
import { getChecksumLocationName } from "./getChecksumLocationName";
88
import { FlexibleChecksumsMiddlewareConfig } from "./getFlexibleChecksumsPlugin";
@@ -23,7 +23,9 @@ describe(flexibleChecksumsResponseMiddleware.name, () => {
2323
commandName: "mockCommandName",
2424
};
2525

26-
const mockConfig = {} as PreviouslyResolved;
26+
const mockConfig = {
27+
responseChecksumValidation: () => Promise.resolve(ResponseChecksumValidation.WHEN_REQUIRED),
28+
} as PreviouslyResolved;
2729
const mockRequestValidationModeMember = "ChecksumEnabled";
2830
const mockResponseAlgorithms = [ChecksumAlgorithm.CRC32, ChecksumAlgorithm.CRC32C];
2931
const mockMiddlewareConfig = {
@@ -59,52 +61,66 @@ describe(flexibleChecksumsResponseMiddleware.name, () => {
5961
});
6062

6163
describe("skips", () => {
62-
it("if not an instance of HttpRequest", async () => {
63-
const { isInstance } = HttpRequest;
64-
(isInstance as unknown as jest.Mock).mockReturnValue(false);
65-
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, mockContext);
64+
it("if requestValidationModeMember is not defined", async () => {
65+
const mockMwConfig = Object.assign({}, mockMiddlewareConfig) as FlexibleChecksumsMiddlewareConfig;
66+
delete mockMwConfig.requestValidationModeMember;
67+
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMwConfig)(mockNext, mockContext);
6668
await handler(mockArgs);
6769
expect(validateChecksumFromResponse).not.toHaveBeenCalled();
70+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
6871
});
6972

70-
describe("response checksum", () => {
71-
it("if requestValidationModeMember is not defined", async () => {
72-
const mockMwConfig = Object.assign({}, mockMiddlewareConfig) as FlexibleChecksumsMiddlewareConfig;
73-
delete mockMwConfig.requestValidationModeMember;
74-
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMwConfig)(mockNext, mockContext);
75-
await handler(mockArgs);
76-
expect(validateChecksumFromResponse).not.toHaveBeenCalled();
77-
});
73+
it("if requestValidationModeMember is not enabled in input", async () => {
74+
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, mockContext);
7875

79-
it("if requestValidationModeMember is not enabled in input", async () => {
80-
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, mockContext);
81-
await handler({ ...mockArgs, input: {} });
82-
expect(validateChecksumFromResponse).not.toHaveBeenCalled();
83-
});
76+
const mockArgsWithoutEnabled = { ...mockArgs, input: {} };
77+
await handler(mockArgsWithoutEnabled);
78+
expect(validateChecksumFromResponse).not.toHaveBeenCalled();
79+
expect(mockNext).toHaveBeenCalledWith(mockArgsWithoutEnabled);
80+
});
8481

85-
it("if checksum is for S3 whole-object multipart GET", async () => {
86-
(isChecksumWithPartNumber as jest.Mock).mockReturnValue(true);
87-
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {
88-
clientName: "S3Client",
89-
commandName: "GetObjectCommand",
90-
});
91-
await handler(mockArgs);
92-
expect(isChecksumWithPartNumber).toHaveBeenCalledTimes(1);
93-
expect(isChecksumWithPartNumber).toHaveBeenCalledWith(mockChecksum);
94-
expect(validateChecksumFromResponse).not.toHaveBeenCalled();
82+
it("if checksum is for S3 whole-object multipart GET", async () => {
83+
(isChecksumWithPartNumber as jest.Mock).mockReturnValue(true);
84+
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, {
85+
clientName: "S3Client",
86+
commandName: "GetObjectCommand",
9587
});
88+
await handler(mockArgs);
89+
expect(isChecksumWithPartNumber).toHaveBeenCalledTimes(1);
90+
expect(isChecksumWithPartNumber).toHaveBeenCalledWith(mockChecksum);
91+
expect(validateChecksumFromResponse).not.toHaveBeenCalled();
92+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
9693
});
9794
});
9895

9996
describe("validates checksum from response header", () => {
100-
it("generic case", async () => {
97+
it("if requestValidationModeMember is enabled in input", async () => {
10198
const handler = flexibleChecksumsResponseMiddleware(mockConfig, mockMiddlewareConfig)(mockNext, mockContext);
10299

103100
await handler(mockArgs);
104101
expect(validateChecksumFromResponse).toHaveBeenCalledWith(mockResult.response, {
105102
config: mockConfig,
106103
responseAlgorithms: mockResponseAlgorithms,
107104
});
105+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
106+
});
107+
108+
it(`if requestValidationModeMember is not enabled in input, but responseChecksumValidation returns ${ResponseChecksumValidation.WHEN_SUPPORTED}`, async () => {
109+
const mockConfigWithResponseChecksumValidationSupported = {
110+
...mockConfig,
111+
responseChecksumValidation: () => Promise.resolve(ResponseChecksumValidation.WHEN_SUPPORTED),
112+
};
113+
const handler = flexibleChecksumsResponseMiddleware(
114+
mockConfigWithResponseChecksumValidationSupported,
115+
mockMiddlewareConfig
116+
)(mockNext, mockContext);
117+
118+
await handler({ ...mockArgs, input: {} });
119+
expect(validateChecksumFromResponse).toHaveBeenCalledWith(mockResult.response, {
120+
config: mockConfigWithResponseChecksumValidationSupported,
121+
responseAlgorithms: mockResponseAlgorithms,
122+
});
123+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
108124
});
109125

110126
it("if checksum is for S3 GET without part number", async () => {
@@ -120,6 +136,7 @@ describe(flexibleChecksumsResponseMiddleware.name, () => {
120136
config: mockConfig,
121137
responseAlgorithms: mockResponseAlgorithms,
122138
});
139+
expect(mockNext).toHaveBeenCalledWith(mockArgs);
123140
});
124141
});
125142
});

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from "@smithy/types";
1111

1212
import { PreviouslyResolved } from "./configuration";
13-
import { ChecksumAlgorithm } from "./constants";
13+
import { ChecksumAlgorithm, ResponseChecksumValidation } from "./constants";
1414
import { getChecksumAlgorithmListForResponse } from "./getChecksumAlgorithmListForResponse";
1515
import { getChecksumLocationName } from "./getChecksumLocationName";
1616
import { isChecksumWithPartNumber } from "./isChecksumWithPartNumber";
@@ -37,8 +37,8 @@ export interface FlexibleChecksumsResponseMiddlewareConfig {
3737
*/
3838
export const flexibleChecksumsResponseMiddlewareOptions: RelativeMiddlewareOptions = {
3939
name: "flexibleChecksumsResponseMiddleware",
40-
toMiddleware: "deserializerMiddleware",
41-
relation: "after",
40+
toMiddleware: "serializerMiddleware",
41+
relation: "before",
4242
tags: ["BODY_CHECKSUM"],
4343
override: true,
4444
};
@@ -58,19 +58,25 @@ export const flexibleChecksumsResponseMiddleware =
5858
context: HandlerExecutionContext
5959
): DeserializeHandler<any, Output> =>
6060
async (args: DeserializeHandlerArguments<any>): Promise<DeserializeHandlerOutput<Output>> => {
61-
if (!HttpRequest.isInstance(args.request)) {
62-
return next(args);
61+
const input = args.input;
62+
const { requestValidationModeMember, responseAlgorithms } = middlewareConfig;
63+
const responseChecksumValidation = await config.responseChecksumValidation();
64+
65+
const isResponseChecksumValidationNeeded =
66+
requestValidationModeMember &&
67+
(input[requestValidationModeMember] === "ENABLED" ||
68+
responseChecksumValidation === ResponseChecksumValidation.WHEN_SUPPORTED);
69+
70+
if (isResponseChecksumValidationNeeded) {
71+
input[requestValidationModeMember] = "ENABLED";
6372
}
6473

65-
const input = args.input;
6674
const result = await next(args);
6775

6876
const response = result.response as HttpResponse;
6977
let collectedStream: Uint8Array | undefined = undefined;
7078

71-
const { requestValidationModeMember, responseAlgorithms } = middlewareConfig;
72-
// @ts-ignore Element implicitly has an 'any' type for input[requestValidationModeMember]
73-
if (requestValidationModeMember && input[requestValidationModeMember] === "ENABLED") {
79+
if (isResponseChecksumValidationNeeded) {
7480
const { clientName, commandName } = context;
7581
const isS3WholeObjectMultipartGetResponseChecksum =
7682
clientName === "S3Client" &&

0 commit comments

Comments
 (0)