ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç EndpointArnMiddleware.php000064400000031730152267307140011507 0ustar00 [ 'CreateAccessPoint', ], 'BucketName' => [], ]; /** * Commands which do not do ARN expansion at all for relevant members * @var array */ private static $nonArnableCmds = [ 'CreateBucket', 'ListRegionalBuckets', ]; /** * Commands which trigger endpoint and signer redirection based on presence * of OutpostId * @var array */ private static $outpostIdRedirectCmds = [ 'CreateBucket', 'ListRegionalBuckets', ]; /** @var callable */ private $nextHandler; /** @var boolean */ private $isUseEndpointV2; /** * Create a middleware wrapper function. * * @param Service $service * @param $region * @param array $config * @return callable */ public static function wrap( Service $service, $region, array $config, $isUseEndpointV2 ) { return function (callable $handler) use ($service, $region, $config, $isUseEndpointV2) { return new self($handler, $service, $region, $config, $isUseEndpointV2); }; } public function __construct( callable $nextHandler, Service $service, $region, array $config = [], $isUseEndpointV2 = false ) { $this->partitionProvider = PartitionEndpointProvider::defaultProvider(); $this->region = $region; $this->service = $service; $this->config = $config; $this->nextHandler = $nextHandler; $this->isUseEndpointV2 = $isUseEndpointV2; } public function __invoke(CommandInterface $cmd, RequestInterface $req) { $nextHandler = $this->nextHandler; $op = $this->service->getOperation($cmd->getName())->toArray(); if (!empty($op['input']['shape']) && !in_array($cmd->getName(), self::$nonArnableCmds) ) { $service = $this->service->toArray(); if (!empty($input = $service['shapes'][$op['input']['shape']])) { // Stores member name that targets 'BucketName' shape $bucketNameMember = null; // Stores member name that targets 'AccessPointName' shape $accesspointNameMember = null; foreach ($input['members'] as $key => $member) { if ($member['shape'] === 'BucketName') { $bucketNameMember = $key; } if ($member['shape'] === 'AccessPointName') { $accesspointNameMember = $key; } } // Determine if appropriate member contains ARN value and is // eligible for ARN expansion if (!is_null($bucketNameMember) && !empty($cmd[$bucketNameMember]) && !in_array($cmd->getName(), self::$selectiveNonArnableCmds['BucketName']) && ArnParser::isArn($cmd[$bucketNameMember]) ) { $arn = ArnParser::parse($cmd[$bucketNameMember]); !$this->isUseEndpointV2 && $partition = $this->validateBucketArn($arn); } elseif (!is_null($accesspointNameMember) && !empty($cmd[$accesspointNameMember]) && !in_array($cmd->getName(), self::$selectiveNonArnableCmds['AccessPointName']) && ArnParser::isArn($cmd[$accesspointNameMember]) ) { $arn = ArnParser::parse($cmd[$accesspointNameMember]); !$this->isUseEndpointV2 && $partition = $this->validateAccessPointArn($arn); } // Process only if an appropriate member contains an ARN value // and is an Outposts ARN if (!empty($arn) && $arn instanceof OutpostsArnInterface) { if (!$this->isUseEndpointV2) { // Generate host based on ARN $host = $this->generateOutpostsArnHost($arn, $req); $req = $req->withHeader('x-amz-outpost-id', $arn->getOutpostId()); } // ARN replacement $path = $req->getUri()->getPath(); if ($arn instanceof AccessPointArnInterface) { // Replace ARN with access point name $path = str_replace( urlencode($cmd[$accesspointNameMember]), $arn->getAccesspointName(), $path ); // Replace ARN in the payload $req->getBody()->seek(0); $body = Psr7\Utils::streamFor(str_replace( $cmd[$accesspointNameMember], $arn->getAccesspointName(), $req->getBody()->getContents() )); // Replace ARN in the command $cmd[$accesspointNameMember] = $arn->getAccesspointName(); } elseif ($arn instanceof BucketArnInterface) { // Replace ARN in the path $path = str_replace( urlencode($cmd[$bucketNameMember]), $arn->getBucketName(), $path ); // Replace ARN in the payload $req->getBody()->seek(0); $newBody = str_replace( $cmd[$bucketNameMember], $arn->getBucketName(), $req->getBody()->getContents() ); $body = Psr7\Utils::streamFor($newBody); // Replace ARN in the command $cmd[$bucketNameMember] = $arn->getBucketName(); } // Validate or set account ID in command if (isset($cmd['AccountId'])) { if ($cmd['AccountId'] !== $arn->getAccountId()) { throw new \InvalidArgumentException("The account ID" . " supplied in the command ({$cmd['AccountId']})" . " does not match the account ID supplied in the" . " ARN (" . $arn->getAccountId() . ")."); } } else { $cmd['AccountId'] = $arn->getAccountId(); } // Set modified request if (isset($body)) { $req = $req->withBody($body); } if ($this->isUseEndpointV2) { $req = $req->withUri($req->getUri()->withPath($path)); goto next; } $req = $req ->withUri($req->getUri()->withHost($host)->withPath($path)) ->withHeader('x-amz-account-id', $arn->getAccountId()); // Update signing region based on ARN data if configured to do so if ($this->config['use_arn_region']->isUseArnRegion()) { $region = $arn->getRegion(); } else { $region = $this->region; } $endpointData = $partition([ 'region' => $region, 'service' => $arn->getService() ]); $cmd['@context']['signing_region'] = $endpointData['signingRegion']; // Update signing service for Outposts ARNs if ($arn instanceof OutpostsArnInterface) { $cmd['@context']['signing_service'] = $arn->getService(); } } } } if ($this->isUseEndpointV2) { goto next; } // For operations that redirect endpoint & signing service based on // presence of OutpostId member. These operations will likely not // overlap with operations that perform ARN expansion. if (in_array($cmd->getName(), self::$outpostIdRedirectCmds) && !empty($cmd['OutpostId']) ) { $req = $req->withUri( $req->getUri()->withHost($this->generateOutpostIdHost()) ); $cmd['@context']['signing_service'] = 's3-outposts'; } next: return $nextHandler($cmd, $req); } private function generateOutpostsArnHost( OutpostsArnInterface $arn, RequestInterface $req ) { if (!empty($this->config['use_arn_region']->isUseArnRegion())) { $region = $arn->getRegion(); } else { $region = $this->region; } $fipsString = $this->config['use_fips_endpoint']->isUseFipsEndpoint() ? "-fips" : ""; $suffix = $this->getPartitionSuffix($arn, $this->partitionProvider); return "s3-outposts{$fipsString}.{$region}.{$suffix}"; } private function generateOutpostIdHost() { $partition = $this->partitionProvider->getPartition( $this->region, $this->service->getEndpointPrefix() ); $suffix = $partition->getDnsSuffix(); return "s3-outposts.{$this->region}.{$suffix}"; } private function validateBucketArn(ArnInterface $arn) { if ($arn instanceof BucketArnInterface) { return $this->validateArn($arn); } throw new InvalidArnException('Provided ARN was not a valid S3 bucket' . ' ARN.'); } private function validateAccessPointArn(ArnInterface $arn) { if ($arn instanceof AccessPointArnInterface) { return $this->validateArn($arn); } throw new InvalidArnException('Provided ARN was not a valid S3 access' . ' point ARN.'); } /** * Validates an ARN, returning a partition object corresponding to the ARN * if successful * * @param $arn * @return \Aws\Endpoint\Partition */ private function validateArn(ArnInterface $arn) { // Dualstack is not supported with Outposts ARNs if ($arn instanceof OutpostsArnInterface && !empty($this->config['dual_stack']) ) { throw new UnresolvedEndpointException( 'Dualstack is currently not supported with S3 Outposts ARNs.' . ' Please disable dualstack or do not supply an Outposts ARN.'); } // Get partitions for ARN and client region $arnPart = $this->partitionProvider->getPartitionByName( $arn->getPartition() ); $clientPart = $this->partitionProvider->getPartition( $this->region, 's3' ); // If client partition not found, try removing pseudo-region qualifiers if (!($clientPart->isRegionMatch($this->region, 's3'))) { $clientPart = $this->partitionProvider->getPartition( \Aws\strip_fips_pseudo_regions($this->region), 's3' ); } // Verify that the partition matches for supplied partition and region if ($arn->getPartition() !== $clientPart->getName()) { throw new InvalidRegionException('The supplied ARN partition' . " does not match the client's partition."); } if ($clientPart->getName() !== $arnPart->getName()) { throw new InvalidRegionException('The corresponding partition' . ' for the supplied ARN region does not match the' . " client's partition."); } // Ensure ARN region matches client region unless // configured for using ARN region over client region $this->validateMatchingRegion($arn); // Ensure it is not resolved to fips pseudo-region for S3 Outposts $this->validateFipsConfigurations($arn); return $arnPart; } }S3ControlClient.php000064400000046066152267307140010265 0ustar00 [ 'type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to an S3 Control Dual Stack' . ' endpoint by default, which enables IPv6 Protocol.' . ' Can be enabled or disabled on individual operations by setting' . ' \'@use_dual_stack_endpoint\' to true or false.', 'default' => false, ], 'use_arn_region' => [ 'type' => 'config', 'valid' => [ 'bool', Configuration::class, CacheInterface::class, 'callable' ], 'doc' => 'Set to true to allow passed in ARNs to override' . ' client region. Accepts...', 'fn' => [__CLASS__, '_apply_use_arn_region'], 'default' => [UseArnRegionConfigurationProvider::class, 'defaultProvider'], ], ]; } public static function _apply_use_arn_region($value, array &$args, HandlerList $list) { if ($value instanceof CacheInterface) { $value = UseArnRegionConfigurationProvider::defaultProvider($args); } if (is_callable($value)) { $value = $value(); } if ($value instanceof PromiseInterface) { $value = $value->wait(); } if ($value instanceof ConfigurationInterface) { $args['use_arn_region'] = $value; } else { // The Configuration class itself will validate other inputs $args['use_arn_region'] = new Configuration($value); } } /** * {@inheritdoc} * * In addition to the options available to * {@see Aws\AwsClient::__construct}, S3ControlClient accepts the following * option: * * - use_dual_stack_endpoint: (bool) Set to true to send requests to an S3 * Control Dual Stack endpoint by default, which enables IPv6 Protocol. * Can be enabled or disabled on individual operations by setting * '@use_dual_stack_endpoint\' to true or false. Note: * you cannot use it together with an accelerate endpoint. * * @param array $args */ public function __construct(array $args) { parent::__construct($args); if ($this->isUseEndpointV2()) { $this->processEndpointV2Model(); } else { $stack = $this->getHandlerList(); $stack->appendBuild( EndpointArnMiddleware::wrap( $this->getApi(), $this->getRegion(), [ 'use_arn_region' => $this->getConfig('use_arn_region'), 'dual_stack' => $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(), 'endpoint' => isset($args['endpoint']) ? $args['endpoint'] : null, 'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'), ], $this->isUseEndpointV2() ), 's3control.endpoint_arn_middleware' ); } } /** * Modifies API definition to remove `AccountId` * host prefix. This is now handled by the endpoint ruleset. * * @return void * * @internal */ private function processEndpointV2Model() { $definition = $this->getApi()->getDefinition(); $this->removeHostPrefix($definition); $this->removeRequiredMember($definition); $this->getApi()->setDefinition($definition); } private function removeHostPrefix(&$definition) { foreach($definition['operations'] as &$operation) { if (isset($operation['endpoint']['hostPrefix']) && $operation['endpoint']['hostPrefix'] === '{AccountId}.' ) { $operation['endpoint']['hostPrefix'] = str_replace( '{AccountId}.', '', $operation['endpoint']['hostPrefix'] ); } } } private function removeRequiredMember(&$definition) { foreach($definition['shapes'] as &$shape) { if (isset($shape['required']) ) { $found = array_search('AccountId', $shape['required']); if ($found !== false) { unset($shape['required'][$found]); } } } } } Exception/S3ControlException.php000064400000000314152267307140012725 0ustar00