%PDF- %PDF-
Direktori : /home/vacivi36/intranet.vacivitta.com.br/protected/vendor/async-aws/core/src/ |
Current File : /home/vacivi36/intranet.vacivitta.com.br/protected/vendor/async-aws/core/src/AbstractApi.php |
<?php declare(strict_types=1); namespace AsyncAws\Core; use AsyncAws\Core\AwsError\AwsErrorFactoryInterface; use AsyncAws\Core\AwsError\ChainAwsErrorFactory; use AsyncAws\Core\Credentials\CacheProvider; use AsyncAws\Core\Credentials\ChainProvider; use AsyncAws\Core\Credentials\CredentialProvider; use AsyncAws\Core\EndpointDiscovery\EndpointCache; use AsyncAws\Core\Exception\InvalidArgument; use AsyncAws\Core\Exception\LogicException; use AsyncAws\Core\Exception\RuntimeException; use AsyncAws\Core\HttpClient\AwsRetryStrategy; use AsyncAws\Core\Signer\Signer; use AsyncAws\Core\Signer\SignerV4; use AsyncAws\Core\Stream\StringStream; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\RetryableHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; /** * Base class all API clients are inheriting. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> * @author Jérémy Derussé <jeremy@derusse.com> */ abstract class AbstractApi { /** * @var HttpClientInterface */ private $httpClient; /** * @var Configuration */ private $configuration; /** * @var CredentialProvider */ private $credentialProvider; /** * @var Signer[] */ private $signers; /** * @var LoggerInterface */ private $logger; /** * @var AwsErrorFactoryInterface */ private $awsErrorFactory; /** * @var EndpointCache */ private $endpointCache; /** * @param Configuration|array $configuration */ public function __construct($configuration = [], ?CredentialProvider $credentialProvider = null, ?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null) { if (\is_array($configuration)) { $configuration = Configuration::create($configuration); } elseif (!$configuration instanceof Configuration) { throw new InvalidArgument(sprintf('First argument to "%s::__construct()" must be an array or an instance of "%s"', static::class, Configuration::class)); } $this->logger = $logger ?? new NullLogger(); $this->awsErrorFactory = $this->getAwsErrorFactory(); $this->endpointCache = new EndpointCache(); if (!isset($httpClient)) { $httpClient = HttpClient::create(); if (class_exists(RetryableHttpClient::class)) { /** @psalm-suppress MissingDependency */ $httpClient = new RetryableHttpClient( $httpClient, new AwsRetryStrategy(AwsRetryStrategy::DEFAULT_RETRY_STATUS_CODES, 1000, 2.0, 0, 0.1, $this->awsErrorFactory), 3, $this->logger ); } } $this->httpClient = $httpClient; $this->configuration = $configuration; $this->credentialProvider = $credentialProvider ?? new CacheProvider(ChainProvider::createDefaultChain($this->httpClient, $this->logger)); } final public function getConfiguration(): Configuration { return $this->configuration; } final public function presign(Input $input, ?\DateTimeImmutable $expires = null): string { $request = $input->request(); $request->setEndpoint($this->getEndpoint($request->getUri(), $request->getQuery(), $input->getRegion())); if (null !== $credentials = $this->credentialProvider->getCredentials($this->configuration)) { $this->getSigner($input->getRegion())->presign($request, $credentials, new RequestContext(['expirationDate' => $expires])); } return $request->getEndpoint(); } /** * @deprecated */ protected function getServiceCode(): string { throw new LogicException(sprintf('The method "%s" should not be called. The Client "%s" must implement the "%s" method.', __FUNCTION__, \get_class($this), 'getEndpointMetadata')); } /** * @deprecated */ protected function getSignatureVersion(): string { throw new LogicException(sprintf('The method "%s" should not be called. The Client "%s" must implement the "%s" method.', __FUNCTION__, \get_class($this), 'getEndpointMetadata')); } /** * @deprecated */ protected function getSignatureScopeName(): string { throw new LogicException(sprintf('The method "%s" should not be called. The Client "%s" must implement the "%s" method.', __FUNCTION__, \get_class($this), 'getEndpointMetadata')); } final protected function getResponse(Request $request, ?RequestContext $context = null): Response { $request->setEndpoint($this->getDiscoveredEndpoint($request->getUri(), $request->getQuery(), $context ? $context->getRegion() : null, $context ? $context->usesEndpointDiscovery() : false, $context ? $context->requiresEndpointDiscovery() : false)); if (null !== $credentials = $this->credentialProvider->getCredentials($this->configuration)) { $this->getSigner($context ? $context->getRegion() : null)->sign($request, $credentials, $context ?? new RequestContext()); } $length = $request->getBody()->length(); if (null !== $length && !$request->hasHeader('content-length')) { $request->setHeader('content-length', (string) $length); } // Some servers (like testing Docker Images) does not supports `Transfer-Encoding: chunked` requests. // The body is converted into string to prevent curl using `Transfer-Encoding: chunked` unless it really has to. if (($requestBody = $request->getBody()) instanceof StringStream) { $requestBody = $requestBody->stringify(); } $response = $this->httpClient->request( $request->getMethod(), $request->getEndpoint(), [ 'headers' => $request->getHeaders(), ] + (0 === $length ? [] : ['body' => $requestBody]) ); if ($debug = filter_var($this->configuration->get('debug'), \FILTER_VALIDATE_BOOLEAN)) { $this->logger->debug('AsyncAws HTTP request sent: {method} {endpoint}', [ 'method' => $request->getMethod(), 'endpoint' => $request->getEndpoint(), 'headers' => json_encode($request->getHeaders()), 'body' => 0 === $length ? null : $requestBody, ]); } return new Response($response, $this->httpClient, $this->logger, $this->awsErrorFactory, $this->endpointCache, $request, $debug, $context ? $context->getExceptionMapping() : []); } /** * @return callable[] */ protected function getSignerFactories(): array { return [ 'v4' => static function (string $service, string $region) { return new SignerV4($service, $region); }, ]; } protected function getAwsErrorFactory(): AwsErrorFactoryInterface { return new ChainAwsErrorFactory(); } /** * Returns the AWS endpoint metadata for the given region. * When user did not provide a region, the client have to either return a global endpoint or fallback to * the Configuration::DEFAULT_REGION constant. * * This implementation is a BC layer for client that does not require core:^1.2. * * @param ?string $region region provided by the user (without fallback to a default region) * * @return array{endpoint: string, signRegion: string, signService: string, signVersions: string[]} */ protected function getEndpointMetadata(?string $region): array { /** @psalm-suppress TooManyArguments */ trigger_deprecation('async-aws/core', '1.2', 'Extending "%s"" without overriding "%s" is deprecated. This method will be abstract in version 2.0.', __CLASS__, __FUNCTION__); /** @var string $endpoint */ $endpoint = $this->configuration->get('endpoint'); /** @var string $region */ $region = $region ?? $this->configuration->get('region'); return [ 'endpoint' => strtr($endpoint, [ '%region%' => $region, '%service%' => $this->getServiceCode(), ]), 'signRegion' => $region, 'signService' => $this->getSignatureScopeName(), 'signVersions' => [$this->getSignatureVersion()], ]; } /** * Build the endpoint full uri. * * @param string $uri or path * @param array $query parameters that should go in the query string * @param ?string $region region provided by the user in the `@region` parameter of the Input */ protected function getEndpoint(string $uri, array $query, ?string $region): string { /** @var string $region */ $region = $region ?? ($this->configuration->isDefault('region') ? null : $this->configuration->get('region')); if (!$this->configuration->isDefault('endpoint')) { /** @var string $endpoint */ $endpoint = $this->configuration->get('endpoint'); } else { $metadata = $this->getEndpointMetadata($region); $endpoint = $metadata['endpoint']; } if (false !== strpos($endpoint, '%region%') || false !== strpos($endpoint, '%service%')) { /** @psalm-suppress TooManyArguments */ trigger_deprecation('async-aws/core', '1.2', 'providing an endpoint with placeholder is deprecated and will be ignored in version 2.0. Provide full endpoint instead.'); $endpoint = strtr($endpoint, [ '%region%' => $region ?? $this->configuration->get('region'), '%service%' => $this->getServiceCode(), // if people provides a custom endpoint 'http://%service%.localhost/ ]); } $endpoint .= $uri; if (empty($query)) { return $endpoint; } return $endpoint . (false === strpos($endpoint, '?') ? '?' : '&') . http_build_query($query); } protected function discoverEndpoints(?string $region): array { throw new LogicException(sprintf('The Client "%s" must implement the "%s" method.', \get_class($this), 'discoverEndpoints')); } private function getDiscoveredEndpoint(string $uri, array $query, ?string $region, bool $usesEndpointDiscovery, bool $requiresEndpointDiscovery) { if (!$this->configuration->isDefault('endpoint')) { return $this->getEndpoint($uri, $query, $region); } $usesEndpointDiscovery = $requiresEndpointDiscovery || ($usesEndpointDiscovery && filter_var($this->configuration->get(Configuration::OPTION_ENDPOINT_DISCOVERY_ENABLED), \FILTER_VALIDATE_BOOLEAN)); if (!$usesEndpointDiscovery) { return $this->getEndpoint($uri, $query, $region); } // 1. use an active endpoints if (null === $endpoint = $this->endpointCache->getActiveEndpoint($region)) { $previous = null; try { // 2. call API to fetch new endpoints $endpoints = $this->discoverEndpoints($region); $this->endpointCache->addEndpoints($region, $endpoints); // 3. use active endpoints that has just been injected $endpoint = $this->endpointCache->getActiveEndpoint($region); } catch (\Exception $previous) { } // 4. if endpoint is still null, fallback to expired endpoint if (null === $endpoint && null === $endpoint = $this->endpointCache->getExpiredEndpoint($region)) { if ($requiresEndpointDiscovery) { throw new RuntimeException(sprintf('The Client "%s" failed to fetch the endpoint.', \get_class($this)), 0, $previous); } return $this->getEndpoint($uri, $query, $region); } } return $endpoint; } /** * @param ?string $region region provided by the user in the `@region` parameter of the Input */ private function getSigner(?string $region) { /** @var string $region */ $region = $region ?? ($this->configuration->isDefault('region') ? null : $this->configuration->get('region')); if (!isset($this->signers[$region])) { $factories = $this->getSignerFactories(); $factory = null; if ($this->configuration->isDefault('endpoint') || $this->configuration->isDefault('region')) { $metadata = $this->getEndpointMetadata($region); } else { // Allow non-aws region with custom endpoint $metadata = $this->getEndpointMetadata(Configuration::DEFAULT_REGION); $metadata['signRegion'] = $region; } foreach ($metadata['signVersions'] as $signatureVersion) { if (isset($factories[$signatureVersion])) { $factory = $factories[$signatureVersion]; break; } } if (null === $factory) { throw new InvalidArgument(sprintf('None of the signatures "%s" is implemented.', implode(', ', $metadata['signVersions']))); } $this->signers[$region] = $factory($metadata['signService'], $metadata['signRegion']); } /** @psalm-suppress PossiblyNullArrayOffset */ return $this->signers[$region]; } }