vendor/aws/aws-sdk-php/src/S3/S3Client.php line 383

Open in your IDE?
  1. <?php
  2. namespace Aws\S3;
  3. use Aws\Api\ApiProvider;
  4. use Aws\Api\DocModel;
  5. use Aws\Api\Service;
  6. use Aws\AwsClient;
  7. use Aws\CacheInterface;
  8. use Aws\ClientResolver;
  9. use Aws\Command;
  10. use Aws\CommandInterface;
  11. use Aws\Configuration\ConfigurationResolver;
  12. use Aws\Exception\AwsException;
  13. use Aws\HandlerList;
  14. use Aws\Identity\S3\S3ExpressIdentityProvider;
  15. use Aws\InputValidationMiddleware;
  16. use Aws\Middleware;
  17. use Aws\ResultInterface;
  18. use Aws\Retry\QuotaManager;
  19. use Aws\RetryMiddleware;
  20. use Aws\RetryMiddlewareV2;
  21. use Aws\S3\Parser\GetBucketLocationResultMutator;
  22. use Aws\S3\Parser\S3Parser;
  23. use Aws\S3\Parser\ValidateResponseChecksumResultMutator;
  24. use Aws\S3\RegionalEndpoint\ConfigurationProvider;
  25. use Aws\S3\UseArnRegion\Configuration;
  26. use Aws\S3\UseArnRegion\ConfigurationInterface;
  27. use Aws\S3\UseArnRegion\ConfigurationProvider as UseArnRegionConfigurationProvider;
  28. use GuzzleHttp\Exception\RequestException;
  29. use GuzzleHttp\Promise\PromiseInterface;
  30. use Psr\Http\Message\RequestInterface;
  31. /**
  32.  * Client used to interact with **Amazon Simple Storage Service (Amazon S3)**.
  33.  *
  34.  * @method \Aws\Result abortMultipartUpload(array $args = [])
  35.  * @method \GuzzleHttp\Promise\Promise abortMultipartUploadAsync(array $args = [])
  36.  * @method \Aws\Result completeMultipartUpload(array $args = [])
  37.  * @method \GuzzleHttp\Promise\Promise completeMultipartUploadAsync(array $args = [])
  38.  * @method \Aws\Result copyObject(array $args = [])
  39.  * @method \GuzzleHttp\Promise\Promise copyObjectAsync(array $args = [])
  40.  * @method \Aws\Result createBucket(array $args = [])
  41.  * @method \GuzzleHttp\Promise\Promise createBucketAsync(array $args = [])
  42.  * @method \Aws\Result createBucketMetadataTableConfiguration(array $args = [])
  43.  * @method \GuzzleHttp\Promise\Promise createBucketMetadataTableConfigurationAsync(array $args = [])
  44.  * @method \Aws\Result createMultipartUpload(array $args = [])
  45.  * @method \GuzzleHttp\Promise\Promise createMultipartUploadAsync(array $args = [])
  46.  * @method \Aws\Result createSession(array $args = [])
  47.  * @method \GuzzleHttp\Promise\Promise createSessionAsync(array $args = [])
  48.  * @method \Aws\Result deleteBucket(array $args = [])
  49.  * @method \GuzzleHttp\Promise\Promise deleteBucketAsync(array $args = [])
  50.  * @method \Aws\Result deleteBucketAnalyticsConfiguration(array $args = [])
  51.  * @method \GuzzleHttp\Promise\Promise deleteBucketAnalyticsConfigurationAsync(array $args = [])
  52.  * @method \Aws\Result deleteBucketCors(array $args = [])
  53.  * @method \GuzzleHttp\Promise\Promise deleteBucketCorsAsync(array $args = [])
  54.  * @method \Aws\Result deleteBucketEncryption(array $args = [])
  55.  * @method \GuzzleHttp\Promise\Promise deleteBucketEncryptionAsync(array $args = [])
  56.  * @method \Aws\Result deleteBucketIntelligentTieringConfiguration(array $args = [])
  57.  * @method \GuzzleHttp\Promise\Promise deleteBucketIntelligentTieringConfigurationAsync(array $args = [])
  58.  * @method \Aws\Result deleteBucketInventoryConfiguration(array $args = [])
  59.  * @method \GuzzleHttp\Promise\Promise deleteBucketInventoryConfigurationAsync(array $args = [])
  60.  * @method \Aws\Result deleteBucketLifecycle(array $args = [])
  61.  * @method \GuzzleHttp\Promise\Promise deleteBucketLifecycleAsync(array $args = [])
  62.  * @method \Aws\Result deleteBucketMetadataTableConfiguration(array $args = [])
  63.  * @method \GuzzleHttp\Promise\Promise deleteBucketMetadataTableConfigurationAsync(array $args = [])
  64.  * @method \Aws\Result deleteBucketMetricsConfiguration(array $args = [])
  65.  * @method \GuzzleHttp\Promise\Promise deleteBucketMetricsConfigurationAsync(array $args = [])
  66.  * @method \Aws\Result deleteBucketOwnershipControls(array $args = [])
  67.  * @method \GuzzleHttp\Promise\Promise deleteBucketOwnershipControlsAsync(array $args = [])
  68.  * @method \Aws\Result deleteBucketPolicy(array $args = [])
  69.  * @method \GuzzleHttp\Promise\Promise deleteBucketPolicyAsync(array $args = [])
  70.  * @method \Aws\Result deleteBucketReplication(array $args = [])
  71.  * @method \GuzzleHttp\Promise\Promise deleteBucketReplicationAsync(array $args = [])
  72.  * @method \Aws\Result deleteBucketTagging(array $args = [])
  73.  * @method \GuzzleHttp\Promise\Promise deleteBucketTaggingAsync(array $args = [])
  74.  * @method \Aws\Result deleteBucketWebsite(array $args = [])
  75.  * @method \GuzzleHttp\Promise\Promise deleteBucketWebsiteAsync(array $args = [])
  76.  * @method \Aws\Result deleteObject(array $args = [])
  77.  * @method \GuzzleHttp\Promise\Promise deleteObjectAsync(array $args = [])
  78.  * @method \Aws\Result deleteObjectTagging(array $args = [])
  79.  * @method \GuzzleHttp\Promise\Promise deleteObjectTaggingAsync(array $args = [])
  80.  * @method \Aws\Result deleteObjects(array $args = [])
  81.  * @method \GuzzleHttp\Promise\Promise deleteObjectsAsync(array $args = [])
  82.  * @method \Aws\Result deletePublicAccessBlock(array $args = [])
  83.  * @method \GuzzleHttp\Promise\Promise deletePublicAccessBlockAsync(array $args = [])
  84.  * @method \Aws\Result getBucketAccelerateConfiguration(array $args = [])
  85.  * @method \GuzzleHttp\Promise\Promise getBucketAccelerateConfigurationAsync(array $args = [])
  86.  * @method \Aws\Result getBucketAcl(array $args = [])
  87.  * @method \GuzzleHttp\Promise\Promise getBucketAclAsync(array $args = [])
  88.  * @method \Aws\Result getBucketAnalyticsConfiguration(array $args = [])
  89.  * @method \GuzzleHttp\Promise\Promise getBucketAnalyticsConfigurationAsync(array $args = [])
  90.  * @method \Aws\Result getBucketCors(array $args = [])
  91.  * @method \GuzzleHttp\Promise\Promise getBucketCorsAsync(array $args = [])
  92.  * @method \Aws\Result getBucketEncryption(array $args = [])
  93.  * @method \GuzzleHttp\Promise\Promise getBucketEncryptionAsync(array $args = [])
  94.  * @method \Aws\Result getBucketIntelligentTieringConfiguration(array $args = [])
  95.  * @method \GuzzleHttp\Promise\Promise getBucketIntelligentTieringConfigurationAsync(array $args = [])
  96.  * @method \Aws\Result getBucketInventoryConfiguration(array $args = [])
  97.  * @method \GuzzleHttp\Promise\Promise getBucketInventoryConfigurationAsync(array $args = [])
  98.  * @method \Aws\Result getBucketLifecycle(array $args = [])
  99.  * @method \GuzzleHttp\Promise\Promise getBucketLifecycleAsync(array $args = [])
  100.  * @method \Aws\Result getBucketLifecycleConfiguration(array $args = [])
  101.  * @method \GuzzleHttp\Promise\Promise getBucketLifecycleConfigurationAsync(array $args = [])
  102.  * @method \Aws\Result getBucketLocation(array $args = [])
  103.  * @method \GuzzleHttp\Promise\Promise getBucketLocationAsync(array $args = [])
  104.  * @method \Aws\Result getBucketLogging(array $args = [])
  105.  * @method \GuzzleHttp\Promise\Promise getBucketLoggingAsync(array $args = [])
  106.  * @method \Aws\Result getBucketMetadataTableConfiguration(array $args = [])
  107.  * @method \GuzzleHttp\Promise\Promise getBucketMetadataTableConfigurationAsync(array $args = [])
  108.  * @method \Aws\Result getBucketMetricsConfiguration(array $args = [])
  109.  * @method \GuzzleHttp\Promise\Promise getBucketMetricsConfigurationAsync(array $args = [])
  110.  * @method \Aws\Result getBucketNotification(array $args = [])
  111.  * @method \GuzzleHttp\Promise\Promise getBucketNotificationAsync(array $args = [])
  112.  * @method \Aws\Result getBucketNotificationConfiguration(array $args = [])
  113.  * @method \GuzzleHttp\Promise\Promise getBucketNotificationConfigurationAsync(array $args = [])
  114.  * @method \Aws\Result getBucketOwnershipControls(array $args = [])
  115.  * @method \GuzzleHttp\Promise\Promise getBucketOwnershipControlsAsync(array $args = [])
  116.  * @method \Aws\Result getBucketPolicy(array $args = [])
  117.  * @method \GuzzleHttp\Promise\Promise getBucketPolicyAsync(array $args = [])
  118.  * @method \Aws\Result getBucketPolicyStatus(array $args = [])
  119.  * @method \GuzzleHttp\Promise\Promise getBucketPolicyStatusAsync(array $args = [])
  120.  * @method \Aws\Result getBucketReplication(array $args = [])
  121.  * @method \GuzzleHttp\Promise\Promise getBucketReplicationAsync(array $args = [])
  122.  * @method \Aws\Result getBucketRequestPayment(array $args = [])
  123.  * @method \GuzzleHttp\Promise\Promise getBucketRequestPaymentAsync(array $args = [])
  124.  * @method \Aws\Result getBucketTagging(array $args = [])
  125.  * @method \GuzzleHttp\Promise\Promise getBucketTaggingAsync(array $args = [])
  126.  * @method \Aws\Result getBucketVersioning(array $args = [])
  127.  * @method \GuzzleHttp\Promise\Promise getBucketVersioningAsync(array $args = [])
  128.  * @method \Aws\Result getBucketWebsite(array $args = [])
  129.  * @method \GuzzleHttp\Promise\Promise getBucketWebsiteAsync(array $args = [])
  130.  * @method \Aws\Result getObject(array $args = [])
  131.  * @method \GuzzleHttp\Promise\Promise getObjectAsync(array $args = [])
  132.  * @method \Aws\Result getObjectAcl(array $args = [])
  133.  * @method \GuzzleHttp\Promise\Promise getObjectAclAsync(array $args = [])
  134.  * @method \Aws\Result getObjectAttributes(array $args = [])
  135.  * @method \GuzzleHttp\Promise\Promise getObjectAttributesAsync(array $args = [])
  136.  * @method \Aws\Result getObjectLegalHold(array $args = [])
  137.  * @method \GuzzleHttp\Promise\Promise getObjectLegalHoldAsync(array $args = [])
  138.  * @method \Aws\Result getObjectLockConfiguration(array $args = [])
  139.  * @method \GuzzleHttp\Promise\Promise getObjectLockConfigurationAsync(array $args = [])
  140.  * @method \Aws\Result getObjectRetention(array $args = [])
  141.  * @method \GuzzleHttp\Promise\Promise getObjectRetentionAsync(array $args = [])
  142.  * @method \Aws\Result getObjectTagging(array $args = [])
  143.  * @method \GuzzleHttp\Promise\Promise getObjectTaggingAsync(array $args = [])
  144.  * @method \Aws\Result getObjectTorrent(array $args = [])
  145.  * @method \GuzzleHttp\Promise\Promise getObjectTorrentAsync(array $args = [])
  146.  * @method \Aws\Result getPublicAccessBlock(array $args = [])
  147.  * @method \GuzzleHttp\Promise\Promise getPublicAccessBlockAsync(array $args = [])
  148.  * @method \Aws\Result headBucket(array $args = [])
  149.  * @method \GuzzleHttp\Promise\Promise headBucketAsync(array $args = [])
  150.  * @method \Aws\Result headObject(array $args = [])
  151.  * @method \GuzzleHttp\Promise\Promise headObjectAsync(array $args = [])
  152.  * @method \Aws\Result listBucketAnalyticsConfigurations(array $args = [])
  153.  * @method \GuzzleHttp\Promise\Promise listBucketAnalyticsConfigurationsAsync(array $args = [])
  154.  * @method \Aws\Result listBucketIntelligentTieringConfigurations(array $args = [])
  155.  * @method \GuzzleHttp\Promise\Promise listBucketIntelligentTieringConfigurationsAsync(array $args = [])
  156.  * @method \Aws\Result listBucketInventoryConfigurations(array $args = [])
  157.  * @method \GuzzleHttp\Promise\Promise listBucketInventoryConfigurationsAsync(array $args = [])
  158.  * @method \Aws\Result listBucketMetricsConfigurations(array $args = [])
  159.  * @method \GuzzleHttp\Promise\Promise listBucketMetricsConfigurationsAsync(array $args = [])
  160.  * @method \Aws\Result listBuckets(array $args = [])
  161.  * @method \GuzzleHttp\Promise\Promise listBucketsAsync(array $args = [])
  162.  * @method \Aws\Result listDirectoryBuckets(array $args = [])
  163.  * @method \GuzzleHttp\Promise\Promise listDirectoryBucketsAsync(array $args = [])
  164.  * @method \Aws\Result listMultipartUploads(array $args = [])
  165.  * @method \GuzzleHttp\Promise\Promise listMultipartUploadsAsync(array $args = [])
  166.  * @method \Aws\Result listObjectVersions(array $args = [])
  167.  * @method \GuzzleHttp\Promise\Promise listObjectVersionsAsync(array $args = [])
  168.  * @method \Aws\Result listObjects(array $args = [])
  169.  * @method \GuzzleHttp\Promise\Promise listObjectsAsync(array $args = [])
  170.  * @method \Aws\Result listObjectsV2(array $args = [])
  171.  * @method \GuzzleHttp\Promise\Promise listObjectsV2Async(array $args = [])
  172.  * @method \Aws\Result listParts(array $args = [])
  173.  * @method \GuzzleHttp\Promise\Promise listPartsAsync(array $args = [])
  174.  * @method \Aws\Result putBucketAccelerateConfiguration(array $args = [])
  175.  * @method \GuzzleHttp\Promise\Promise putBucketAccelerateConfigurationAsync(array $args = [])
  176.  * @method \Aws\Result putBucketAcl(array $args = [])
  177.  * @method \GuzzleHttp\Promise\Promise putBucketAclAsync(array $args = [])
  178.  * @method \Aws\Result putBucketAnalyticsConfiguration(array $args = [])
  179.  * @method \GuzzleHttp\Promise\Promise putBucketAnalyticsConfigurationAsync(array $args = [])
  180.  * @method \Aws\Result putBucketCors(array $args = [])
  181.  * @method \GuzzleHttp\Promise\Promise putBucketCorsAsync(array $args = [])
  182.  * @method \Aws\Result putBucketEncryption(array $args = [])
  183.  * @method \GuzzleHttp\Promise\Promise putBucketEncryptionAsync(array $args = [])
  184.  * @method \Aws\Result putBucketIntelligentTieringConfiguration(array $args = [])
  185.  * @method \GuzzleHttp\Promise\Promise putBucketIntelligentTieringConfigurationAsync(array $args = [])
  186.  * @method \Aws\Result putBucketInventoryConfiguration(array $args = [])
  187.  * @method \GuzzleHttp\Promise\Promise putBucketInventoryConfigurationAsync(array $args = [])
  188.  * @method \Aws\Result putBucketLifecycle(array $args = [])
  189.  * @method \GuzzleHttp\Promise\Promise putBucketLifecycleAsync(array $args = [])
  190.  * @method \Aws\Result putBucketLifecycleConfiguration(array $args = [])
  191.  * @method \GuzzleHttp\Promise\Promise putBucketLifecycleConfigurationAsync(array $args = [])
  192.  * @method \Aws\Result putBucketLogging(array $args = [])
  193.  * @method \GuzzleHttp\Promise\Promise putBucketLoggingAsync(array $args = [])
  194.  * @method \Aws\Result putBucketMetricsConfiguration(array $args = [])
  195.  * @method \GuzzleHttp\Promise\Promise putBucketMetricsConfigurationAsync(array $args = [])
  196.  * @method \Aws\Result putBucketNotification(array $args = [])
  197.  * @method \GuzzleHttp\Promise\Promise putBucketNotificationAsync(array $args = [])
  198.  * @method \Aws\Result putBucketNotificationConfiguration(array $args = [])
  199.  * @method \GuzzleHttp\Promise\Promise putBucketNotificationConfigurationAsync(array $args = [])
  200.  * @method \Aws\Result putBucketOwnershipControls(array $args = [])
  201.  * @method \GuzzleHttp\Promise\Promise putBucketOwnershipControlsAsync(array $args = [])
  202.  * @method \Aws\Result putBucketPolicy(array $args = [])
  203.  * @method \GuzzleHttp\Promise\Promise putBucketPolicyAsync(array $args = [])
  204.  * @method \Aws\Result putBucketReplication(array $args = [])
  205.  * @method \GuzzleHttp\Promise\Promise putBucketReplicationAsync(array $args = [])
  206.  * @method \Aws\Result putBucketRequestPayment(array $args = [])
  207.  * @method \GuzzleHttp\Promise\Promise putBucketRequestPaymentAsync(array $args = [])
  208.  * @method \Aws\Result putBucketTagging(array $args = [])
  209.  * @method \GuzzleHttp\Promise\Promise putBucketTaggingAsync(array $args = [])
  210.  * @method \Aws\Result putBucketVersioning(array $args = [])
  211.  * @method \GuzzleHttp\Promise\Promise putBucketVersioningAsync(array $args = [])
  212.  * @method \Aws\Result putBucketWebsite(array $args = [])
  213.  * @method \GuzzleHttp\Promise\Promise putBucketWebsiteAsync(array $args = [])
  214.  * @method \Aws\Result putObject(array $args = [])
  215.  * @method \GuzzleHttp\Promise\Promise putObjectAsync(array $args = [])
  216.  * @method \Aws\Result putObjectAcl(array $args = [])
  217.  * @method \GuzzleHttp\Promise\Promise putObjectAclAsync(array $args = [])
  218.  * @method \Aws\Result putObjectLegalHold(array $args = [])
  219.  * @method \GuzzleHttp\Promise\Promise putObjectLegalHoldAsync(array $args = [])
  220.  * @method \Aws\Result putObjectLockConfiguration(array $args = [])
  221.  * @method \GuzzleHttp\Promise\Promise putObjectLockConfigurationAsync(array $args = [])
  222.  * @method \Aws\Result putObjectRetention(array $args = [])
  223.  * @method \GuzzleHttp\Promise\Promise putObjectRetentionAsync(array $args = [])
  224.  * @method \Aws\Result putObjectTagging(array $args = [])
  225.  * @method \GuzzleHttp\Promise\Promise putObjectTaggingAsync(array $args = [])
  226.  * @method \Aws\Result putPublicAccessBlock(array $args = [])
  227.  * @method \GuzzleHttp\Promise\Promise putPublicAccessBlockAsync(array $args = [])
  228.  * @method \Aws\Result restoreObject(array $args = [])
  229.  * @method \GuzzleHttp\Promise\Promise restoreObjectAsync(array $args = [])
  230.  * @method \Aws\Result selectObjectContent(array $args = [])
  231.  * @method \GuzzleHttp\Promise\Promise selectObjectContentAsync(array $args = [])
  232.  * @method \Aws\Result uploadPart(array $args = [])
  233.  * @method \GuzzleHttp\Promise\Promise uploadPartAsync(array $args = [])
  234.  * @method \Aws\Result uploadPartCopy(array $args = [])
  235.  * @method \GuzzleHttp\Promise\Promise uploadPartCopyAsync(array $args = [])
  236.  * @method \Aws\Result writeGetObjectResponse(array $args = [])
  237.  * @method \GuzzleHttp\Promise\Promise writeGetObjectResponseAsync(array $args = [])
  238.  */
  239. class S3Client extends AwsClient implements S3ClientInterface
  240. {
  241.     private const DIRECTORY_BUCKET_REGEX '/^[a-zA-Z0-9_-]+--[a-z0-9]+-az\d+--x-s3'
  242.                                             .'(?!.*(?:-s3alias|--ol-s3|\.mrap))$/';
  243.     use S3ClientTrait;
  244.     /** @var array */
  245.     private static $mandatoryAttributes = ['Bucket''Key'];
  246.     public static function getArguments()
  247.     {
  248.         $args parent::getArguments();
  249.         $args['retries']['fn'] = [__CLASS__'_applyRetryConfig'];
  250.         $args['api_provider']['fn'] = [__CLASS__'_applyApiProvider'];
  251.         return $args + [
  252.             'bucket_endpoint' => [
  253.                 'type'    => 'config',
  254.                 'valid'   => ['bool'],
  255.                 'doc'     => 'Set to true to send requests to a hardcoded '
  256.                     'bucket endpoint rather than create an endpoint as a '
  257.                     'result of injecting the bucket into the URL. This '
  258.                     'option is useful for interacting with CNAME endpoints.',
  259.             ],
  260.             'use_arn_region' => [
  261.                 'type'    => 'config',
  262.                 'valid'   => [
  263.                     'bool',
  264.                     Configuration::class,
  265.                     CacheInterface::class,
  266.                     'callable'
  267.                 ],
  268.                 'doc'     => 'Set to true to allow passed in ARNs to override'
  269.                     ' client region. Accepts...',
  270.                 'fn' => [__CLASS__'_apply_use_arn_region'],
  271.                 'default' => [UseArnRegionConfigurationProvider::class, 'defaultProvider'],
  272.             ],
  273.             'use_accelerate_endpoint' => [
  274.                 'type' => 'config',
  275.                 'valid' => ['bool'],
  276.                 'doc' => 'Set to true to send requests to an S3 Accelerate'
  277.                     ' endpoint by default. Can be enabled or disabled on'
  278.                     ' individual operations by setting'
  279.                     ' \'@use_accelerate_endpoint\' to true or false. Note:'
  280.                     ' you must enable S3 Accelerate on a bucket before it can'
  281.                     ' be accessed via an Accelerate endpoint.',
  282.                 'default' => false,
  283.             ],
  284.             'use_path_style_endpoint' => [
  285.                 'type' => 'config',
  286.                 'valid' => ['bool'],
  287.                 'doc' => 'Set to true to send requests to an S3 path style'
  288.                     ' endpoint by default.'
  289.                     ' Can be enabled or disabled on individual operations by setting'
  290.                     ' \'@use_path_style_endpoint\' to true or false.',
  291.                 'default' => false,
  292.             ],
  293.             'disable_multiregion_access_points' => [
  294.                 'type' => 'config',
  295.                 'valid' => ['bool'],
  296.                 'doc' => 'Set to true to disable the usage of'
  297.                     ' multi region access points. These are enabled by default.'
  298.                     ' Can be enabled or disabled on individual operations by setting'
  299.                     ' \'@disable_multiregion_access_points\' to true or false.',
  300.                 'default' => false,
  301.             ],
  302.             'disable_express_session_auth' => [
  303.                 'type' => 'config',
  304.                 'valid' => ['bool'],
  305.                 'doc' => 'Set to true to disable the usage of'
  306.                     ' s3 express session authentication. This is enabled by default.',
  307.                 'default' => [__CLASS__'_default_disable_express_session_auth'],
  308.             ],
  309.             's3_express_identity_provider' => [
  310.                 'type'    => 'config',
  311.                 'valid'   => [
  312.                     'bool',
  313.                     'callable'
  314.                 ],
  315.                 'doc'     => 'Specifies the provider used to generate identities to sign s3 express requests.  '
  316.                     'Set to `false` to disable s3 express auth, or a callable provider used to create s3 express '
  317.                     'identities or return null.',
  318.                 'default' => [__CLASS__'_default_s3_express_identity_provider'],
  319.             ],
  320.         ];
  321.     }
  322.     /**
  323.      * {@inheritdoc}
  324.      *
  325.      * In addition to the options available to
  326.      * {@see Aws\AwsClient::__construct}, S3Client accepts the following
  327.      * options:
  328.      *
  329.      * - bucket_endpoint: (bool) Set to true to send requests to a
  330.      *   hardcoded bucket endpoint rather than create an endpoint as a result
  331.      *   of injecting the bucket into the URL. This option is useful for
  332.      *   interacting with CNAME endpoints. Note: if you are using version 2.243.0
  333.      *   and above and do not expect the bucket name to appear in the host, you will
  334.      *   also need to set `use_path_style_endpoint` to `true`.
  335.      * - calculate_md5: (bool) Set to false to disable calculating an MD5
  336.      *   for all Amazon S3 signed uploads.
  337.      * - s3_us_east_1_regional_endpoint:
  338.      *   (Aws\S3\RegionalEndpoint\ConfigurationInterface|Aws\CacheInterface\|callable|string|array)
  339.      *   Specifies whether to use regional or legacy endpoints for the us-east-1
  340.      *   region. Provide an Aws\S3\RegionalEndpoint\ConfigurationInterface object, an
  341.      *   instance of Aws\CacheInterface, a callable configuration provider used
  342.      *   to create endpoint configuration, a string value of `legacy` or
  343.      *   `regional`, or an associative array with the following keys:
  344.      *   endpoint_types: (string)  Set to `legacy` or `regional`, defaults to
  345.      *   `legacy`
  346.      * - use_accelerate_endpoint: (bool) Set to true to send requests to an S3
  347.      *   Accelerate endpoint by default. Can be enabled or disabled on
  348.      *   individual operations by setting '@use_accelerate_endpoint' to true or
  349.      *   false. Note: you must enable S3 Accelerate on a bucket before it can be
  350.      *   accessed via an Accelerate endpoint.
  351.      * - use_arn_region: (Aws\S3\UseArnRegion\ConfigurationInterface,
  352.      *   Aws\CacheInterface, bool, callable) Set to true to enable the client
  353.      *   to use the region from a supplied ARN argument instead of the client's
  354.      *   region. Provide an instance of Aws\S3\UseArnRegion\ConfigurationInterface,
  355.      *   an instance of Aws\CacheInterface, a callable that provides a promise for
  356.      *   a Configuration object, or a boolean value. Defaults to false (i.e.
  357.      *   the SDK will not follow the ARN region if it conflicts with the client
  358.      *   region and instead throw an error).
  359.      * - use_dual_stack_endpoint: (bool) Set to true to send requests to an S3
  360.      *   Dual Stack endpoint by default, which enables IPv6 Protocol.
  361.      *   Can be enabled or disabled on individual operations by setting
  362.      *   '@use_dual_stack_endpoint\' to true or false. Note:
  363.      *   you cannot use it together with an accelerate endpoint.
  364.      * - use_path_style_endpoint: (bool) Set to true to send requests to an S3
  365.      *   path style endpoint by default.
  366.      *   Can be enabled or disabled on individual operations by setting
  367.      *   '@use_path_style_endpoint\' to true or false. Note:
  368.      *   you cannot use it together with an accelerate endpoint.
  369.      * - disable_multiregion_access_points: (bool) Set to true to disable
  370.      *   sending multi region requests.  They are enabled by default.
  371.      *   Can be enabled or disabled on individual operations by setting
  372.      *   '@disable_multiregion_access_points\' to true or false. Note:
  373.      *   you cannot use it together with an accelerate or dualstack endpoint.
  374.      *
  375.      * @param array $args
  376.      */
  377.     public function __construct(array $args)
  378.     {
  379.         if (
  380.             !isset($args['s3_us_east_1_regional_endpoint'])
  381.             || $args['s3_us_east_1_regional_endpoint'] instanceof CacheInterface
  382.         ) {
  383.             $args['s3_us_east_1_regional_endpoint'] = ConfigurationProvider::defaultProvider($args);
  384.         }
  385.         $this->addBuiltIns($args);
  386.         parent::__construct($args);
  387.         $stack $this->getHandlerList();
  388.         $stack->appendInit(SSECMiddleware::wrap($this->getEndpoint()->getScheme()), 's3.ssec');
  389.         $stack->appendBuild(ApplyChecksumMiddleware::wrap($this->getApi()), 's3.checksum');
  390.         $stack->appendBuild(
  391.             Middleware::contentType(['PutObject''UploadPart']),
  392.             's3.content_type'
  393.         );
  394.         if ($this->getConfig('bucket_endpoint')) {
  395.             $stack->appendBuild(BucketEndpointMiddleware::wrap(), 's3.bucket_endpoint');
  396.         } elseif (!$this->isUseEndpointV2()) {
  397.             $stack->appendBuild(
  398.                 S3EndpointMiddleware::wrap(
  399.                     $this->getRegion(),
  400.                     $this->getConfig('endpoint_provider'),
  401.                     [
  402.                         'accelerate' => $this->getConfig('use_accelerate_endpoint'),
  403.                         'path_style' => $this->getConfig('use_path_style_endpoint'),
  404.                         'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'),
  405.                         'dual_stack' =>
  406.                             $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(),
  407.                     ]
  408.                 ),
  409.                 's3.endpoint_middleware'
  410.             );
  411.         }
  412.         $stack->appendBuild(
  413.             BucketEndpointArnMiddleware::wrap(
  414.                 $this->getApi(),
  415.                 $this->getRegion(),
  416.                 [
  417.                     'use_arn_region' => $this->getConfig('use_arn_region'),
  418.                     'accelerate' => $this->getConfig('use_accelerate_endpoint'),
  419.                     'path_style' => $this->getConfig('use_path_style_endpoint'),
  420.                     'dual_stack' =>
  421.                         $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(),
  422.                     'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'),
  423.                     'disable_multiregion_access_points' =>
  424.                         $this->getConfig('disable_multiregion_access_points'),
  425.                     'endpoint' => $args['endpoint'] ?? null
  426.                 ],
  427.                 $this->isUseEndpointV2()
  428.             ),
  429.             's3.bucket_endpoint_arn'
  430.         );
  431.         if ($this->getConfig('disable_express_session_auth')) {
  432.             $stack->prependSign(
  433.                 $this->getDisableExpressSessionAuthMiddleware(),
  434.                 's3.disable_express_session_auth'
  435.             );
  436.         }
  437.         $stack->appendValidate(
  438.             InputValidationMiddleware::wrap($this->getApi(), self::$mandatoryAttributes),
  439.             'input_validation_middleware'
  440.         );
  441.         $stack->appendSign(ExpiresParsingMiddleware::wrap(), 's3.expires_parsing');
  442.         $stack->appendSign(PutObjectUrlMiddleware::wrap(), 's3.put_object_url');
  443.         $stack->appendSign(PermanentRedirectMiddleware::wrap(), 's3.permanent_redirect');
  444.         $stack->appendInit(Middleware::sourceFile($this->getApi()), 's3.source_file');
  445.         $stack->appendInit($this->getSaveAsParameter(), 's3.save_as');
  446.         $stack->appendInit($this->getLocationConstraintMiddleware(), 's3.location');
  447.         $stack->appendInit($this->getEncodingTypeMiddleware(), 's3.auto_encode');
  448.         $stack->appendInit($this->getHeadObjectMiddleware(), 's3.head_object');
  449.         $this->processModel($this->isUseEndpointV2());
  450.         if ($this->isUseEndpointV2()) {
  451.             $stack->after('builder',
  452.                 's3.check_empty_path_with_query',
  453.                 $this->getEmptyPathWithQuery());
  454.         }
  455.     }
  456.     /**
  457.      * Determine if a string is a valid name for a DNS compatible Amazon S3
  458.      * bucket.
  459.      *
  460.      * DNS compatible bucket names can be used as a subdomain in a URL (e.g.,
  461.      * "<bucket>.s3.amazonaws.com").
  462.      *
  463.      * @param string $bucket Bucket name to check.
  464.      *
  465.      * @return bool
  466.      */
  467.     public static function isBucketDnsCompatible($bucket)
  468.     {
  469.         if (!is_string($bucket)) {
  470.             return false;
  471.         }
  472.         $bucketLen strlen($bucket);
  473.         return ($bucketLen >= && $bucketLen <= 63) &&
  474.             // Cannot look like an IP address
  475.             !filter_var($bucketFILTER_VALIDATE_IP) &&
  476.             preg_match('/^[a-z0-9]([a-z0-9\-\.]*[a-z0-9])?$/'$bucket);
  477.     }
  478.     public static function _apply_use_arn_region($value, array &$argsHandlerList $list)
  479.     {
  480.         if ($value instanceof CacheInterface) {
  481.             $value UseArnRegionConfigurationProvider::defaultProvider($args);
  482.         }
  483.         if (is_callable($value)) {
  484.             $value $value();
  485.         }
  486.         if ($value instanceof PromiseInterface) {
  487.             $value $value->wait();
  488.         }
  489.         if ($value instanceof ConfigurationInterface) {
  490.             $args['use_arn_region'] = $value;
  491.         } else {
  492.             // The Configuration class itself will validate other inputs
  493.             $args['use_arn_region'] = new Configuration($value);
  494.         }
  495.     }
  496.     public function createPresignedRequest(CommandInterface $command$expires, array $options = [])
  497.     {
  498.         $command = clone $command;
  499.         $command->getHandlerList()->remove('signer');
  500.         $request = \Aws\serialize($command);
  501.         $signing_name $command['@context']['signing_service']
  502.             ?? $this->getSigningName($request->getUri()->getHost());
  503.         $signature_version $this->getSignatureVersionFromCommand($command);
  504.         /** @var \Aws\Signature\SignatureInterface $signer */
  505.         $signer call_user_func(
  506.             $this->getSignatureProvider(),
  507.             $signature_version,
  508.             $signing_name,
  509.             $this->getConfig('signing_region')
  510.         );
  511.         if ($signature_version == 'v4-s3express') {
  512.             $provider $this->getConfig('s3_express_identity_provider');
  513.             $credentials $provider($command)->wait();
  514.         } else {
  515.             $credentials $this->getCredentials()->wait();
  516.         }
  517.         return $signer->presign(
  518.             $request,
  519.             $credentials,
  520.             $expires,
  521.             $options
  522.         );
  523.     }
  524.     /**
  525.      * Returns the URL to an object identified by its bucket and key.
  526.      *
  527.      * The URL returned by this method is not signed nor does it ensure that the
  528.      * bucket and key given to the method exist. If you need a signed URL, then
  529.      * use the {@see \Aws\S3\S3Client::createPresignedRequest} method and get
  530.      * the URI of the signed request.
  531.      *
  532.      * @param string $bucket  The name of the bucket where the object is located
  533.      * @param string $key     The key of the object
  534.      *
  535.      * @return string The URL to the object
  536.      */
  537.     public function getObjectUrl($bucket$key)
  538.     {
  539.         $command $this->getCommand('GetObject', [
  540.             'Bucket' => $bucket,
  541.             'Key'    => $key
  542.         ]);
  543.         return (string) \Aws\serialize($command)->getUri();
  544.     }
  545.     /**
  546.      * Raw URL encode a key and allow for '/' characters
  547.      *
  548.      * @param string $key Key to encode
  549.      *
  550.      * @return string Returns the encoded key
  551.      */
  552.     public static function encodeKey($key)
  553.     {
  554.         return str_replace('%2F''/'rawurlencode($key));
  555.     }
  556.     /**
  557.      * Provides a middleware that removes the need to specify LocationConstraint on CreateBucket.
  558.      *
  559.      * @return \Closure
  560.      */
  561.     private function getLocationConstraintMiddleware()
  562.     {
  563.         $region $this->getRegion();
  564.         return static function (callable $handler) use ($region) {
  565.             return function (Command $command$request null) use ($handler$region) {
  566.                 if ($command->getName() === 'CreateBucket'
  567.                     && !self::isDirectoryBucket($command['Bucket'])
  568.                 ) {
  569.                     $locationConstraint $command['CreateBucketConfiguration']['LocationConstraint']
  570.                         ?? null;
  571.                     if ($locationConstraint === 'us-east-1') {
  572.                         unset($command['CreateBucketConfiguration']);
  573.                     } elseif ('us-east-1' !== $region && empty($locationConstraint)) {
  574.                         if (isset($command['CreateBucketConfiguration'])) {
  575.                             $command['CreateBucketConfiguration']['LocationConstraint'] = $region;
  576.                         } else {
  577.                             $command['CreateBucketConfiguration'] = ['LocationConstraint' => $region];
  578.                         }
  579.                     }
  580.                 }
  581.                 return $handler($command$request);
  582.             };
  583.         };
  584.     }
  585.     /**
  586.      * Provides a middleware that supports the `SaveAs` parameter.
  587.      *
  588.      * @return \Closure
  589.      */
  590.     private function getSaveAsParameter()
  591.     {
  592.         return static function (callable $handler) {
  593.             return function (Command $command$request null) use ($handler) {
  594.                 if ($command->getName() === 'GetObject' && isset($command['SaveAs'])) {
  595.                     $command['@http']['sink'] = $command['SaveAs'];
  596.                     unset($command['SaveAs']);
  597.                 }
  598.                 return $handler($command$request);
  599.             };
  600.         };
  601.     }
  602.     /**
  603.      * Provides a middleware that disables content decoding on HeadObject
  604.      * commands.
  605.      *
  606.      * @return \Closure
  607.      */
  608.     private function getHeadObjectMiddleware()
  609.     {
  610.         return static function (callable $handler) {
  611.             return function (
  612.                 CommandInterface $command,
  613.                 ?RequestInterface $request null
  614.             ) use ($handler) {
  615.                 if ($command->getName() === 'HeadObject'
  616.                     && !isset($command['@http']['decode_content'])
  617.                 ) {
  618.                     $command['@http']['decode_content'] = false;
  619.                 }
  620.                 return $handler($command$request);
  621.             };
  622.         };
  623.     }
  624.     /**
  625.      * Provides a middleware that autopopulates the EncodingType parameter on
  626.      * ListObjects commands.
  627.      *
  628.      * @return \Closure
  629.      */
  630.     private function getEncodingTypeMiddleware()
  631.     {
  632.         return static function (callable $handler) {
  633.             return function (Command $command$request null) use ($handler) {
  634.                 $autoSet false;
  635.                 if ($command->getName() === 'ListObjects'
  636.                     && empty($command['EncodingType'])
  637.                 ) {
  638.                     $command['EncodingType'] = 'url';
  639.                     $autoSet true;
  640.                 }
  641.                 return $handler($command$request)
  642.                     ->then(function (ResultInterface $result) use ($autoSet) {
  643.                         if ($result['EncodingType'] === 'url' && $autoSet) {
  644.                             static $topLevel = [
  645.                                 'Delimiter',
  646.                                 'Marker',
  647.                                 'NextMarker',
  648.                                 'Prefix',
  649.                             ];
  650.                             static $nested = [
  651.                                 ['Contents''Key'],
  652.                                 ['CommonPrefixes''Prefix'],
  653.                             ];
  654.                             foreach ($topLevel as $key) {
  655.                                 if (isset($result[$key])) {
  656.                                     $result[$key] = urldecode($result[$key]);
  657.                                 }
  658.                             }
  659.                             foreach ($nested as $steps) {
  660.                                 if (isset($result[$steps[0]])) {
  661.                                     foreach ($result[$steps[0]] as $key => $part) {
  662.                                         if (isset($part[$steps[1]])) {
  663.                                             $result[$steps[0]][$key][$steps[1]]
  664.                                                 = urldecode($part[$steps[1]]);
  665.                                         }
  666.                                     }
  667.                                 }
  668.                             }
  669.                         }
  670.                         return $result;
  671.                     });
  672.             };
  673.         };
  674.     }
  675.     /**
  676.      * Provides a middleware that checks for an empty path and a
  677.      * non-empty query string.
  678.      *
  679.      * @return \Closure
  680.      */
  681.     private function getEmptyPathWithQuery()
  682.     {
  683.         return static function (callable $handler) {
  684.             return function (Command $commandRequestInterface $request) use ($handler) {
  685.                 $uri $request->getUri();
  686.                 if (empty($uri->getPath()) && !empty($uri->getQuery())) {
  687.                     $uri $uri->withPath('/');
  688.                     $request $request->withUri($uri);
  689.                 }
  690.                 return $handler($command$request);
  691.             };
  692.         };
  693.     }
  694.     /**
  695.      * Provides a middleware that disables express session auth when
  696.      * customers opt out of it.
  697.      *
  698.      * @return \Closure
  699.      */
  700.     private function getDisableExpressSessionAuthMiddleware()
  701.     {
  702.         return function (callable $handler) {
  703.             return function (
  704.                 CommandInterface $command,
  705.                 ?RequestInterface $request null
  706.             ) use ($handler) {
  707.                 if (!empty($command['@context']['signature_version'])
  708.                     && $command['@context']['signature_version'] === 'v4-s3express'
  709.                 ) {
  710.                     $command['@context']['signature_version'] = 's3v4';
  711.                 }
  712.                 return $handler($command$request);
  713.             };
  714.         };
  715.     }
  716.     /**
  717.      * Special handling for when the service name is s3-object-lambda.
  718.      * So, if the host contains s3-object-lambda, then the service name
  719.      * returned is s3-object-lambda, otherwise the default signing service is returned.
  720.      * @param string $host The host to validate if is a s3-object-lambda URL.
  721.      * @return string returns the signing service name to be used
  722.      */
  723.     private function getSigningName($host)
  724.     {
  725.         if (strpos$host's3-object-lambda')) {
  726.             return 's3-object-lambda';
  727.         }
  728.         return $this->getConfig('signing_name');
  729.     }
  730.     public static function _default_disable_express_session_auth(array &$args) {
  731.         return ConfigurationResolver::resolve(
  732.             's3_disable_express_session_auth',
  733.             false,
  734.             'bool',
  735.             $args
  736.         );
  737.     }
  738.     public static function _default_s3_express_identity_provider(array $args)
  739.     {
  740.         if ($args['config']['disable_express_session_auth']) {
  741.             return false;
  742.         }
  743.         return new S3ExpressIdentityProvider($args['region']);
  744.     }
  745.     /**
  746.      * If EndpointProviderV2 is used, removes `Bucket` from request URIs.
  747.      * This is now handled by the endpoint ruleset.
  748.      *
  749.      * Additionally adds a synthetic shape `ExpiresString` and modifies
  750.      * `Expires` type to ensure it remains set to `timestamp`.
  751.      *
  752.      * @param array $args
  753.      * @return void
  754.      *
  755.      * @internal
  756.      */
  757.     private function processModel(bool $isUseEndpointV2): void
  758.     {
  759.         $definition $this->getApi()->getDefinition();
  760.         if ($isUseEndpointV2) {
  761.             foreach($definition['operations'] as &$operation) {
  762.                 if (isset($operation['http']['requestUri'])) {
  763.                     $requestUri $operation['http']['requestUri'];
  764.                     if ($requestUri === "/{Bucket}") {
  765.                         $requestUri str_replace('/{Bucket}''/'$requestUri);
  766.                     } else {
  767.                         $requestUri str_replace('/{Bucket}'''$requestUri);
  768.                     }
  769.                     $operation['http']['requestUri'] = $requestUri;
  770.                 }
  771.             }
  772.         }
  773.         foreach ($definition['shapes'] as $key => &$value) {
  774.             $suffix 'Output';
  775.             if (substr($key, -strlen($suffix)) === $suffix) {
  776.                 if (isset($value['members']['Expires'])) {
  777.                     $value['members']['Expires']['deprecated'] = true;
  778.                     $value['members']['ExpiresString'] = [
  779.                         'shape' => 'ExpiresString',
  780.                         'location' => 'header',
  781.                         'locationName' => 'Expires'
  782.                     ];
  783.                 }
  784.             }
  785.         }
  786.         $definition['shapes']['ExpiresString']['type'] = 'string';
  787.         $definition['shapes']['Expires']['type'] = 'timestamp';
  788.         $this->getApi()->setDefinition($definition);
  789.     }
  790.     /**
  791.      * Adds service-specific client built-in values
  792.      *
  793.      * @return void
  794.      */
  795.     private function addBuiltIns($args)
  796.     {
  797.         if (isset($args['region'])
  798.             && $args['region'] !== 'us-east-1'
  799.         ) {
  800.             return false;
  801.         }
  802.         if (!isset($args['region'])
  803.             && ConfigurationResolver::resolve('region''''string') !== 'us-east-1'
  804.         ) {
  805.             return false;
  806.         }
  807.         $key 'AWS::S3::UseGlobalEndpoint';
  808.         $result $args['s3_us_east_1_regional_endpoint'] instanceof \Closure ?
  809.             $args['s3_us_east_1_regional_endpoint']()->wait() : $args['s3_us_east_1_regional_endpoint'];
  810.         if (is_string($result)) {
  811.             if ($result === 'regional') {
  812.                 $value false;
  813.             } else if ($result === 'legacy') {
  814.                 $value true;
  815.             } else {
  816.                 return;
  817.             }
  818.         } else {
  819.             if ($result->isFallback()
  820.                 || $result->getEndpointsType() === 'legacy'
  821.             ) {
  822.                 $value true;
  823.             } else {
  824.                 $value false;
  825.             }
  826.         }
  827.         $this->clientBuiltIns[$key] = $value;
  828.     }
  829.     /**
  830.      * Determines whether a bucket is a directory bucket.
  831.      * Only considers the availability zone/suffix format
  832.      *
  833.      * @param string $bucket
  834.      * @return bool
  835.      */
  836.     public static function isDirectoryBucket(string $bucket): bool
  837.     {
  838.         return preg_match(self::DIRECTORY_BUCKET_REGEX$bucket) === 1;
  839.     }
  840.     /** @internal */
  841.     public static function _applyRetryConfig($value$argsHandlerList $list)
  842.     {
  843.         if ($value) {
  844.             $config = \Aws\Retry\ConfigurationProvider::unwrap($value);
  845.             if ($config->getMode() === 'legacy') {
  846.                 $maxRetries $config->getMaxAttempts() - 1;
  847.                 $decider RetryMiddleware::createDefaultDecider($maxRetries);
  848.                 $decider = function ($retries$command$request$result$error) use ($decider$maxRetries) {
  849.                     $maxRetries $command['@retries'] ?? $maxRetries;
  850.                     if ($decider($retries$command$request$result$error)) {
  851.                         return true;
  852.                     }
  853.                     if ($error instanceof AwsException
  854.                         && $retries $maxRetries
  855.                     ) {
  856.                         if ($error->getResponse()
  857.                             && $error->getResponse()->getStatusCode() >= 400
  858.                         ) {
  859.                             return strpos(
  860.                                     $error->getResponse()->getBody(),
  861.                                     'Your socket connection to the server'
  862.                                 ) !== false;
  863.                         }
  864.                         if ($error->getPrevious() instanceof RequestException) {
  865.                             // All commands except CompleteMultipartUpload are
  866.                             // idempotent and may be retried without worry if a
  867.                             // networking error has occurred.
  868.                             return $command->getName() !== 'CompleteMultipartUpload';
  869.                         }
  870.                     }
  871.                     return false;
  872.                 };
  873.                 $delay = [RetryMiddleware::class, 'exponentialDelay'];
  874.                 $list->appendSign(Middleware::retry($decider$delay), 'retry');
  875.             } else {
  876.                 $defaultDecider RetryMiddlewareV2::createDefaultDecider(
  877.                     new QuotaManager(),
  878.                     $config->getMaxAttempts()
  879.                 );
  880.                 $list->appendSign(
  881.                     RetryMiddlewareV2::wrap(
  882.                         $config,
  883.                         [
  884.                             'collect_stats' => $args['stats']['retries'],
  885.                             'decider' => function(
  886.                                 $attempts,
  887.                                 CommandInterface $cmd,
  888.                                 $result
  889.                             ) use ($defaultDecider$config) {
  890.                                 $isRetryable $defaultDecider($attempts$cmd$result);
  891.                                 if (!$isRetryable
  892.                                     && $result instanceof AwsException
  893.                                     && $attempts $config->getMaxAttempts()
  894.                                 ) {
  895.                                     if (!empty($result->getResponse())
  896.                                         && $result->getResponse()->getStatusCode() >= 400
  897.                                     ) {
  898.                                         return strpos(
  899.                                                 $result->getResponse()->getBody(),
  900.                                                 'Your socket connection to the server'
  901.                                             ) !== false;
  902.                                     }
  903.                                     if ($result->getPrevious() instanceof RequestException
  904.                                         && $cmd->getName() !== 'CompleteMultipartUpload'
  905.                                     ) {
  906.                                         $isRetryable true;
  907.                                     }
  908.                                 }
  909.                                 return $isRetryable;
  910.                             }
  911.                         ]
  912.                     ),
  913.                     'retry'
  914.                 );
  915.             }
  916.         }
  917.     }
  918.     /** @internal */
  919.     public static function _applyApiProvider($value, array &$argsHandlerList $list)
  920.     {
  921.         ClientResolver::_apply_api_provider($value$args);
  922.         $s3Parser = new S3Parser(
  923.             $args['parser'],
  924.             $args['error_parser'],
  925.             $args['api'],
  926.             $args['exception_class']
  927.         );
  928.         $s3Parser->addS3ResultMutator(
  929.             'get-bucket-location',
  930.             new GetBucketLocationResultMutator()
  931.         );
  932.         $s3Parser->addS3ResultMutator(
  933.             'validate-response-checksum',
  934.             new ValidateResponseChecksumResultMutator($args['api'])
  935.         );
  936.         $args['parser'] = $s3Parser;
  937.     }
  938.     /**
  939.      * @internal
  940.      * @codeCoverageIgnore
  941.      */
  942.     public static function applyDocFilters(array $api, array $docs)
  943.     {
  944.         $b64 '<div class="alert alert-info">This value will be base64 encoded on your behalf.</div>';
  945.         $opt '<div class="alert alert-info">This value will be computed for you it is not supplied.</div>';
  946.         // Add a note on the CopyObject docs
  947.          $s3ExceptionRetryMessage "<p>Additional info on response behavior: if there is"
  948.             " an internal error in S3 after the request was successfully recieved,"
  949.             " a 200 response will be returned with an <code>S3Exception</code> embedded"
  950.             " in it; this will still be caught and retried by"
  951.             " <code>RetryMiddleware.</code></p>";
  952.         $docs['operations']['CopyObject'] .=  $s3ExceptionRetryMessage;
  953.         $docs['operations']['CompleteMultipartUpload'] .=  $s3ExceptionRetryMessage;
  954.         $docs['operations']['UploadPartCopy'] .=  $s3ExceptionRetryMessage;
  955.         $docs['operations']['UploadPart'] .=  $s3ExceptionRetryMessage;
  956.         // Add note about stream ownership in the putObject call
  957.         $guzzleStreamMessage "<p>Additional info on behavior of the stream"
  958.             " parameters: Psr7 takes ownership of streams and will automatically close"
  959.             " streams when this method is called with a stream as the <code>Body</code>"
  960.             " parameter.  To prevent this, set the <code>Body</code> using"
  961.             " <code>GuzzleHttp\Psr7\stream_for</code> method with a is an instance of"
  962.             " <code>Psr\Http\Message\StreamInterface</code>, and it will be returned"
  963.             " unmodified. This will allow you to keep the stream in scope. </p>";
  964.         $docs['operations']['PutObject'] .=  $guzzleStreamMessage;
  965.         // Add the SourceFile parameter.
  966.         $docs['shapes']['SourceFile']['base'] = 'The path to a file on disk to use instead of the Body parameter.';
  967.         $api['shapes']['SourceFile'] = ['type' => 'string'];
  968.         $api['shapes']['PutObjectRequest']['members']['SourceFile'] = ['shape' => 'SourceFile'];
  969.         $api['shapes']['UploadPartRequest']['members']['SourceFile'] = ['shape' => 'SourceFile'];
  970.         // Add the ContentSHA256 parameter.
  971.         $docs['shapes']['ContentSHA256']['base'] = 'A SHA256 hash of the body content of the request.';
  972.         $api['shapes']['ContentSHA256'] = ['type' => 'string'];
  973.         $api['shapes']['PutObjectRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256'];
  974.         $api['shapes']['UploadPartRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256'];
  975.         $docs['shapes']['ContentSHA256']['append'] = $opt;
  976.         // Add the AddContentMD5 parameter.
  977.         $docs['shapes']['AddContentMD5']['base'] = 'Set to true to calculate the ContentMD5 for the upload.';
  978.         $api['shapes']['AddContentMD5'] = ['type' => 'boolean'];
  979.         $api['shapes']['PutObjectRequest']['members']['AddContentMD5'] = ['shape' => 'AddContentMD5'];
  980.         $api['shapes']['UploadPartRequest']['members']['AddContentMD5'] = ['shape' => 'AddContentMD5'];
  981.         // Add the SaveAs parameter.
  982.         $docs['shapes']['SaveAs']['base'] = 'The path to a file on disk to save the object data.';
  983.         $api['shapes']['SaveAs'] = ['type' => 'string'];
  984.         $api['shapes']['GetObjectRequest']['members']['SaveAs'] = ['shape' => 'SaveAs'];
  985.         // Several SSECustomerKey documentation updates.
  986.         $docs['shapes']['SSECustomerKey']['append'] = $b64;
  987.         $docs['shapes']['CopySourceSSECustomerKey']['append'] = $b64;
  988.         $docs['shapes']['SSECustomerKeyMd5']['append'] = $opt;
  989.         // Add the ObjectURL to various output shapes and documentation.
  990.         $docs['shapes']['ObjectURL']['base'] = 'The URI of the created object.';
  991.         $api['shapes']['ObjectURL'] = ['type' => 'string'];
  992.         $api['shapes']['PutObjectOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL'];
  993.         $api['shapes']['CopyObjectOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL'];
  994.         $api['shapes']['CompleteMultipartUploadOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL'];
  995.         // Fix references to Location Constraint.
  996.         unset($api['shapes']['CreateBucketRequest']['payload']);
  997.         $api['shapes']['BucketLocationConstraint']['enum'] = [
  998.             "ap-northeast-1",
  999.             "ap-southeast-2",
  1000.             "ap-southeast-1",
  1001.             "cn-north-1",
  1002.             "eu-central-1",
  1003.             "eu-west-1",
  1004.             "us-east-1",
  1005.             "us-west-1",
  1006.             "us-west-2",
  1007.             "sa-east-1",
  1008.         ];
  1009.         // Add a note that the ContentMD5 is automatically computed, except for with PutObject and UploadPart
  1010.         $docs['shapes']['ContentMD5']['append'] = '<div class="alert alert-info">The value will be computed on '
  1011.             'your behalf.</div>';
  1012.         $docs['shapes']['ContentMD5']['excludeAppend'] = ['PutObjectRequest''UploadPartRequest'];
  1013.         //Add a note to ContentMD5 for PutObject and UploadPart that specifies the value is required
  1014.         // When uploading to a bucket with object lock enabled and that it is not computed automatically
  1015.         $objectLock '<div class="alert alert-info">This value is required if uploading to a bucket '
  1016.             'which has Object Lock enabled. It will not be calculated for you automatically. If you wish to have '
  1017.             'the value calculated for you, use the `AddContentMD5` parameter.</div>';
  1018.         $docs['shapes']['ContentMD5']['appendOnly'] = [
  1019.             'message' => $objectLock,
  1020.             'shapes' => ['PutObjectRequest''UploadPartRequest']
  1021.         ];
  1022.         // Add `ExpiresString` shape to output structures which contain `Expires`
  1023.         // Deprecate existing `Expires` shapes in output structures
  1024.         // Add/Update documentation for both `ExpiresString` and `Expires`
  1025.         // Ensure `Expires` type remains timestamp
  1026.         foreach ($api['shapes'] as $key => &$value) {
  1027.             $suffix 'Output';
  1028.             if (substr($key, -strlen($suffix)) === $suffix) {
  1029.                 if (isset($value['members']['Expires'])) {
  1030.                     $value['members']['Expires']['deprecated'] = true;
  1031.                     $value['members']['ExpiresString'] = [
  1032.                         'shape' => 'ExpiresString',
  1033.                         'location' => 'header',
  1034.                         'locationName' => 'Expires'
  1035.                     ];
  1036.                     $docs['shapes']['Expires']['refs'][$key '$Expires']
  1037.                         .= '<p>This output shape has been deprecated. Please refer to <code>ExpiresString</code> instead.</p>.';
  1038.                 }
  1039.             }
  1040.         }
  1041.         $api['shapes']['ExpiresString']['type'] = 'string';
  1042.         $docs['shapes']['ExpiresString']['base'] = 'The unparsed string value of the <code>Expires</code> output member.';
  1043.         $api['shapes']['Expires']['type'] = 'timestamp';
  1044.         return [
  1045.             new Service($apiApiProvider::defaultProvider()),
  1046.             new DocModel($docs)
  1047.         ];
  1048.     }
  1049.     /**
  1050.      * @internal
  1051.      * @codeCoverageIgnore
  1052.      */
  1053.     public static function addDocExamples($examples)
  1054.     {
  1055.         $getObjectExample = [
  1056.             'input' => [
  1057.                 'Bucket' => 'arn:aws:s3:us-east-1:123456789012:accesspoint:myaccesspoint',
  1058.                 'Key' => 'my-key'
  1059.             ],
  1060.             'output' => [
  1061.                 'Body' => 'class GuzzleHttp\Psr7\Stream#208 (7) {...}',
  1062.                 'ContentLength' => '11',
  1063.                 'ContentType' => 'application/octet-stream',
  1064.             ],
  1065.             'comments' => [
  1066.                 'input' => '',
  1067.                 'output' => 'Simplified example output'
  1068.             ],
  1069.             'description' => 'The following example retrieves an object by referencing the bucket via an S3 accesss point ARN. Result output is simplified for the example.',
  1070.             'id' => '',
  1071.             'title' => 'To get an object via an S3 access point ARN'
  1072.         ];
  1073.         if (isset($examples['GetObject'])) {
  1074.             $examples['GetObject'] []= $getObjectExample;
  1075.         } else {
  1076.             $examples['GetObject'] = [$getObjectExample];
  1077.         }
  1078.         $putObjectExample = [
  1079.             'input' => [
  1080.                 'Bucket' => 'arn:aws:s3:us-east-1:123456789012:accesspoint:myaccesspoint',
  1081.                 'Key' => 'my-key',
  1082.                 'Body' => 'my-body',
  1083.             ],
  1084.             'output' => [
  1085.                 'ObjectURL' => 'https://my-bucket.s3.us-east-1.amazonaws.com/my-key'
  1086.             ],
  1087.             'comments' => [
  1088.                 'input' => '',
  1089.                 'output' => 'Simplified example output'
  1090.             ],
  1091.             'description' => 'The following example uploads an object by referencing the bucket via an S3 accesss point ARN. Result output is simplified for the example.',
  1092.             'id' => '',
  1093.             'title' => 'To upload an object via an S3 access point ARN'
  1094.         ];
  1095.         if (isset($examples['PutObject'])) {
  1096.             $examples['PutObject'] []= $putObjectExample;
  1097.         } else {
  1098.             $examples['PutObject'] = [$putObjectExample];
  1099.         }
  1100.         return $examples;
  1101.     }
  1102.     /**
  1103.      * @param CommandInterface $command
  1104.      * @return array|mixed|null
  1105.      */
  1106.     private function getSignatureVersionFromCommand(CommandInterface $command)
  1107.     {
  1108.         return $command['@context']['signature_version']
  1109.             ?? $this->getConfig('signature_version');
  1110.     }
  1111. }