Skip to content

Commit dfda129

Browse files
authored
chore(middleware-user-agent): add feature detection for account-id, s3-express, lib-dynamodb (#6541)
1 parent 544120e commit dfda129

File tree

12 files changed

+144
-3
lines changed

12 files changed

+144
-3
lines changed

lib/lib-dynamodb/src/baseCommand/DynamoDBDocumentClientCommand.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { setFeature } from "@aws-sdk/core";
12
import { Command as $Command } from "@smithy/smithy-client";
23
import {
34
DeserializeHandler,
@@ -51,6 +52,7 @@ export abstract class DynamoDBDocumentClientCommand<
5152
async (
5253
args: InitializeHandlerArguments<Input | BaseInput>
5354
): Promise<InitializeHandlerOutput<Output | BaseOutput>> => {
55+
setFeature(context, "DDB_MAPPER", "d");
5456
args.input = marshallInput(this.input, this.inputKeyNodes, marshallOptions);
5557
context.dynamoDbDocumentClientOptions =
5658
context.dynamoDbDocumentClientOptions || DynamoDBDocumentClientCommand.defaultLogFilterOverrides;

packages/middleware-flexible-checksums/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"dependencies": {
3131
"@aws-crypto/crc32": "5.2.0",
3232
"@aws-crypto/crc32c": "5.2.0",
33+
"@aws-sdk/core": "*",
3334
"@aws-sdk/types": "*",
3435
"@smithy/is-array-buffer": "^3.0.0",
3536
"@smithy/node-config-provider": "^3.1.8",

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

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { setFeature } from "@aws-sdk/core";
12
import { HttpRequest } from "@smithy/protocol-http";
23
import {
34
BuildHandler,
@@ -10,6 +11,7 @@ import {
1011
} from "@smithy/types";
1112

1213
import { PreviouslyResolved } from "./configuration";
14+
import { ChecksumAlgorithm } from "./constants";
1315
import { getChecksumAlgorithmForRequest } from "./getChecksumAlgorithmForRequest";
1416
import { getChecksumLocationName } from "./getChecksumLocationName";
1517
import { hasHeader } from "./hasHeader";
@@ -72,6 +74,20 @@ export const flexibleChecksumsMiddleware =
7274
let updatedHeaders = headers;
7375

7476
if (checksumAlgorithm) {
77+
switch (checksumAlgorithm) {
78+
case ChecksumAlgorithm.CRC32:
79+
setFeature(context, "FLEXIBLE_CHECKSUMS_REQ_CRC32", "U");
80+
break;
81+
case ChecksumAlgorithm.CRC32C:
82+
setFeature(context, "FLEXIBLE_CHECKSUMS_REQ_CRC32C", "V");
83+
break;
84+
case ChecksumAlgorithm.SHA1:
85+
setFeature(context, "FLEXIBLE_CHECKSUMS_REQ_SHA1", "X");
86+
break;
87+
case ChecksumAlgorithm.SHA256:
88+
setFeature(context, "FLEXIBLE_CHECKSUMS_REQ_SHA256", "Y");
89+
break;
90+
}
7591
const checksumLocationName = getChecksumLocationName(checksumAlgorithm);
7692
const checksumAlgorithmFn = selectChecksumAlgorithmFunction(checksumAlgorithm, config);
7793
if (isStreaming(requestBody)) {

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

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { S3 } from "@aws-sdk/client-s3";
1+
import { ChecksumAlgorithm, S3 } from "@aws-sdk/client-s3";
22
import { Transform } from "stream";
33

44
import { requireRequestsFrom } from "../../../private/aws-util-test/src";
@@ -124,5 +124,33 @@ describe("middleware-flexible-checksums", () => {
124124

125125
expect.hasAssertions();
126126
});
127+
128+
describe("features", () => {
129+
[
130+
["SHA256", "Y"],
131+
["SHA1", "X"],
132+
["CRC32", "U"],
133+
["CRC32C", "V"],
134+
].forEach(([algo, id]) => {
135+
it(`should feature-detect checksum ${algo}=${id}`, async () => {
136+
const client = new S3({ region: "us-west-2", logger });
137+
138+
requireRequestsFrom(client).toMatch({
139+
headers: {
140+
"user-agent": new RegExp(`(.*?) m\/${id}$`),
141+
},
142+
});
143+
144+
await client.putObject({
145+
Bucket: "b",
146+
Key: "k",
147+
Body: "abcd",
148+
ChecksumAlgorithm: algo as ChecksumAlgorithm,
149+
});
150+
151+
expect.hasAssertions();
152+
});
153+
});
154+
});
127155
});
128156
});

packages/middleware-sdk-s3/src/s3-express/functions/s3ExpressMiddleware.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { setFeature } from "@aws-sdk/core";
12
import { AwsCredentialIdentity } from "@aws-sdk/types";
23
import { HttpRequest } from "@smithy/protocol-http";
34
import {
@@ -51,6 +52,7 @@ export const s3ExpressMiddleware: (options: S3ExpressResolvedConfig) => BuildMid
5152
endpoint.properties?.bucketType === S3_EXPRESS_BUCKET_TYPE;
5253

5354
if (isS3ExpressBucket) {
55+
setFeature(context, "S3_EXPRESS_BUCKET", "J");
5456
context.isS3ExpressBucket = true;
5557
}
5658

packages/middleware-sdk-s3/src/s3-express/middleware-s3-express.integ.spec.ts

+17
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,22 @@ describe("middleware-s3-express", () => {
8484

8585
expect.hasAssertions();
8686
});
87+
88+
it("should feature-detect S3 express bucket", async () => {
89+
const client = new S3({
90+
region: "us-west-2",
91+
s3ExpressIdentityProvider,
92+
});
93+
94+
requireRequestsFrom(client).toMatch({
95+
headers: {
96+
"user-agent": /(.*?) m\/J$/,
97+
},
98+
});
99+
100+
await client.headBucket({
101+
Bucket: "aws-sdk-js-v3-test--usw2-az1--x-s3",
102+
});
103+
});
87104
});
88105
});

packages/middleware-user-agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
},
2323
"license": "Apache-2.0",
2424
"dependencies": {
25+
"@aws-sdk/core": "*",
2526
"@aws-sdk/types": "*",
2627
"@aws-sdk/util-endpoints": "*",
2728
"@smithy/core": "^2.4.8",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { setFeature } from "@aws-sdk/core";
2+
import type { AccountIdEndpointMode } from "@aws-sdk/core/account-id-endpoint";
3+
import type { AwsHandlerExecutionContext } from "@aws-sdk/types";
4+
import type { IHttpRequest } from "@smithy/protocol-http";
5+
import type { BuildHandlerArguments, Provider } from "@smithy/types";
6+
7+
/**
8+
* @internal
9+
*/
10+
type PreviouslyResolved = Partial<{
11+
accountIdEndpointMode?: Provider<AccountIdEndpointMode>;
12+
}>;
13+
14+
/**
15+
* @internal
16+
* Check for features that don't have a middleware activation site but
17+
* may be detected on the context, client config, or request.
18+
*/
19+
export async function checkFeatures(
20+
context: AwsHandlerExecutionContext,
21+
config: PreviouslyResolved,
22+
args: BuildHandlerArguments<any>
23+
): Promise<void> {
24+
// eslint-disable-next-line
25+
const request = args.request as IHttpRequest;
26+
if (typeof config.accountIdEndpointMode === "function") {
27+
switch (await config.accountIdEndpointMode?.()) {
28+
case "disabled":
29+
setFeature(context, "ACCOUNT_ID_MODE_DISABLED", "Q");
30+
break;
31+
case "preferred":
32+
setFeature(context, "ACCOUNT_ID_MODE_PREFERRED", "P");
33+
break;
34+
case "required":
35+
setFeature(context, "ACCOUNT_ID_MODE_REQUIRED", "R");
36+
break;
37+
}
38+
}
39+
}

packages/middleware-user-agent/src/configurations.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Logger, Provider, UserAgent } from "@smithy/types";
21
import { normalizeProvider } from "@smithy/core";
2+
import { Logger, Provider, UserAgent } from "@smithy/types";
33

44
/**
55
* @internal

packages/middleware-user-agent/src/middleware-user-agent.integ.spec.ts

+31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { CodeCatalyst } from "@aws-sdk/client-codecatalyst";
2+
import { DynamoDB } from "@aws-sdk/client-dynamodb";
3+
import { S3 } from "@aws-sdk/client-s3";
4+
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
25

36
import { requireRequestsFrom } from "../../../private/aws-util-test/src";
47

@@ -23,4 +26,32 @@ describe("middleware-user-agent", () => {
2326
});
2427
});
2528
});
29+
30+
describe("features", () => {
31+
it("should detect DDB mapper, and account id mode", async () => {
32+
const client = new DynamoDB({
33+
credentials: {
34+
accessKeyId: "",
35+
secretAccessKey: "",
36+
accountId: "123",
37+
},
38+
accountIdEndpointMode: async () => "preferred" as const,
39+
});
40+
41+
const doc = DynamoDBDocument.from(client);
42+
43+
requireRequestsFrom(doc).toMatch({
44+
headers: {
45+
"user-agent": /(.*?) m\/d,P$/,
46+
},
47+
});
48+
49+
await doc.get({
50+
TableName: "table",
51+
Key: {
52+
id: "1",
53+
},
54+
});
55+
});
56+
});
2657
});

packages/middleware-user-agent/src/user-agent-middleware.ts

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
UserAgentPair,
1414
} from "@smithy/types";
1515

16+
import { checkFeatures } from "./check-features";
1617
import { UserAgentResolvedConfig } from "./configurations";
1718
import {
1819
SPACE,
@@ -51,12 +52,15 @@ export const userAgentMiddleware =
5152
const { headers } = request;
5253
const userAgent = context?.userAgent?.map(escapeUserAgent) || [];
5354
const defaultUserAgent = (await options.defaultUserAgentProvider()).map(escapeUserAgent);
55+
56+
await checkFeatures(context, options as any, args);
5457
const awsContext = context as AwsHandlerExecutionContext;
5558
defaultUserAgent.push(
5659
`m/${encodeFeatures(
5760
Object.assign({}, context.__smithy_context?.features, awsContext.__aws_sdk_context?.features)
5861
)}`
5962
);
63+
6064
const customUserAgent = options?.customUserAgent?.map(escapeUserAgent) || [];
6165
const appId = await options.userAgentAppId();
6266
if (appId) {

private/aws-util-test/src/requests/test-http-handler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class TestHttpHandler implements HttpHandler {
5656
*/
5757
public watch(client: Client<any, any, any>, matcher: HttpRequestMatcher = this.matcher) {
5858
this.client = client;
59-
this.originalRequestHandler = client.config.originalRequestHandler;
59+
this.originalRequestHandler = client.config.requestHandler;
6060
// mock credentials to avoid default chain lookup.
6161
client.config.credentials = async () => MOCK_CREDENTIALS;
6262
client.config.credentialDefaultProvider = () => {

0 commit comments

Comments
 (0)