aws / aws-sdk-js-v3

Modularized AWS SDK for JavaScript.
Apache License 2.0
3.08k stars 575 forks source link

When adding a middleware to a S3Client instance, commands intercepted by the middleware are instances of object, instead of being instances of the original command #5593

Closed PChol22 closed 9 months ago

PChol22 commented 10 months ago

Checkboxes for prior research

Describe the bug

When adding a "initialize" middleware to a S3Client instance, commands intercepted by the middleware are instances of object, instead of being instances of the original command.

This is problematic when implementing a cache middleware: 2 different commands (ex: GetPublicAccessBlockCommand and GetBucketLifecycleConfigurationCommand) with the same input (ex: { BucketName: 'abc' }) will be interpreted as the same command when hashed, and one of them will return incoherent data.

This problem doesn't happen in other clients like LambdaClient for example.

SDK version number

@aws-sdk/client-s3@3.474.0

Which JavaScript Runtime is this issue in?

Node.js

Details of the browser/Node.js/ReactNative version

v18.16.1

Reproduction Steps

import {
  GetBucketLifecycleConfigurationCommand,
  S3Client,
} from '@aws-sdk/client-s3';

const s3Client = new S3Client({});
s3Client.middlewareStack.use({
  applyToStack: stack => {
    stack.add(
      next => async args => {
        console.log(args instanceof GetBucketLifecycleConfigurationCommand);

        return next(args);
      },
      { step: 'initialize' },
    );
  },
});

await s3Client.send(
  new GetBucketLifecycleConfigurationCommand({
    Bucket: 'test',
  }),
);
// Will log false <-- This is the problem

Observed Behavior

In the middleware, args is an instance of object, instead of being an instance of GetBucketLifecycleConfigurationCommand.

This broken behaviour happens with every S3Client command I tried, but doesn't happen for any other client (Lambda, EventBridge...)

Expected Behavior

Existing behaviour with clients like LambdaClient:

import {
  GetFunctionConfigurationCommand,
  LambdaClient,
} from '@aws-sdk/client-lambda';

const lambdaClient = new LambdaClient({});
lambdaClient.middlewareStack.use({
  applyToStack: stack => {
    stack.add(
      next => async args => {
        console.log(args instanceof GetFunctionConfigurationCommand);

        return next(args);
      },
      { step: 'initialize' },
    );
  },
});

await lambdaClient.send(
  new GetFunctionConfigurationCommand({
    FunctionName: 'test',
  }),
);
// Will log true

Args of the middleware are an instance of the command that was intercepted

Possible Solution

Dirty temporary workaround for those who are stuck:

Add an extra commandName parameter to the input of commands sent to the S3Client, that helps the middleware know what command it is intercepting

Additional Information/Context

No response

PChol22 commented 10 months ago

After some investigation, seems like the usage of next({ ...args }) might be the reason of the issue in files packages/middleware-sdk-s3/src/check-content-length-header.ts and packages/middleware-sdk-s3/src/validate-bucket-name.ts

kuhe commented 10 months ago

The async args => {} part of the middleware has type HandlerArguments e.g. https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-smithy-types/Interface/InitializeHandlerArguments/.

It does not say args is the type of the input command, only that args.input is the type of the Command's input.

github-actions[bot] commented 9 months ago

This issue has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing.

github-actions[bot] commented 9 months ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.