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

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