diff --git a/packages/core/package.json b/packages/core/package.json index a53185d2adab1..b19600b67eb49 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -91,7 +91,6 @@ "@smithy/smithy-client": "^4.6.4", "@smithy/types": "^4.5.0", "@smithy/util-base64": "^4.1.0", - "@smithy/util-body-length-browser": "^4.1.0", "@smithy/util-middleware": "^4.1.1", "@smithy/util-utf8": "^4.1.0", "tslib": "^2.6.2" diff --git a/packages/core/src/submodules/protocols/ProtocolLib.ts b/packages/core/src/submodules/protocols/ProtocolLib.ts index f378606fc4f9a..01c688ee7d9a4 100644 --- a/packages/core/src/submodules/protocols/ProtocolLib.ts +++ b/packages/core/src/submodules/protocols/ProtocolLib.ts @@ -1,12 +1,5 @@ import { ErrorSchema, NormalizedSchema, TypeRegistry } from "@smithy/core/schema"; -import type { - BodyLengthCalculator, - HttpResponse as IHttpResponse, - MetadataBearer, - ResponseMetadata, - SerdeFunctions, -} from "@smithy/types"; -import { calculateBodyLength } from "@smithy/util-body-length-browser"; +import type { HttpResponse as IHttpResponse, MetadataBearer, ResponseMetadata } from "@smithy/types"; /** * @internal @@ -22,23 +15,6 @@ type ErrorMetadataBearer = MetadataBearer & { * @internal */ export class ProtocolLib { - /** - * @param body - to be inspected. - * @param serdeContext - this is a subset type but in practice is the client.config having a property called bodyLengthChecker. - * - * @returns content-length value for the body if possible. - * @throws Error and should be caught and handled if not possible to determine length. - */ - public calculateContentLength(body: any, serdeContext?: SerdeFunctions) { - const bodyLengthCalculator: BodyLengthCalculator = - ( - serdeContext as SerdeFunctions & { - bodyLengthChecker?: BodyLengthCalculator; - } - )?.bodyLengthChecker ?? calculateBodyLength; - return String(bodyLengthCalculator(body)); - } - /** * This is only for REST protocols. * @@ -108,9 +84,7 @@ export class ProtocolLib { const errorSchema = getErrorSchema?.(registry, errorName) ?? (registry.getSchema(errorIdentifier) as ErrorSchema); return { errorSchema, errorMetadata }; } catch (e) { - if (dataObject.Message) { - dataObject.message = dataObject.Message; - } + dataObject.message = dataObject.message ?? dataObject.Message ?? "UnknownError"; const baseExceptionSchema = TypeRegistry.for("smithy.ts.sdk.synthetic." + namespace).getBaseException(); if (baseExceptionSchema) { const ErrorCtor = baseExceptionSchema.ctor; diff --git a/packages/core/src/submodules/protocols/json/AwsJson1_0Protocol.spec.ts b/packages/core/src/submodules/protocols/json/AwsJson1_0Protocol.spec.ts index 2fbf124344889..16d7c227bba55 100644 --- a/packages/core/src/submodules/protocols/json/AwsJson1_0Protocol.spec.ts +++ b/packages/core/src/submodules/protocols/json/AwsJson1_0Protocol.spec.ts @@ -115,7 +115,6 @@ describe(AwsJson1_0Protocol.name, () => { ); expect(request.headers).toEqual({ - "content-length": "60", "content-type": "application/x-amz-json-1.0", "x-amz-target": "JsonRpc10.MyOperation", }); diff --git a/packages/core/src/submodules/protocols/json/AwsJsonRpcProtocol.ts b/packages/core/src/submodules/protocols/json/AwsJsonRpcProtocol.ts index 115796935327e..34eecbb6a9a9e 100644 --- a/packages/core/src/submodules/protocols/json/AwsJsonRpcProtocol.ts +++ b/packages/core/src/submodules/protocols/json/AwsJsonRpcProtocol.ts @@ -71,9 +71,9 @@ export abstract class AwsJsonRpcProtocol extends RpcProtocol { if (deref(operationSchema.input) === "unit" || !request.body) { request.body = "{}"; } - try { - request.headers["content-length"] = this.mixin.calculateContentLength(request.body, this.serdeContext); - } catch (e) {} + + // content-length header is set by the contentLengthMiddleware. + return request; } diff --git a/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.spec.ts b/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.spec.ts index 1f152e70e9a5a..ead21b9da5d79 100644 --- a/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.spec.ts +++ b/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.spec.ts @@ -161,7 +161,6 @@ describe(AwsRestJsonProtocol.name, () => { ); expect(request.headers).toEqual({ - "content-length": "25", "content-type": "application/json", header: "hello", a: "1", @@ -265,7 +264,6 @@ describe(AwsRestJsonProtocol.name, () => { expect(request.headers).toEqual({ "content-type": "application/json", - "content-length": "24", "header-default-date": "Thu, 01 Jan 1970 00:00:00 GMT", "header-member-trait-date": "1970-01-01T00:00:00Z", "header-epoch-seconds": "0", diff --git a/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.ts b/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.ts index 63fb7354a7cd3..695d9a50aac4f 100644 --- a/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.ts +++ b/packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.ts @@ -78,11 +78,7 @@ export class AwsRestJsonProtocol extends HttpBindingProtocol { request.body = "{}"; } - if (request.body) { - try { - request.headers["content-length"] = this.mixin.calculateContentLength(request.body, this.serdeContext); - } catch (e) {} - } + // content-length header is set by the contentLengthMiddleware. return request; } diff --git a/packages/core/src/submodules/protocols/json/JsonShapeSerializer.ts b/packages/core/src/submodules/protocols/json/JsonShapeSerializer.ts index 4ef83d947b276..38c4a210099d1 100644 --- a/packages/core/src/submodules/protocols/json/JsonShapeSerializer.ts +++ b/packages/core/src/submodules/protocols/json/JsonShapeSerializer.ts @@ -130,7 +130,7 @@ export class JsonShapeSerializer extends SerdeContextConfig implements ShapeSeri const mediaType = ns.getMergedTraits().mediaType; - if (typeof value === "string" && mediaType) { + if (value != null && mediaType) { const isJson = mediaType === "application/json" || mediaType.endsWith("+json"); if (isJson) { return LazyJsonString.from(value); diff --git a/packages/core/src/submodules/protocols/query/AwsQueryProtocol.ts b/packages/core/src/submodules/protocols/query/AwsQueryProtocol.ts index 30d1fe3d67ee0..31e088f73e4e0 100644 --- a/packages/core/src/submodules/protocols/query/AwsQueryProtocol.ts +++ b/packages/core/src/submodules/protocols/query/AwsQueryProtocol.ts @@ -82,9 +82,8 @@ export class AwsQueryProtocol extends RpcProtocol { request.body = request.body.slice(-1); } - try { - request.headers["content-length"] = this.mixin.calculateContentLength(request.body, this.serdeContext); - } catch (e) {} + // content-length header is set by the contentLengthMiddleware. + return request; } @@ -142,6 +141,13 @@ export class AwsQueryProtocol extends RpcProtocol { ): Promise { const errorIdentifier = this.loadQueryErrorCode(response, dataObject) ?? "Unknown"; const errorData = this.loadQueryError(dataObject); + const message = this.loadQueryErrorMessage(dataObject); + errorData.message = message; + errorData.Error = { + Type: errorData.Type, + Code: errorData.Code, + Message: message, + }; const { errorSchema, errorMetadata } = await this.mixin.getErrorSchemaOrThrowBaseException( errorIdentifier, @@ -156,10 +162,11 @@ export class AwsQueryProtocol extends RpcProtocol { ); const ns = NormalizedSchema.of(errorSchema); - const message = this.loadQueryErrorMessage(dataObject); const exception = new errorSchema.ctor(message); - const output = {} as any; + const output = { + Error: errorData.Error, + } as any; for (const [name, member] of ns.structIterator()) { const target = member.getMergedTraits().xmlName ?? name; diff --git a/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.spec.ts b/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.spec.ts index 5fdbd8863c381..ded37f44705a1 100644 --- a/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.spec.ts +++ b/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.spec.ts @@ -37,7 +37,6 @@ describe(AwsRestXmlProtocol.name, () => { method: "POST", headers: { "content-type": "application/xml", - "content-length": "167", }, query: { delete: "", diff --git a/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.ts b/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.ts index b915d2ba6700c..de759d5e685e6 100644 --- a/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.ts +++ b/packages/core/src/submodules/protocols/xml/AwsRestXmlProtocol.ts @@ -74,11 +74,7 @@ export class AwsRestXmlProtocol extends HttpBindingProtocol { } } - if (request.body) { - try { - request.headers["content-length"] = this.mixin.calculateContentLength(request.body, this.serdeContext); - } catch (e) {} - } + // content-length header is set by the contentLengthMiddleware. return request; } diff --git a/packages/core/src/submodules/protocols/xml/XmlShapeDeserializer.ts b/packages/core/src/submodules/protocols/xml/XmlShapeDeserializer.ts index 212ab2da183bc..992a408151cbd 100644 --- a/packages/core/src/submodules/protocols/xml/XmlShapeDeserializer.ts +++ b/packages/core/src/submodules/protocols/xml/XmlShapeDeserializer.ts @@ -58,6 +58,11 @@ export class XmlShapeDeserializer extends SerdeContextConfig implements ShapeDes public readSchema(_schema: Schema, value: any): any { const ns = NormalizedSchema.of(_schema); + + if (ns.isUnitSchema()) { + return; + } + const traits = ns.getMergedTraits(); if (ns.isListSchema() && !Array.isArray(value)) { diff --git a/packages/middleware-sdk-ec2/src/index.ts b/packages/middleware-sdk-ec2/src/index.ts index bbb861974daa5..a3063fa9c3971 100755 --- a/packages/middleware-sdk-ec2/src/index.ts +++ b/packages/middleware-sdk-ec2/src/index.ts @@ -3,7 +3,7 @@ import { getEndpointFromInstructions, toEndpointV1 } from "@smithy/middleware-en import { HttpRequest } from "@smithy/protocol-http"; import { SignatureV4 } from "@smithy/signature-v4"; import { extendedEncodeURIComponent } from "@smithy/smithy-client"; -import { +import type { AwsCredentialIdentity, ChecksumConstructor, Endpoint, @@ -113,8 +113,8 @@ export function copySnapshotPresignedUrlMiddleware(options: PreviouslyResolved): }, }; - // we also double-check the work of the serialzier here - // because this middleware may be placed after the regular serialzier. + // we also double-check the work of the serializer here + // because this middleware may be placed after the regular serializer. if (HttpRequest.isInstance(args.request)) { const { request } = args; if (!(request.body ?? "").includes("DestinationRegion=")) { diff --git a/packages/middleware-sdk-ec2/src/middleware-sdk-ec2.e2e.spec.ts b/packages/middleware-sdk-ec2/src/middleware-sdk-ec2.e2e.spec.ts index 8e919b573469e..df46e022c8b81 100644 --- a/packages/middleware-sdk-ec2/src/middleware-sdk-ec2.e2e.spec.ts +++ b/packages/middleware-sdk-ec2/src/middleware-sdk-ec2.e2e.spec.ts @@ -1,5 +1,6 @@ import { EC2, EC2ServiceException, waitUntilSnapshotCompleted, waitUntilVolumeAvailable } from "@aws-sdk/client-ec2"; import { KMS } from "@aws-sdk/client-kms"; +import { getHttpDebugLogPlugin } from "@aws-sdk/middleware-http-debug-log"; import { afterAll, beforeAll, describe, expect, onTestFailed, test as it } from "vitest"; const errors = [] as any[]; @@ -108,6 +109,14 @@ describe("EC2 feature test", () => { const sourceKms = new KMS({ region: sourceRegion, logger }); const destinationKms = new KMS({ region: destRegion, logger }); + for (const client of [sourceEc2, destinationEc2, sourceKms, destinationKms]) { + // I'm leaving this debug call in the test because it's so slow that + // you will want to see active request progress. + void getHttpDebugLogPlugin; + void client; + // client.middlewareStack.use(getHttpDebugLogPlugin("line")); + } + async function teardown() { if (volumeId) { await sourceEc2.deleteVolume({ VolumeId: volumeId }); diff --git a/private/aws-client-retry-test/src/ClientRetryTest.spec.ts b/private/aws-client-retry-test/src/ClientRetryTest.spec.ts index c9c38a8726064..e218b5fc8328e 100644 --- a/private/aws-client-retry-test/src/ClientRetryTest.spec.ts +++ b/private/aws-client-retry-test/src/ClientRetryTest.spec.ts @@ -1,4 +1,4 @@ -import { ListFunctionsCommand, Lambda, LambdaClient, LambdaServiceException } from "@aws-sdk/client-lambda"; +import { Lambda, LambdaClient, LambdaServiceException, ListFunctionsCommand } from "@aws-sdk/client-lambda"; import { HttpHandler, HttpResponse } from "@smithy/protocol-http"; import { AwsCredentialIdentity, RequestHandlerOutput } from "@smithy/types"; import { ConfiguredRetryStrategy, StandardRetryStrategy } from "@smithy/util-retry"; diff --git a/private/aws-middleware-test/src/middleware-content-length.spec.ts b/private/aws-middleware-test/src/middleware-content-length.spec.ts index 34aaeed347779..84fb882847a34 100644 --- a/private/aws-middleware-test/src/middleware-content-length.spec.ts +++ b/private/aws-middleware-test/src/middleware-content-length.spec.ts @@ -1,10 +1,9 @@ +import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src"; import { AccessAnalyzer } from "@aws-sdk/client-accessanalyzer"; import { S3 } from "@aws-sdk/client-s3"; import { XRay } from "@aws-sdk/client-xray"; import { describe, expect, test as it } from "vitest"; -import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src"; - describe("middleware-content-length", () => { describe(AccessAnalyzer.name, () => { it("should not add content-length if no body", async () => { @@ -40,6 +39,7 @@ describe("middleware-content-length", () => { headers: { "content-length": /106/, }, + body: /clientToken/, // must include idempotencyToken. }); await client.createAccessPreview({ @@ -47,7 +47,7 @@ describe("middleware-content-length", () => { analyzerArn: "my-analyzer-arn", }); - expect.assertions(1); + expect.assertions(2); }); }); diff --git a/private/aws-middleware-test/src/middleware-serde.spec.ts b/private/aws-middleware-test/src/middleware-serde.spec.ts index ebe2cc3fe8511..58ec7b3777abd 100644 --- a/private/aws-middleware-test/src/middleware-serde.spec.ts +++ b/private/aws-middleware-test/src/middleware-serde.spec.ts @@ -1,11 +1,10 @@ +import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src"; import { EC2 } from "@aws-sdk/client-ec2"; import { S3 } from "@aws-sdk/client-s3"; import { SageMaker } from "@aws-sdk/client-sagemaker"; import { SageMakerRuntime } from "@aws-sdk/client-sagemaker-runtime"; import { describe, test as it } from "vitest"; -import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src"; - describe("middleware-serde", () => { describe(S3.name, () => { it("should serialize xml", async () => { @@ -75,7 +74,15 @@ describe("middleware-serde", () => { "content-type": "application/x-www-form-urlencoded", host: "ec2.us-west-2.amazonaws.com", }, - body: /ClientCidrBlock=ClientCidrBlock&ServerCertificateArn=ServerCertificateArn(.*?)&Action=CreateClientVpnEndpoint&Version=2016-11-15/, + body(body: any) { + const params = Object.fromEntries(new URLSearchParams(body).entries()); + expect(params).toMatchObject({ + Action: "CreateClientVpnEndpoint", + Version: "2016-11-15", + ClientCidrBlock: "ClientCidrBlock", + ServerCertificateArn: "ServerCertificateArn", + }); + }, protocol: "https:", path: "/", }); diff --git a/yarn.lock b/yarn.lock index 81aeafa89902a..62242bd39107a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23355,7 +23355,6 @@ __metadata: "@smithy/smithy-client": "npm:^4.6.4" "@smithy/types": "npm:^4.5.0" "@smithy/util-base64": "npm:^4.1.0" - "@smithy/util-body-length-browser": "npm:^4.1.0" "@smithy/util-middleware": "npm:^4.1.1" "@smithy/util-utf8": "npm:^4.1.0" "@tsconfig/recommended": "npm:1.0.1"