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

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.     /** @var array */
  247.     private static $checksumOptionEnum = [
  248.         'when_supported' => true,
  249.         'when_required' => true
  250.     ];
  251.     public static function getArguments()
  252.     {
  253.         $args parent::getArguments();
  254.         $args['retries']['fn'] = [__CLASS__'_applyRetryConfig'];
  255.         $args['api_provider']['fn'] = [__CLASS__'_applyApiProvider'];
  256.         return
  257.             [
  258.                 'request_checksum_calculation' => [
  259.                     'type' => 'config',
  260.                     'valid' => ['string'],
  261.                     'doc' => 'Valid values are `when_supported` and `when_required`. Default is `when_supported`.'
  262.                         ' `when_supported` results in checksum calculation when an operation has modeled checksum support.'
  263.                         ' `when_required` results in checksum calculation when an operation has modeled checksum support and'
  264.                         ' request checksums are modeled as required.',
  265.                     'fn' => [__CLASS__'_apply_request_checksum_calculation'],
  266.                     'default' => [__CLASS__'_default_request_checksum_calculation'],
  267.                 ],
  268.                 'response_checksum_validation' => [
  269.                     'type' => 'config',
  270.                     'valid' => ['string'],
  271.                     'doc' => 'Valid values are `when_supported` and `when_required`. Default is `when_supported`.'
  272.                         ' `when_supported` results in checksum validation when an operation has modeled checksum support.'
  273.                         ' `when_required` results in checksum validation when an operation has modeled checksum support and'
  274.                         ' `CheckSumMode` is set to `enabled`.',
  275.                     'fn' => [__CLASS__'_apply_response_checksum_validation'],
  276.                     'default' => [__CLASS__'_default_response_checksum_validation'],
  277.                 ]
  278.             ]
  279.             + $args + [
  280.                 'bucket_endpoint' => [
  281.                     'type'    => 'config',
  282.                     'valid'   => ['bool'],
  283.                     'doc'     => 'Set to true to send requests to a hardcoded '
  284.                         'bucket endpoint rather than create an endpoint as a '
  285.                         'result of injecting the bucket into the URL. This '
  286.                         'option is useful for interacting with CNAME endpoints.',
  287.                 ],
  288.                 'use_arn_region' => [
  289.                     'type'    => 'config',
  290.                     'valid'   => [
  291.                         'bool',
  292.                         Configuration::class,
  293.                         CacheInterface::class,
  294.                         'callable'
  295.                     ],
  296.                     'doc'     => 'Set to true to allow passed in ARNs to override'
  297.                         ' client region. Accepts...',
  298.                     'fn' => [__CLASS__'_apply_use_arn_region'],
  299.                     'default' => [UseArnRegionConfigurationProvider::class, 'defaultProvider'],
  300.                 ],
  301.                 'use_accelerate_endpoint' => [
  302.                     'type' => 'config',
  303.                     'valid' => ['bool'],
  304.                     'doc' => 'Set to true to send requests to an S3 Accelerate'
  305.                         ' endpoint by default. Can be enabled or disabled on'
  306.                         ' individual operations by setting'
  307.                         ' \'@use_accelerate_endpoint\' to true or false. Note:'
  308.                         ' you must enable S3 Accelerate on a bucket before it can'
  309.                         ' be accessed via an Accelerate endpoint.',
  310.                     'default' => false,
  311.                 ],
  312.                 'use_path_style_endpoint' => [
  313.                     'type' => 'config',
  314.                     'valid' => ['bool'],
  315.                     'doc' => 'Set to true to send requests to an S3 path style'
  316.                         ' endpoint by default.'
  317.                         ' Can be enabled or disabled on individual operations by setting'
  318.                         ' \'@use_path_style_endpoint\' to true or false.',
  319.                     'default' => false,
  320.                 ],
  321.                 'disable_multiregion_access_points' => [
  322.                     'type' => 'config',
  323.                     'valid' => ['bool'],
  324.                     'doc' => 'Set to true to disable the usage of'
  325.                         ' multi region access points. These are enabled by default.'
  326.                         ' Can be enabled or disabled on individual operations by setting'
  327.                         ' \'@disable_multiregion_access_points\' to true or false.',
  328.                     'default' => false,
  329.                 ],
  330.                 'disable_express_session_auth' => [
  331.                     'type' => 'config',
  332.                     'valid' => ['bool'],
  333.                     'doc' => 'Set to true to disable the usage of'
  334.                         ' s3 express session authentication. This is enabled by default.',
  335.                     'default' => [__CLASS__'_default_disable_express_session_auth'],
  336.                 ],
  337.                 's3_express_identity_provider' => [
  338.                     'type'    => 'config',
  339.                     'valid'   => [
  340.                         'bool',
  341.                         'callable'
  342.                     ],
  343.                     'doc'     => 'Specifies the provider used to generate identities to sign s3 express requests.  '
  344.                         'Set to `false` to disable s3 express auth, or a callable provider used to create s3 express '
  345.                         'identities or return null.',
  346.                     'default' => [__CLASS__'_default_s3_express_identity_provider'],
  347.             ],
  348.         ];
  349.     }
  350.     /**
  351.      * {@inheritdoc}
  352.      *
  353.      * In addition to the options available to
  354.      * {@see Aws\AwsClient::__construct}, S3Client accepts the following
  355.      * options:
  356.      *
  357.      * - bucket_endpoint: (bool) Set to true to send requests to a
  358.      *   hardcoded bucket endpoint rather than create an endpoint as a result
  359.      *   of injecting the bucket into the URL. This option is useful for
  360.      *   interacting with CNAME endpoints. Note: if you are using version 2.243.0
  361.      *   and above and do not expect the bucket name to appear in the host, you will
  362.      *   also need to set `use_path_style_endpoint` to `true`.
  363.      * - calculate_md5: (bool) Set to false to disable calculating an MD5
  364.      *   for all Amazon S3 signed uploads.
  365.      * - s3_us_east_1_regional_endpoint:
  366.      *   (Aws\S3\RegionalEndpoint\ConfigurationInterface|Aws\CacheInterface\|callable|string|array)
  367.      *   Specifies whether to use regional or legacy endpoints for the us-east-1
  368.      *   region. Provide an Aws\S3\RegionalEndpoint\ConfigurationInterface object, an
  369.      *   instance of Aws\CacheInterface, a callable configuration provider used
  370.      *   to create endpoint configuration, a string value of `legacy` or
  371.      *   `regional`, or an associative array with the following keys:
  372.      *   endpoint_types: (string)  Set to `legacy` or `regional`, defaults to
  373.      *   `legacy`
  374.      * - use_accelerate_endpoint: (bool) Set to true to send requests to an S3
  375.      *   Accelerate endpoint by default. Can be enabled or disabled on
  376.      *   individual operations by setting '@use_accelerate_endpoint' to true or
  377.      *   false. Note: you must enable S3 Accelerate on a bucket before it can be
  378.      *   accessed via an Accelerate endpoint.
  379.      * - use_arn_region: (Aws\S3\UseArnRegion\ConfigurationInterface,
  380.      *   Aws\CacheInterface, bool, callable) Set to true to enable the client
  381.      *   to use the region from a supplied ARN argument instead of the client's
  382.      *   region. Provide an instance of Aws\S3\UseArnRegion\ConfigurationInterface,
  383.      *   an instance of Aws\CacheInterface, a callable that provides a promise for
  384.      *   a Configuration object, or a boolean value. Defaults to false (i.e.
  385.      *   the SDK will not follow the ARN region if it conflicts with the client
  386.      *   region and instead throw an error).
  387.      * - use_dual_stack_endpoint: (bool) Set to true to send requests to an S3
  388.      *   Dual Stack endpoint by default, which enables IPv6 Protocol.
  389.      *   Can be enabled or disabled on individual operations by setting
  390.      *   '@use_dual_stack_endpoint\' to true or false. Note:
  391.      *   you cannot use it together with an accelerate endpoint.
  392.      * - use_path_style_endpoint: (bool) Set to true to send requests to an S3
  393.      *   path style endpoint by default.
  394.      *   Can be enabled or disabled on individual operations by setting
  395.      *   '@use_path_style_endpoint\' to true or false. Note:
  396.      *   you cannot use it together with an accelerate endpoint.
  397.      * - disable_multiregion_access_points: (bool) Set to true to disable
  398.      *   sending multi region requests.  They are enabled by default.
  399.      *   Can be enabled or disabled on individual operations by setting
  400.      *   '@disable_multiregion_access_points\' to true or false. Note:
  401.      *   you cannot use it together with an accelerate or dualstack endpoint.
  402.      *
  403.      * @param array $args
  404.      */
  405.     public function __construct(array $args)
  406.     {
  407.         if (
  408.             !isset($args['s3_us_east_1_regional_endpoint'])
  409.             || $args['s3_us_east_1_regional_endpoint'] instanceof CacheInterface
  410.         ) {
  411.             $args['s3_us_east_1_regional_endpoint'] = ConfigurationProvider::defaultProvider($args);
  412.         }
  413.         $this->addBuiltIns($args);
  414.         parent::__construct($args);
  415.         $stack $this->getHandlerList();
  416.         $stack->appendInit(SSECMiddleware::wrap($this->getEndpoint()->getScheme()), 's3.ssec');
  417.         $stack->appendBuild(
  418.             ApplyChecksumMiddleware::wrap($this->getApi(), $this->getConfig()),
  419.             's3.checksum'
  420.         );
  421.         $stack->appendBuild(
  422.             Middleware::contentType(['PutObject''UploadPart']),
  423.             's3.content_type'
  424.         );
  425.         if ($this->getConfig('bucket_endpoint')) {
  426.             $stack->appendBuild(BucketEndpointMiddleware::wrap(), 's3.bucket_endpoint');
  427.         } elseif (!$this->isUseEndpointV2()) {
  428.             $stack->appendBuild(
  429.                 S3EndpointMiddleware::wrap(
  430.                     $this->getRegion(),
  431.                     $this->getConfig('endpoint_provider'),
  432.                     [
  433.                         'accelerate' => $this->getConfig('use_accelerate_endpoint'),
  434.                         'path_style' => $this->getConfig('use_path_style_endpoint'),
  435.                         'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'),
  436.                         'dual_stack' =>
  437.                             $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(),
  438.                     ]
  439.                 ),
  440.                 's3.endpoint_middleware'
  441.             );
  442.         }
  443.         $stack->appendBuild(
  444.             BucketEndpointArnMiddleware::wrap(
  445.                 $this->getApi(),
  446.                 $this->getRegion(),
  447.                 [
  448.                     'use_arn_region' => $this->getConfig('use_arn_region'),
  449.                     'accelerate' => $this->getConfig('use_accelerate_endpoint'),
  450.                     'path_style' => $this->getConfig('use_path_style_endpoint'),
  451.                     'dual_stack' =>
  452.                         $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(),
  453.                     'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'),
  454.                     'disable_multiregion_access_points' =>
  455.                         $this->getConfig('disable_multiregion_access_points'),
  456.                     'endpoint' => $args['endpoint'] ?? null
  457.                 ],
  458.                 $this->isUseEndpointV2()
  459.             ),
  460.             's3.bucket_endpoint_arn'
  461.         );
  462.         if ($this->getConfig('disable_express_session_auth')) {
  463.             $stack->prependSign(
  464.                 $this->getDisableExpressSessionAuthMiddleware(),
  465.                 's3.disable_express_session_auth'
  466.             );
  467.         }
  468.         $stack->appendValidate(
  469.             InputValidationMiddleware::wrap($this->getApi(), self::$mandatoryAttributes),
  470.             'input_validation_middleware'
  471.         );
  472.         $stack->appendSign(ExpiresParsingMiddleware::wrap(), 's3.expires_parsing');
  473.         $stack->appendSign(PutObjectUrlMiddleware::wrap(), 's3.put_object_url');
  474.         $stack->appendSign(PermanentRedirectMiddleware::wrap(), 's3.permanent_redirect');
  475.         $stack->appendInit(Middleware::sourceFile($this->getApi()), 's3.source_file');
  476.         $stack->appendInit($this->getSaveAsParameter(), 's3.save_as');
  477.         $stack->appendInit($this->getLocationConstraintMiddleware(), 's3.location');
  478.         $stack->appendInit($this->getEncodingTypeMiddleware(), 's3.auto_encode');
  479.         $stack->appendInit($this->getHeadObjectMiddleware(), 's3.head_object');
  480.         $this->processModel($this->isUseEndpointV2());
  481.         if ($this->isUseEndpointV2()) {
  482.             $stack->after('builder',
  483.                 's3.check_empty_path_with_query',
  484.                 $this->getEmptyPathWithQuery());
  485.         }
  486.     }
  487.     /**
  488.      * Determine if a string is a valid name for a DNS compatible Amazon S3
  489.      * bucket.
  490.      *
  491.      * DNS compatible bucket names can be used as a subdomain in a URL (e.g.,
  492.      * "<bucket>.s3.amazonaws.com").
  493.      *
  494.      * @param string $bucket Bucket name to check.
  495.      *
  496.      * @return bool
  497.      */
  498.     public static function isBucketDnsCompatible($bucket)
  499.     {
  500.         if (!is_string($bucket)) {
  501.             return false;
  502.         }
  503.         $bucketLen strlen($bucket);
  504.         return ($bucketLen >= && $bucketLen <= 63) &&
  505.             // Cannot look like an IP address
  506.             !filter_var($bucketFILTER_VALIDATE_IP) &&
  507.             preg_match('/^[a-z0-9]([a-z0-9\-\.]*[a-z0-9])?$/'$bucket);
  508.     }
  509.     public static function _apply_use_arn_region($value, array &$argsHandlerList $list)
  510.     {
  511.         if ($value instanceof CacheInterface) {
  512.             $value UseArnRegionConfigurationProvider::defaultProvider($args);
  513.         }
  514.         if (is_callable($value)) {
  515.             $value $value();
  516.         }
  517.         if ($value instanceof PromiseInterface) {
  518.             $value $value->wait();
  519.         }
  520.         if ($value instanceof ConfigurationInterface) {
  521.             $args['use_arn_region'] = $value;
  522.         } else {
  523.             // The Configuration class itself will validate other inputs
  524.             $args['use_arn_region'] = new Configuration($value);
  525.         }
  526.     }
  527.     public static function _default_request_checksum_calculation(array $args): string
  528.     {
  529.         return ConfigurationResolver::resolve(
  530.             'request_checksum_calculation',
  531.             ApplyChecksumMiddleware::DEFAULT_CALCULATION_MODE,
  532.             'string',
  533.             $args
  534.         );
  535.     }
  536.     public static function _apply_request_checksum_calculation(
  537.         string $value,
  538.         array &$args
  539.     ): void
  540.     {
  541.         $value strtolower($value);
  542.         if (array_key_exists($valueself::$checksumOptionEnum)) {
  543.             $args['request_checksum_calculation'] = $value;
  544.         } else {
  545.             $validValues implode(' | 'array_keys(self::$checksumOptionEnum));
  546.             throw new \InvalidArgumentException(
  547.                 'invalid value provided for `request_checksum_calculation`.'
  548.                 ' valid values are: ' $validValues '.'
  549.             );
  550.         }
  551.     }
  552.     public static function _default_response_checksum_validation(array $args): string
  553.     {
  554.         return ConfigurationResolver::resolve(
  555.             'response_checksum_validation',
  556.             ValidateResponseChecksumResultMutator::DEFAULT_VALIDATION_MODE,
  557.             'string',
  558.             $args
  559.         );
  560.     }
  561.     public static function _apply_response_checksum_validation(
  562.         $value,
  563.         array &$args
  564.     ): void
  565.     {
  566.         $value strtolower($value);
  567.         if (array_key_exists($valueself::$checksumOptionEnum)) {
  568.             $args['request_checksum_calculation'] = $value;
  569.         } else {
  570.             $validValues implode(' | 'array_keys(self::$checksumOptionEnum));
  571.             throw new \InvalidArgumentException(
  572.                 'invalid value provided for `request_checksum_calculation`.'
  573.                 ' valid values are: ' $validValues '.'
  574.             );
  575.         }
  576.     }
  577.     public static function _default_disable_express_session_auth(array &$args)
  578.     {
  579.         return ConfigurationResolver::resolve(
  580.             's3_disable_express_session_auth',
  581.             false,
  582.             'bool',
  583.             $args
  584.         );
  585.     }
  586.     public static function _default_s3_express_identity_provider(array $args)
  587.     {
  588.         if ($args['config']['disable_express_session_auth']) {
  589.             return false;
  590.         }
  591.         return new S3ExpressIdentityProvider($args['region']);
  592.     }
  593.     public function createPresignedRequest(CommandInterface $command$expires, array $options = [])
  594.     {
  595.         $command = clone $command;
  596.         $list $command->getHandlerList();
  597.         $list->remove('signer');
  598.         //Removes checksum calculation behavior by default
  599.         if (empty($command['ChecksumAlgorithm'])
  600.             && empty($command['AddContentMD5'])
  601.         ) {
  602.             $list->remove('s3.checksum');
  603.         }
  604.         $request \Aws\serialize($command);
  605.         //Applies ContentSHA256 parameter, if provided and not applied
  606.         // by middleware
  607.         $commandName $command->getName();
  608.         if (!empty($command['ContentSHA256']
  609.             && isset(ApplyChecksumMiddleware::$sha256[$commandName])
  610.             && !$request->hasHeader('X-Amz-Content-Sha256')
  611.         )) {
  612.             $request $request->withHeader(
  613.                 'X-Amz-Content-Sha256',
  614.                 $command['ContentSHA256']
  615.             );
  616.         }
  617.         $signing_name $command['@context']['signing_service']
  618.             ?? $this->getSigningName($request->getUri()->getHost());
  619.         $signature_version $this->getSignatureVersionFromCommand($command);
  620.         /** @var \Aws\Signature\SignatureInterface $signer */
  621.         $signer call_user_func(
  622.             $this->getSignatureProvider(),
  623.             $signature_version,
  624.             $signing_name,
  625.             $this->getConfig('signing_region')
  626.         );
  627.         if ($signature_version == 'v4-s3express') {
  628.             $provider $this->getConfig('s3_express_identity_provider');
  629.             $credentials $provider($command)->wait();
  630.         } else {
  631.             $credentials $this->getCredentials()->wait();
  632.         }
  633.         return $signer->presign(
  634.             $request,
  635.             $credentials,
  636.             $expires,
  637.             $options
  638.         );
  639.     }
  640.     /**
  641.      * Returns the URL to an object identified by its bucket and key.
  642.      *
  643.      * The URL returned by this method is not signed nor does it ensure that the
  644.      * bucket and key given to the method exist. If you need a signed URL, then
  645.      * use the {@see \Aws\S3\S3Client::createPresignedRequest} method and get
  646.      * the URI of the signed request.
  647.      *
  648.      * @param string $bucket  The name of the bucket where the object is located
  649.      * @param string $key     The key of the object
  650.      *
  651.      * @return string The URL to the object
  652.      */
  653.     public function getObjectUrl($bucket$key)
  654.     {
  655.         $command $this->getCommand('GetObject', [
  656.             'Bucket' => $bucket,
  657.             'Key'    => $key
  658.         ]);
  659.         return (string) \Aws\serialize($command)->getUri();
  660.     }
  661.     /**
  662.      * Raw URL encode a key and allow for '/' characters
  663.      *
  664.      * @param string $key Key to encode
  665.      *
  666.      * @return string Returns the encoded key
  667.      */
  668.     public static function encodeKey($key)
  669.     {
  670.         return str_replace('%2F''/'rawurlencode($key));
  671.     }
  672.     /**
  673.      * Provides a middleware that removes the need to specify LocationConstraint on CreateBucket.
  674.      *
  675.      * @return \Closure
  676.      */
  677.     private function getLocationConstraintMiddleware()
  678.     {
  679.         $region $this->getRegion();
  680.         return static function (callable $handler) use ($region) {
  681.             return function (Command $command$request null) use ($handler$region) {
  682.                 if ($command->getName() === 'CreateBucket'
  683.                     && !self::isDirectoryBucket($command['Bucket'])
  684.                 ) {
  685.                     $locationConstraint $command['CreateBucketConfiguration']['LocationConstraint']
  686.                         ?? null;
  687.                     if ($locationConstraint === 'us-east-1') {
  688.                         unset($command['CreateBucketConfiguration']);
  689.                     } elseif ('us-east-1' !== $region && empty($locationConstraint)) {
  690.                         if (isset($command['CreateBucketConfiguration'])) {
  691.                             $command['CreateBucketConfiguration']['LocationConstraint'] = $region;
  692.                         } else {
  693.                             $command['CreateBucketConfiguration'] = ['LocationConstraint' => $region];
  694.                         }
  695.                     }
  696.                 }
  697.                 return $handler($command$request);
  698.             };
  699.         };
  700.     }
  701.     /**
  702.      * Provides a middleware that supports the `SaveAs` parameter.
  703.      *
  704.      * @return \Closure
  705.      */
  706.     private function getSaveAsParameter()
  707.     {
  708.         return static function (callable $handler) {
  709.             return function (Command $command$request null) use ($handler) {
  710.                 if ($command->getName() === 'GetObject' && isset($command['SaveAs'])) {
  711.                     $command['@http']['sink'] = $command['SaveAs'];
  712.                     unset($command['SaveAs']);
  713.                 }
  714.                 return $handler($command$request);
  715.             };
  716.         };
  717.     }
  718.     /**
  719.      * Provides a middleware that disables content decoding on HeadObject
  720.      * commands.
  721.      *
  722.      * @return \Closure
  723.      */
  724.     private function getHeadObjectMiddleware()
  725.     {
  726.         return static function (callable $handler) {
  727.             return function (
  728.                 CommandInterface $command,
  729.                 ?RequestInterface $request null
  730.             ) use ($handler) {
  731.                 if ($command->getName() === 'HeadObject'
  732.                     && !isset($command['@http']['decode_content'])
  733.                 ) {
  734.                     $command['@http']['decode_content'] = false;
  735.                 }
  736.                 return $handler($command$request);
  737.             };
  738.         };
  739.     }
  740.     /**
  741.      * Provides a middleware that autopopulates the EncodingType parameter on
  742.      * ListObjects commands.
  743.      *
  744.      * @return \Closure
  745.      */
  746.     private function getEncodingTypeMiddleware()
  747.     {
  748.         return static function (callable $handler) {
  749.             return function (Command $command$request null) use ($handler) {
  750.                 $autoSet false;
  751.                 if ($command->getName() === 'ListObjects'
  752.                     && empty($command['EncodingType'])
  753.                 ) {
  754.                     $command['EncodingType'] = 'url';
  755.                     $autoSet true;
  756.                 }
  757.                 return $handler($command$request)
  758.                     ->then(function (ResultInterface $result) use ($autoSet) {
  759.                         if ($result['EncodingType'] === 'url' && $autoSet) {
  760.                             static $topLevel = [
  761.                                 'Delimiter',
  762.                                 'Marker',
  763.                                 'NextMarker',
  764.                                 'Prefix',
  765.                             ];
  766.                             static $nested = [
  767.                                 ['Contents''Key'],
  768.                                 ['CommonPrefixes''Prefix'],
  769.                             ];
  770.                             foreach ($topLevel as $key) {
  771.                                 if (isset($result[$key])) {
  772.                                     $result[$key] = urldecode($result[$key]);
  773.                                 }
  774.                             }
  775.                             foreach ($nested as $steps) {
  776.                                 if (isset($result[$steps[0]])) {
  777.                                     foreach ($result[$steps[0]] as $key => $part) {
  778.                                         if (isset($part[$steps[1]])) {
  779.                                             $result[$steps[0]][$key][$steps[1]]
  780.                                                 = urldecode($part[$steps[1]]);
  781.                                         }
  782.                                     }
  783.                                 }
  784.                             }
  785.                         }
  786.                         return $result;
  787.                     });
  788.             };
  789.         };
  790.     }
  791.     /**
  792.      * Provides a middleware that checks for an empty path and a
  793.      * non-empty query string.
  794.      *
  795.      * @return \Closure
  796.      */
  797.     private function getEmptyPathWithQuery()
  798.     {
  799.         return static function (callable $handler) {
  800.             return function (Command $commandRequestInterface $request) use ($handler) {
  801.                 $uri $request->getUri();
  802.                 if (empty($uri->getPath()) && !empty($uri->getQuery())) {
  803.                     $uri $uri->withPath('/');
  804.                     $request $request->withUri($uri);
  805.                 }
  806.                 return $handler($command$request);
  807.             };
  808.         };
  809.     }
  810.     /**
  811.      * Provides a middleware that disables express session auth when
  812.      * customers opt out of it.
  813.      *
  814.      * @return \Closure
  815.      */
  816.     private function getDisableExpressSessionAuthMiddleware()
  817.     {
  818.         return function (callable $handler) {
  819.             return function (
  820.                 CommandInterface $command,
  821.                 ?RequestInterface $request null
  822.             ) use ($handler) {
  823.                 if (!empty($command['@context']['signature_version'])
  824.                     && $command['@context']['signature_version'] === 'v4-s3express'
  825.                 ) {
  826.                     $command['@context']['signature_version'] = 's3v4';
  827.                 }
  828.                 return $handler($command$request);
  829.             };
  830.         };
  831.     }
  832.     /**
  833.      * Special handling for when the service name is s3-object-lambda.
  834.      * So, if the host contains s3-object-lambda, then the service name
  835.      * returned is s3-object-lambda, otherwise the default signing service is returned.
  836.      * @param string $host The host to validate if is a s3-object-lambda URL.
  837.      * @return string returns the signing service name to be used
  838.      */
  839.     private function getSigningName($host)
  840.     {
  841.         if (strpos$host's3-object-lambda')) {
  842.             return 's3-object-lambda';
  843.         }
  844.         return $this->getConfig('signing_name');
  845.     }
  846.     /**
  847.      * If EndpointProviderV2 is used, removes `Bucket` from request URIs.
  848.      * This is now handled by the endpoint ruleset.
  849.      *
  850.      * Additionally adds a synthetic shape `ExpiresString` and modifies
  851.      * `Expires` type to ensure it remains set to `timestamp`.
  852.      *
  853.      * @param array $args
  854.      * @return void
  855.      *
  856.      * @internal
  857.      */
  858.     private function processModel(bool $isUseEndpointV2): void
  859.     {
  860.         $definition $this->getApi()->getDefinition();
  861.         if ($isUseEndpointV2) {
  862.             foreach($definition['operations'] as &$operation) {
  863.                 if (isset($operation['http']['requestUri'])) {
  864.                     $requestUri $operation['http']['requestUri'];
  865.                     if ($requestUri === "/{Bucket}") {
  866.                         $requestUri str_replace('/{Bucket}''/'$requestUri);
  867.                     } else {
  868.                         $requestUri str_replace('/{Bucket}'''$requestUri);
  869.                     }
  870.                     $operation['http']['requestUri'] = $requestUri;
  871.                 }
  872.             }
  873.         }
  874.         foreach ($definition['shapes'] as $key => &$value) {
  875.             $suffix 'Output';
  876.             if (substr($key, -strlen($suffix)) === $suffix) {
  877.                 if (isset($value['members']['Expires'])) {
  878.                     $value['members']['Expires']['deprecated'] = true;
  879.                     $value['members']['ExpiresString'] = [
  880.                         'shape' => 'ExpiresString',
  881.                         'location' => 'header',
  882.                         'locationName' => 'Expires'
  883.                     ];
  884.                 }
  885.             }
  886.         }
  887.         $definition['shapes']['ExpiresString']['type'] = 'string';
  888.         $definition['shapes']['Expires']['type'] = 'timestamp';
  889.         $this->getApi()->setDefinition($definition);
  890.     }
  891.     /**
  892.      * Adds service-specific client built-in values
  893.      *
  894.      * @return void
  895.      */
  896.     private function addBuiltIns($args)
  897.     {
  898.         if (isset($args['region'])
  899.             && $args['region'] !== 'us-east-1'
  900.         ) {
  901.             return false;
  902.         }
  903.         if (!isset($args['region'])
  904.             && ConfigurationResolver::resolve('region''''string') !== 'us-east-1'
  905.         ) {
  906.             return false;
  907.         }
  908.         $key 'AWS::S3::UseGlobalEndpoint';
  909.         $result $args['s3_us_east_1_regional_endpoint'] instanceof \Closure ?
  910.             $args['s3_us_east_1_regional_endpoint']()->wait() : $args['s3_us_east_1_regional_endpoint'];
  911.         if (is_string($result)) {
  912.             if ($result === 'regional') {
  913.                 $value false;
  914.             } else if ($result === 'legacy') {
  915.                 $value true;
  916.             } else {
  917.                 return;
  918.             }
  919.         } else {
  920.             if ($result->isFallback()
  921.                 || $result->getEndpointsType() === 'legacy'
  922.             ) {
  923.                 $value true;
  924.             } else {
  925.                 $value false;
  926.             }
  927.         }
  928.         $this->clientBuiltIns[$key] = $value;
  929.     }
  930.     /**
  931.      * Determines whether a bucket is a directory bucket.
  932.      * Only considers the availability zone/suffix format
  933.      *
  934.      * @param string $bucket
  935.      * @return bool
  936.      */
  937.     public static function isDirectoryBucket(string $bucket): bool
  938.     {
  939.         return preg_match(self::DIRECTORY_BUCKET_REGEX$bucket) === 1;
  940.     }
  941.     /** @internal */
  942.     public static function _applyRetryConfig($value$argsHandlerList $list)
  943.     {
  944.         if ($value) {
  945.             $config \Aws\Retry\ConfigurationProvider::unwrap($value);
  946.             if ($config->getMode() === 'legacy') {
  947.                 $maxRetries $config->getMaxAttempts() - 1;
  948.                 $decider RetryMiddleware::createDefaultDecider($maxRetries);
  949.                 $decider = function ($retries$command$request$result$error) use ($decider$maxRetries) {
  950.                     $maxRetries $command['@retries'] ?? $maxRetries;
  951.                     if ($decider($retries$command$request$result$error)) {
  952.                         return true;
  953.                     }
  954.                     if ($error instanceof AwsException
  955.                         && $retries $maxRetries
  956.                     ) {
  957.                         if ($error->getResponse()
  958.                             && $error->getResponse()->getStatusCode() >= 400
  959.                         ) {
  960.                             return strpos(
  961.                                     $error->getResponse()->getBody(),
  962.                                     'Your socket connection to the server'
  963.                                 ) !== false;
  964.                         }
  965.                         if ($error->getPrevious() instanceof RequestException) {
  966.                             // All commands except CompleteMultipartUpload are
  967.                             // idempotent and may be retried without worry if a
  968.                             // networking error has occurred.
  969.                             return $command->getName() !== 'CompleteMultipartUpload';
  970.                         }
  971.                     }
  972.                     return false;
  973.                 };
  974.                 $delay = [RetryMiddleware::class, 'exponentialDelay'];
  975.                 $list->appendSign(Middleware::retry($decider$delay), 'retry');
  976.             } else {
  977.                 $defaultDecider RetryMiddlewareV2::createDefaultDecider(
  978.                     new QuotaManager(),
  979.                     $config->getMaxAttempts()
  980.                 );
  981.                 $list->appendSign(
  982.                     RetryMiddlewareV2::wrap(
  983.                         $config,
  984.                         [
  985.                             'collect_stats' => $args['stats']['retries'],
  986.                             'decider' => function(
  987.                                 $attempts,
  988.                                 CommandInterface $cmd,
  989.                                 $result
  990.                             ) use ($defaultDecider$config) {
  991.                                 $isRetryable $defaultDecider($attempts$cmd$result);
  992.                                 if (!$isRetryable
  993.                                     && $result instanceof AwsException
  994.                                     && $attempts $config->getMaxAttempts()
  995.                                 ) {
  996.                                     if (!empty($result->getResponse())
  997.                                         && $result->getResponse()->getStatusCode() >= 400
  998.                                     ) {
  999.                                         return strpos(
  1000.                                                 $result->getResponse()->getBody(),
  1001.                                                 'Your socket connection to the server'
  1002.                                             ) !== false;
  1003.                                     }
  1004.                                     if ($result->getPrevious() instanceof RequestException
  1005.                                         && $cmd->getName() !== 'CompleteMultipartUpload'
  1006.                                     ) {
  1007.                                         $isRetryable true;
  1008.                                     }
  1009.                                 }
  1010.                                 return $isRetryable;
  1011.                             }
  1012.                         ]
  1013.                     ),
  1014.                     'retry'
  1015.                 );
  1016.             }
  1017.         }
  1018.     }
  1019.     /** @internal */
  1020.     public static function _applyApiProvider($value, array &$argsHandlerList $list)
  1021.     {
  1022.         ClientResolver::_apply_api_provider($value$args);
  1023.         $s3Parser = new S3Parser(
  1024.             $args['parser'],
  1025.             $args['error_parser'],
  1026.             $args['api'],
  1027.             $args['exception_class']
  1028.         );
  1029.         $s3Parser->addS3ResultMutator(
  1030.             'get-bucket-location',
  1031.             new GetBucketLocationResultMutator()
  1032.         );
  1033.         $s3Parser->addS3ResultMutator(
  1034.             'validate-response-checksum',
  1035.             new ValidateResponseChecksumResultMutator(
  1036.                 $args['api'],
  1037.                 ['response_checksum_validation' => $args['response_checksum_validation']]
  1038.             )
  1039.         );
  1040.         $args['parser'] = $s3Parser;
  1041.     }
  1042.     /**
  1043.      * @internal
  1044.      * @codeCoverageIgnore
  1045.      */
  1046.     public static function applyDocFilters(array $api, array $docs)
  1047.     {
  1048.         $b64 '<div class="alert alert-info">This value will be base64 encoded on your behalf.</div>';
  1049.         $opt '<div class="alert alert-info">This value will be computed for you it is not supplied.</div>';
  1050.         // Add a note on the CopyObject docs
  1051.          $s3ExceptionRetryMessage "<p>Additional info on response behavior: if there is"
  1052.             " an internal error in S3 after the request was successfully recieved,"
  1053.             " a 200 response will be returned with an <code>S3Exception</code> embedded"
  1054.             " in it; this will still be caught and retried by"
  1055.             " <code>RetryMiddleware.</code></p>";
  1056.         $docs['operations']['CopyObject'] .=  $s3ExceptionRetryMessage;
  1057.         $docs['operations']['CompleteMultipartUpload'] .=  $s3ExceptionRetryMessage;
  1058.         $docs['operations']['UploadPartCopy'] .=  $s3ExceptionRetryMessage;
  1059.         $docs['operations']['UploadPart'] .=  $s3ExceptionRetryMessage;
  1060.         // Add note about stream ownership in the putObject call
  1061.         $guzzleStreamMessage "<p>Additional info on behavior of the stream"
  1062.             " parameters: Psr7 takes ownership of streams and will automatically close"
  1063.             " streams when this method is called with a stream as the <code>Body</code>"
  1064.             " parameter.  To prevent this, set the <code>Body</code> using"
  1065.             " <code>GuzzleHttp\Psr7\stream_for</code> method with a is an instance of"
  1066.             " <code>Psr\Http\Message\StreamInterface</code>, and it will be returned"
  1067.             " unmodified. This will allow you to keep the stream in scope. </p>";
  1068.         $docs['operations']['PutObject'] .=  $guzzleStreamMessage;
  1069.         // Add the SourceFile parameter.
  1070.         $docs['shapes']['SourceFile']['base'] = 'The path to a file on disk to use instead of the Body parameter.';
  1071.         $api['shapes']['SourceFile'] = ['type' => 'string'];
  1072.         $api['shapes']['PutObjectRequest']['members']['SourceFile'] = ['shape' => 'SourceFile'];
  1073.         $api['shapes']['UploadPartRequest']['members']['SourceFile'] = ['shape' => 'SourceFile'];
  1074.         // Add the ContentSHA256 parameter.
  1075.         $docs['shapes']['ContentSHA256']['base'] = 'A SHA256 hash of the body content of the request.';
  1076.         $api['shapes']['ContentSHA256'] = ['type' => 'string'];
  1077.         $api['shapes']['PutObjectRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256'];
  1078.         $api['shapes']['UploadPartRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256'];
  1079.         $docs['shapes']['ContentSHA256']['append'] = $opt;
  1080.         // Add the AddContentMD5 parameter.
  1081.         $docs['shapes']['AddContentMD5']['base'] = 'Set to true to calculate the ContentMD5 for the upload.';
  1082.         $api['shapes']['AddContentMD5'] = ['type' => 'boolean'];
  1083.         $api['shapes']['PutObjectRequest']['members']['AddContentMD5'] = ['shape' => 'AddContentMD5'];
  1084.         $api['shapes']['UploadPartRequest']['members']['AddContentMD5'] = ['shape' => 'AddContentMD5'];
  1085.         // Add the SaveAs parameter.
  1086.         $docs['shapes']['SaveAs']['base'] = 'The path to a file on disk to save the object data.';
  1087.         $api['shapes']['SaveAs'] = ['type' => 'string'];
  1088.         $api['shapes']['GetObjectRequest']['members']['SaveAs'] = ['shape' => 'SaveAs'];
  1089.         // Several SSECustomerKey documentation updates.
  1090.         $docs['shapes']['SSECustomerKey']['append'] = $b64;
  1091.         $docs['shapes']['CopySourceSSECustomerKey']['append'] = $b64;
  1092.         $docs['shapes']['SSECustomerKeyMd5']['append'] = $opt;
  1093.         // Add the ObjectURL to various output shapes and documentation.
  1094.         $docs['shapes']['ObjectURL']['base'] = 'The URI of the created object.';
  1095.         $api['shapes']['ObjectURL'] = ['type' => 'string'];
  1096.         $api['shapes']['PutObjectOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL'];
  1097.         $api['shapes']['CopyObjectOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL'];
  1098.         $api['shapes']['CompleteMultipartUploadOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL'];
  1099.         // Fix references to Location Constraint.
  1100.         unset($api['shapes']['CreateBucketRequest']['payload']);
  1101.         $api['shapes']['BucketLocationConstraint']['enum'] = [
  1102.             "ap-northeast-1",
  1103.             "ap-southeast-2",
  1104.             "ap-southeast-1",
  1105.             "cn-north-1",
  1106.             "eu-central-1",
  1107.             "eu-west-1",
  1108.             "us-east-1",
  1109.             "us-west-1",
  1110.             "us-west-2",
  1111.             "sa-east-1",
  1112.         ];
  1113.         // Add a note that the ContentMD5 is automatically computed, except for with PutObject and UploadPart
  1114.         $docs['shapes']['ContentMD5']['append'] = '<div class="alert alert-info">The value will be computed on '
  1115.             'your behalf.</div>';
  1116.         $docs['shapes']['ContentMD5']['excludeAppend'] = ['PutObjectRequest''UploadPartRequest'];
  1117.         //Add a note to ContentMD5 for PutObject and UploadPart that specifies the value is required
  1118.         // When uploading to a bucket with object lock enabled and that it is not computed automatically
  1119.         $objectLock '<div class="alert alert-info">This value is required if uploading to a bucket '
  1120.             'which has Object Lock enabled. It will not be calculated for you automatically. If you wish to have '
  1121.             'the value calculated for you, use the `AddContentMD5` parameter.</div>';
  1122.         $docs['shapes']['ContentMD5']['appendOnly'] = [
  1123.             'message' => $objectLock,
  1124.             'shapes' => ['PutObjectRequest''UploadPartRequest']
  1125.         ];
  1126.         // Add `ExpiresString` shape to output structures which contain `Expires`
  1127.         // Deprecate existing `Expires` shapes in output structures
  1128.         // Add/Update documentation for both `ExpiresString` and `Expires`
  1129.         // Ensure `Expires` type remains timestamp
  1130.         foreach ($api['shapes'] as $key => &$value) {
  1131.             $suffix 'Output';
  1132.             if (substr($key, -strlen($suffix)) === $suffix) {
  1133.                 if (isset($value['members']['Expires'])) {
  1134.                     $value['members']['Expires']['deprecated'] = true;
  1135.                     $value['members']['ExpiresString'] = [
  1136.                         'shape' => 'ExpiresString',
  1137.                         'location' => 'header',
  1138.                         'locationName' => 'Expires'
  1139.                     ];
  1140.                     $docs['shapes']['Expires']['refs'][$key '$Expires']
  1141.                         .= '<p>This output shape has been deprecated. Please refer to <code>ExpiresString</code> instead.</p>.';
  1142.                 }
  1143.             }
  1144.         }
  1145.         $api['shapes']['ExpiresString']['type'] = 'string';
  1146.         $docs['shapes']['ExpiresString']['base'] = 'The unparsed string value of the <code>Expires</code> output member.';
  1147.         $api['shapes']['Expires']['type'] = 'timestamp';
  1148.         return [
  1149.             new Service($apiApiProvider::defaultProvider()),
  1150.             new DocModel($docs)
  1151.         ];
  1152.     }
  1153.     /**
  1154.      * @internal
  1155.      * @codeCoverageIgnore
  1156.      */
  1157.     public static function addDocExamples($examples)
  1158.     {
  1159.         $getObjectExample = [
  1160.             'input' => [
  1161.                 'Bucket' => 'arn:aws:s3:us-east-1:123456789012:accesspoint:myaccesspoint',
  1162.                 'Key' => 'my-key'
  1163.             ],
  1164.             'output' => [
  1165.                 'Body' => 'class GuzzleHttp\Psr7\Stream#208 (7) {...}',
  1166.                 'ContentLength' => '11',
  1167.                 'ContentType' => 'application/octet-stream',
  1168.             ],
  1169.             'comments' => [
  1170.                 'input' => '',
  1171.                 'output' => 'Simplified example output'
  1172.             ],
  1173.             'description' => 'The following example retrieves an object by referencing the bucket via an S3 accesss point ARN. Result output is simplified for the example.',
  1174.             'id' => '',
  1175.             'title' => 'To get an object via an S3 access point ARN'
  1176.         ];
  1177.         if (isset($examples['GetObject'])) {
  1178.             $examples['GetObject'] []= $getObjectExample;
  1179.         } else {
  1180.             $examples['GetObject'] = [$getObjectExample];
  1181.         }
  1182.         $putObjectExample = [
  1183.             'input' => [
  1184.                 'Bucket' => 'arn:aws:s3:us-east-1:123456789012:accesspoint:myaccesspoint',
  1185.                 'Key' => 'my-key',
  1186.                 'Body' => 'my-body',
  1187.             ],
  1188.             'output' => [
  1189.                 'ObjectURL' => 'https://my-bucket.s3.us-east-1.amazonaws.com/my-key'
  1190.             ],
  1191.             'comments' => [
  1192.                 'input' => '',
  1193.                 'output' => 'Simplified example output'
  1194.             ],
  1195.             'description' => 'The following example uploads an object by referencing the bucket via an S3 accesss point ARN. Result output is simplified for the example.',
  1196.             'id' => '',
  1197.             'title' => 'To upload an object via an S3 access point ARN'
  1198.         ];
  1199.         if (isset($examples['PutObject'])) {
  1200.             $examples['PutObject'] []= $putObjectExample;
  1201.         } else {
  1202.             $examples['PutObject'] = [$putObjectExample];
  1203.         }
  1204.         return $examples;
  1205.     }
  1206.     /**
  1207.      * @param CommandInterface $command
  1208.      * @return array|mixed|null
  1209.      */
  1210.     private function getSignatureVersionFromCommand(CommandInterface $command)
  1211.     {
  1212.         return $command['@context']['signature_version']
  1213.             ?? $this->getConfig('signature_version');
  1214.     }
  1215. }