diff options
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php')
-rw-r--r-- | vendor/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php b/vendor/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php new file mode 100644 index 0000000..c8dd007 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php @@ -0,0 +1,343 @@ +<?php +namespace Aws\S3; + +use Aws\Arn\ArnParser; +use Aws\Arn\ObjectLambdaAccessPointArn; +use Aws\ClientResolver; +use Aws\CommandInterface; +use Aws\Endpoint\EndpointProvider; +use Aws\Endpoint\PartitionEndpointProvider; +use GuzzleHttp\Exception\InvalidArgumentException; +use GuzzleHttp\Psr7\Uri; +use Psr\Http\Message\RequestInterface; + +/** + * Used to update the URL used for S3 requests to support: + * S3 Accelerate, S3 DualStack or Both. It will build to + * host style paths unless specified, including for S3 + * DualStack. + * + * IMPORTANT: this middleware must be added after the "build" step. + * + * @internal + */ +class S3EndpointMiddleware +{ + private static $exclusions = [ + 'CreateBucket' => true, + 'DeleteBucket' => true, + 'ListBuckets' => true, + ]; + + const NO_PATTERN = 0; + const DUALSTACK = 1; + const ACCELERATE = 2; + const ACCELERATE_DUALSTACK = 3; + const PATH_STYLE = 4; + const HOST_STYLE = 5; + + /** @var bool */ + private $accelerateByDefault; + /** @var bool */ + private $dualStackByDefault; + /** @var bool */ + private $pathStyleByDefault; + /** @var string */ + private $region; + /** @var callable */ + private $endpointProvider; + /** @var callable */ + private $nextHandler; + /** @var string */ + private $endpoint; + + /** + * Create a middleware wrapper function + * + * @param string $region + * @param EndpointProvider $endpointProvider + * @param array $options + * + * @return callable + */ + public static function wrap($region, $endpointProvider, array $options) + { + return function (callable $handler) use ($region, $endpointProvider, $options) { + return new self($handler, $region, $options, $endpointProvider); + }; + } + + public function __construct( + callable $nextHandler, + $region, + array $options, + $endpointProvider = null + ) { + $this->pathStyleByDefault = isset($options['path_style']) + ? (bool) $options['path_style'] : false; + $this->dualStackByDefault = isset($options['dual_stack']) + ? (bool) $options['dual_stack'] : false; + $this->accelerateByDefault = isset($options['accelerate']) + ? (bool) $options['accelerate'] : false; + $this->region = (string) $region; + $this->endpoint = isset($options['endpoint']) + ? $options['endpoint'] : ""; + $this->endpointProvider = is_null($endpointProvider) + ? PartitionEndpointProvider::defaultProvider() + : $endpointProvider; + $this->nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $command, RequestInterface $request) + { + if (!empty($this->endpoint)) { + $request = $this->applyEndpoint($command, $request); + } else { + switch ($this->endpointPatternDecider($command, $request)) { + case self::HOST_STYLE: + $request = $this->applyHostStyleEndpoint($command, $request); + break; + case self::NO_PATTERN: + break; + case self::PATH_STYLE: + $request = $this->applyPathStyleEndpointCustomizations($command, $request); + break; + case self::DUALSTACK: + $request = $this->applyDualStackEndpoint($command, $request); + break; + case self::ACCELERATE: + $request = $this->applyAccelerateEndpoint( + $command, + $request, + 's3-accelerate' + ); + break; + case self::ACCELERATE_DUALSTACK: + $request = $this->applyAccelerateEndpoint( + $command, + $request, + 's3-accelerate.dualstack' + ); + break; + } + } + $nextHandler = $this->nextHandler; + return $nextHandler($command, $request); + } + + private static function isRequestHostStyleCompatible( + CommandInterface $command, + RequestInterface $request + ) { + return S3Client::isBucketDnsCompatible($command['Bucket']) + && ( + $request->getUri()->getScheme() === 'http' + || strpos($command['Bucket'], '.') === false + ) + && filter_var($request->getUri()->getHost(), FILTER_VALIDATE_IP) === false; + } + + private function endpointPatternDecider( + CommandInterface $command, + RequestInterface $request + ) { + $accelerate = isset($command['@use_accelerate_endpoint']) + ? $command['@use_accelerate_endpoint'] : $this->accelerateByDefault; + $dualStack = isset($command['@use_dual_stack_endpoint']) + ? $command['@use_dual_stack_endpoint'] : $this->dualStackByDefault; + $pathStyle = isset($command['@use_path_style_endpoint']) + ? $command['@use_path_style_endpoint'] : $this->pathStyleByDefault; + + if ($accelerate && $dualStack) { + // When try to enable both for operations excluded from s3-accelerate, + // only dualstack endpoints will be enabled. + return $this->canAccelerate($command) + ? self::ACCELERATE_DUALSTACK + : self::DUALSTACK; + } + + if ($accelerate && $this->canAccelerate($command)) { + return self::ACCELERATE; + } + + if ($dualStack) { + return self::DUALSTACK; + } + + if (!$pathStyle + && self::isRequestHostStyleCompatible($command, $request) + ) { + return self::HOST_STYLE; + } + + return self::PATH_STYLE; + } + + private function canAccelerate(CommandInterface $command) + { + return empty(self::$exclusions[$command->getName()]) + && S3Client::isBucketDnsCompatible($command['Bucket']); + } + + private function getBucketStyleHost(CommandInterface $command, $host) + { + // For operations on the base host (e.g. ListBuckets) + if (!isset($command['Bucket'])) { + return $host; + } + + return "{$command['Bucket']}.{$host}"; + } + + private function applyHostStyleEndpoint( + CommandInterface $command, + RequestInterface $request + ) { + $uri = $request->getUri(); + $request = $request->withUri( + $uri->withHost($this->getBucketStyleHost( + $command, + $uri->getHost() + )) + ->withPath($this->getBucketlessPath( + $uri->getPath(), + $command + )) + ); + return $request; + } + + private function applyPathStyleEndpointCustomizations( + CommandInterface $command, + RequestInterface $request + ) { + if ($command->getName() == 'WriteGetObjectResponse') { + $dnsSuffix = $this->endpointProvider + ->getPartition($this->region, 's3') + ->getDnsSuffix(); + $fips = \Aws\is_fips_pseudo_region($this->region) ? "-fips" : ""; + $region = \Aws\strip_fips_pseudo_regions($this->region); + $host = + "{$command['RequestRoute']}.s3-object-lambda{$fips}.{$region}.{$dnsSuffix}"; + + $uri = $request->getUri(); + $request = $request->withUri( + $uri->withHost($host) + ->withPath($this->getBucketlessPath( + $uri->getPath(), + $command + )) + ); + } + return $request; + } + + + private function applyDualStackEndpoint( + CommandInterface $command, + RequestInterface $request + ) { + $request = $request->withUri( + $request->getUri()->withHost($this->getDualStackHost()) + ); + + if (empty($command['@use_path_style_endpoint']) + && !$this->pathStyleByDefault + && self::isRequestHostStyleCompatible($command, $request) + ) { + $request = $this->applyHostStyleEndpoint($command, $request); + } + return $request; + } + + private function getDualStackHost() + { + $dnsSuffix = $this->endpointProvider + ->getPartition($this->region, 's3') + ->getDnsSuffix(); + return "s3.dualstack.{$this->region}.{$dnsSuffix}"; + } + + private function applyAccelerateEndpoint( + CommandInterface $command, + RequestInterface $request, + $pattern + ) { + $request = $request->withUri( + $request->getUri() + ->withHost($this->getAccelerateHost($command, $pattern)) + ->withPath($this->getBucketlessPath( + $request->getUri()->getPath(), + $command + )) + ); + return $request; + } + + private function getAccelerateHost(CommandInterface $command, $pattern) + { + $dnsSuffix = $this->endpointProvider + ->getPartition($this->region, 's3') + ->getDnsSuffix(); + return "{$command['Bucket']}.{$pattern}.{$dnsSuffix}"; + } + + private function getBucketlessPath($path, CommandInterface $command) + { + $pattern = '/^\\/' . preg_quote($command['Bucket'], '/') . '/'; + $path = preg_replace($pattern, '', $path) ?: '/'; + if (substr($path, 0 , 1) !== '/') { + $path = '/' . $path; + } + return $path; + } + + private function applyEndpoint( + CommandInterface $command, + RequestInterface $request + ) { + $dualStack = isset($command['@use_dual_stack_endpoint']) + ? $command['@use_dual_stack_endpoint'] : $this->dualStackByDefault; + if (ArnParser::isArn($command['Bucket'])) { + $arn = ArnParser::parse($command['Bucket']); + $outpost = $arn->getService() == 's3-outposts'; + if ($outpost && $dualStack) { + throw new InvalidArgumentException("Outposts + dualstack is not supported"); + } + if ($arn instanceof ObjectLambdaAccessPointArn) { + return $request; + } + } + if ($dualStack) { + throw new InvalidArgumentException("Custom Endpoint + Dualstack not supported"); + } + if ($command->getName() == 'WriteGetObjectResponse') { + $host = "{$command['RequestRoute']}.{$this->endpoint}"; + $uri = $request->getUri(); + return $request = $request->withUri( + $uri->withHost($host) + ->withPath($this->getBucketlessPath( + $uri->getPath(), + $command + )) + ); + } + $host = ($this->pathStyleByDefault) ? + $this->endpoint : + $this->getBucketStyleHost( + $command, + $this->endpoint + ); + $uri = $request->getUri(); + $scheme = $uri->getScheme(); + if(empty($scheme)){ + $request = $request->withUri( + $uri->withHost($host) + ); + } else { + $request = $request->withUri($uri); + } + + return $request; + } +} |