diff --git a/packages/middleware-user-agent/src/encode-metrics.spec.ts b/packages/middleware-user-agent/src/encode-metrics.spec.ts new file mode 100644 index 0000000000000..0b1ceb7e9de2f --- /dev/null +++ b/packages/middleware-user-agent/src/encode-metrics.spec.ts @@ -0,0 +1,26 @@ +import { encodeMetrics } from "./encode-metrics"; + +describe(encodeMetrics.name, () => { + it("encodes empty metrics", () => { + expect(encodeMetrics({})).toEqual(""); + }); + + it("encodes metrics", () => { + expect( + encodeMetrics({ + A: "A", + z: "z", + } as any) + ).toEqual("A,z"); + }); + + it("drops values that would exceed 1024 bytes", () => { + expect( + encodeMetrics({ + A: "A".repeat(512), + B: "B".repeat(511), + z: "z", + } as any) + ).toEqual("A".repeat(512) + "," + "B".repeat(511)); + }); +}); diff --git a/packages/middleware-user-agent/src/encode-metrics.ts b/packages/middleware-user-agent/src/encode-metrics.ts new file mode 100644 index 0000000000000..13c2e3973c4ab --- /dev/null +++ b/packages/middleware-user-agent/src/encode-metrics.ts @@ -0,0 +1,25 @@ +import type { AwsSdkFeatures } from "@aws-sdk/types"; + +const BYTE_LIMIT = 1024; + +export function encodeMetrics(metrics: AwsSdkFeatures): string { + let buffer = ""; + + // currently all possible values are 1 byte, + // so string length is used. + + for (const key in metrics) { + const val = metrics[key as keyof typeof metrics]!; + if (buffer.length + val!.length + 1 <= BYTE_LIMIT) { + if (buffer.length) { + buffer += "," + val; + } else { + buffer += val; + } + continue; + } + break; + } + + return buffer; +} diff --git a/packages/types/src/middleware.ts b/packages/types/src/middleware.ts index 3ae51bd9a83d0..f8134a5ddd7d4 100644 --- a/packages/types/src/middleware.ts +++ b/packages/types/src/middleware.ts @@ -1,3 +1,5 @@ +import { HandlerExecutionContext } from "@smithy/types"; + export { AbsoluteLocation, BuildHandler, @@ -38,3 +40,68 @@ export { Step, Terminalware, } from "@smithy/types"; + +/** + * @internal + * Contains reserved keys for AWS SDK internal usage of the + * handler execution context object. + */ +export interface AwsHandlerExecutionContext extends HandlerExecutionContext { + __aws_sdk_context?: { + features?: Partial<{ + RESOURCE_MODEL: "A"; + WAITER: "B"; + PAGINATOR: "C"; + RETRY_MODE_LEGACY: "D"; + RETRY_MODE_STANDARD: "E"; + RETRY_MODE_ADAPTIVE: "F"; + // S3_TRANSFER: "G"; // not applicable. + // S3_CRYPTO_V1N: "H"; // not applicable. + // S3_CRYPTO_V2: "I"; // not applicable. + S3_EXPRESS_BUCKET: "J"; + S3_ACCESS_GRANTS: "K"; + GZIP_REQUEST_COMPRESSION: "L"; + PROTOCOL_RPC_V2_CBOR: "M"; + ENDPOINT_OVERRIDE: "N"; + ACCOUNT_ID_ENDPOINT: "O"; + ACCOUNT_ID_MODE_PREFERRED: "P"; + ACCOUNT_ID_MODE_DISABLED: "Q"; + ACCOUNT_ID_MODE_REQUIRED: "R"; + SIGV4A_SIGNING: "S"; + RESOLVED_ACCOUNT_ID: "T"; + FLEXIBLE_CHECKSUMS_REQ_CRC32: "U"; + FLEXIBLE_CHECKSUMS_REQ_CRC32C: "V"; + FLEXIBLE_CHECKSUMS_REQ_CRC64: "W"; + FLEXIBLE_CHECKSUMS_REQ_SHA1: "X"; + FLEXIBLE_CHECKSUMS_REQ_SHA256: "Y"; + FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED: "Z"; + FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED: "a"; + FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED: "b"; + FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED: "c"; + DDB_MAPPER: "d"; + CREDENTIALS_CODE: "e"; + // CREDENTIALS_JVM_SYSTEM_PROPERTIES: "f"; // not applicable. + CREDENTIALS_ENV_VARS: "g"; + CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN: "h"; + CREDENTIALS_STS_ASSUME_ROLE: "i"; + CREDENTIALS_STS_ASSUME_ROLE_SAML: "j"; + CREDENTIALS_STS_ASSUME_ROLE_WEB_ID: "k"; + CREDENTIALS_STS_FEDERATION_TOKEN: "l"; + CREDENTIALS_STS_SESSION_TOKEN: "m"; + CREDENTIALS_PROFILE: "n"; + CREDENTIALS_PROFILE_SOURCE_PROFILE: "o"; + CREDENTIALS_PROFILE_NAMED_PROVIDER: "p"; + CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN: "q"; + CREDENTIALS_PROFILE_SSO: "r"; + CREDENTIALS_SSO: "s"; + CREDENTIALS_PROFILE_SSO_LEGACY: "t"; + CREDENTIALS_SSO_LEGACY: "u"; + CREDENTIALS_PROFILE_PROCESS: "v"; + CREDENTIALS_PROCESS: "w"; + CREDENTIALS_BOTO2_CONFIG_FILE: "x"; + CREDENTIALS_AWS_SDK_STORE: "y"; + CREDENTIALS_HTTP: "z"; + CREDENTIALS_IMDS: "0"; + }>; + }; +}