AutorÃa | Ultima modificación | Ver Log |
<?phpnamespace 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;}}