Skip to content

Commit 923cb7b

Browse files
committed
chore(middleware-user-agent): add feature detection for account-id, s3-express, lib-dynamodb
1 parent de4dc49 commit 923cb7b

File tree

9 files changed

+99
-2
lines changed

9 files changed

+99
-2
lines changed

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

Lines changed: 2 additions & 0 deletions
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-sdk-s3/src/s3-express/functions/s3ExpressMiddleware.ts

Lines changed: 2 additions & 0 deletions
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

Lines changed: 17 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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.7",
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 { AwsCredentialIdentityProvider, BuildHandlerArguments, Provider } from "@smithy/types";
6+
7+
/**
8+
* @internal
9+
*/
10+
type PreviouslyResolved = Partial<{
11+
credentials?: AwsCredentialIdentityProvider;
12+
accountIdEndpointMode?: Provider<AccountIdEndpointMode>;
13+
}>;
14+
15+
/**
16+
* @internal
17+
* Check for features that don't have a middleware activation site but
18+
* may be detected on the client config.
19+
*/
20+
export async function checkFeatures<C extends {} | PreviouslyResolved>(
21+
context: AwsHandlerExecutionContext,
22+
config: C,
23+
args: BuildHandlerArguments<any>
24+
): Promise<void> {
25+
// eslint-disable-next-line
26+
const request = args.request as IHttpRequest;
27+
if ("accountIdEndpointMode" in config) {
28+
switch (await config.accountIdEndpointMode?.()) {
29+
case "disabled":
30+
setFeature(context, "ACCOUNT_ID_MODE_DISABLED", "Q");
31+
break;
32+
case "preferred":
33+
setFeature(context, "ACCOUNT_ID_MODE_PREFERRED", "P");
34+
break;
35+
case "required":
36+
setFeature(context, "ACCOUNT_ID_MODE_REQUIRED", "R");
37+
break;
38+
}
39+
}
40+
}

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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 31 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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, 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

Lines changed: 1 addition & 1 deletion
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)