diff options
author | Andrew Dolgov <[email protected]> | 2022-11-23 21:14:33 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2022-11-23 21:14:33 +0300 |
commit | 0c8af4992cb0f7589dcafaad65ada12753c64594 (patch) | |
tree | 18e83d068c3e7dd2499331de977782b382279396 /vendor/aws/aws-sdk-php/src/ClientResolver.php |
initial
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/ClientResolver.php')
-rw-r--r-- | vendor/aws/aws-sdk-php/src/ClientResolver.php | 1150 |
1 files changed, 1150 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/ClientResolver.php b/vendor/aws/aws-sdk-php/src/ClientResolver.php new file mode 100644 index 0000000..7943bbc --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/ClientResolver.php @@ -0,0 +1,1150 @@ +<?php +namespace Aws; + +use Aws\Api\Validator; +use Aws\Api\ApiProvider; +use Aws\Api\Service; +use Aws\ClientSideMonitoring\ApiCallAttemptMonitoringMiddleware; +use Aws\ClientSideMonitoring\ApiCallMonitoringMiddleware; +use Aws\ClientSideMonitoring\Configuration; +use Aws\Credentials\Credentials; +use Aws\Credentials\CredentialsInterface; +use Aws\Endpoint\PartitionEndpointProvider; +use Aws\Endpoint\UseFipsEndpoint\Configuration as UseFipsEndpointConfiguration; +use Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider as UseFipsConfigProvider; +use Aws\Endpoint\UseFipsEndpoint\ConfigurationInterface as UseFipsEndpointConfigurationInterface; +use Aws\Endpoint\UseDualstackEndpoint\Configuration as UseDualStackEndpointConfiguration; +use Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider as UseDualStackConfigProvider; +use Aws\Endpoint\UseDualstackEndpoint\ConfigurationInterface as UseDualStackEndpointConfigurationInterface; +use Aws\EndpointDiscovery\ConfigurationInterface; +use Aws\EndpointDiscovery\ConfigurationProvider; +use Aws\EndpointV2\EndpointDefinitionProvider; +use Aws\Exception\InvalidRegionException; +use Aws\Retry\ConfigurationInterface as RetryConfigInterface; +use Aws\Retry\ConfigurationProvider as RetryConfigProvider; +use Aws\DefaultsMode\ConfigurationInterface as ConfigModeInterface; +use Aws\DefaultsMode\ConfigurationProvider as ConfigModeProvider; +use Aws\Signature\SignatureProvider; +use Aws\Endpoint\EndpointProvider; +use Aws\Token\Token; +use Aws\Token\TokenInterface; +use Aws\Token\TokenProvider; +use GuzzleHttp\Promise\PromiseInterface; +use Aws\Credentials\CredentialProvider; +use InvalidArgumentException as IAE; +use Psr\Http\Message\RequestInterface; + +/** + * @internal Resolves a hash of client arguments to construct a client. + */ +class ClientResolver +{ + /** @var array */ + private $argDefinitions; + + /** @var array Map of types to a corresponding function */ + private static $typeMap = [ + 'resource' => 'is_resource', + 'callable' => 'is_callable', + 'int' => 'is_int', + 'bool' => 'is_bool', + 'boolean' => 'is_bool', + 'string' => 'is_string', + 'object' => 'is_object', + 'array' => 'is_array', + ]; + + private static $defaultArgs = [ + 'service' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'Name of the service to utilize. This value will be supplied by default when using one of the SDK clients (e.g., Aws\\S3\\S3Client).', + 'required' => true, + 'internal' => true + ], + 'exception_class' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'Exception class to create when an error occurs.', + 'default' => 'Aws\Exception\AwsException', + 'internal' => true + ], + 'scheme' => [ + 'type' => 'value', + 'valid' => ['string'], + 'default' => 'https', + 'doc' => 'URI scheme to use when connecting connect. The SDK will utilize "https" endpoints (i.e., utilize SSL/TLS connections) by default. You can attempt to connect to a service over an unencrypted "http" endpoint by setting ``scheme`` to "http".', + ], + 'disable_host_prefix_injection' => [ + 'type' => 'value', + 'valid' => ['bool'], + 'doc' => 'Set to true to disable host prefix injection logic for services that use it. This disables the entire prefix injection, including the portions supplied by user-defined parameters. Setting this flag will have no effect on services that do not use host prefix injection.', + 'default' => false, + ], + 'endpoint' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of S3).', + 'fn' => [__CLASS__, '_apply_endpoint'], + ], + 'region' => [ + 'type' => 'value', + 'valid' => ['string'], + 'required' => [__CLASS__, '_missing_region'], + 'doc' => 'Region to connect to. See http://docs.aws.amazon.com/general/latest/gr/rande.html for a list of available regions.', + ], + 'version' => [ + 'type' => 'value', + 'valid' => ['string'], + 'required' => [__CLASS__, '_missing_version'], + 'doc' => 'The version of the webservice to utilize (e.g., 2006-03-01).', + ], + 'signature_provider' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'A callable that accepts a signature version name (e.g., "v4"), a service name, and region, and returns a SignatureInterface object or null. This provider is used to create signers utilized by the client. See Aws\\Signature\\SignatureProvider for a list of built-in providers', + 'default' => [__CLASS__, '_default_signature_provider'], + ], + 'api_provider' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'An optional PHP callable that accepts a type, service, and version argument, and returns an array of corresponding configuration data. The type value can be one of api, waiter, or paginator.', + 'fn' => [__CLASS__, '_apply_api_provider'], + 'default' => [ApiProvider::class, 'defaultProvider'], + ], + 'configuration_mode' => [ + 'type' => 'value', + 'valid' => [ConfigModeInterface::class, CacheInterface::class, 'string', 'closure'], + 'doc' => "Sets the default configuration mode. Otherwise provide an instance of Aws\DefaultsMode\ConfigurationInterface, an instance of Aws\CacheInterface, or a string containing a valid mode", + 'fn' => [__CLASS__, '_apply_defaults'], + 'default' => [ConfigModeProvider::class, 'defaultProvider'] + ], + 'use_fips_endpoint' => [ + 'type' => 'value', + 'valid' => ['bool', UseFipsEndpointConfiguration::class, CacheInterface::class, 'callable'], + 'doc' => 'Set to true to enable the use of FIPS pseudo regions', + 'fn' => [__CLASS__, '_apply_use_fips_endpoint'], + 'default' => [__CLASS__, '_default_use_fips_endpoint'], + ], + 'use_dual_stack_endpoint' => [ + 'type' => 'value', + 'valid' => ['bool', UseDualStackEndpointConfiguration::class, CacheInterface::class, 'callable'], + 'doc' => 'Set to true to enable the use of dual-stack endpoints', + 'fn' => [__CLASS__, '_apply_use_dual_stack_endpoint'], + 'default' => [__CLASS__, '_default_use_dual_stack_endpoint'], + ], + 'endpoint_provider' => [ + 'type' => 'value', + 'valid' => ['callable', EndpointV2\EndpointProviderV2::class], + 'fn' => [__CLASS__, '_apply_endpoint_provider'], + 'doc' => 'An optional PHP callable that accepts a hash of options including a "service" and "region" key and returns NULL or a hash of endpoint data, of which the "endpoint" key is required. See Aws\\Endpoint\\EndpointProvider for a list of built-in providers.', + 'default' => [__CLASS__, '_default_endpoint_provider'], + ], + 'serializer' => [ + 'default' => [__CLASS__, '_default_serializer'], + 'internal' => true, + 'type' => 'value', + 'valid' => ['callable'], + ], + 'signature_version' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'A string representing a custom signature version to use with a service (e.g., v4). Note that per/operation signature version MAY override this requested signature version.', + 'default' => [__CLASS__, '_default_signature_version'], + ], + 'signing_name' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'A string representing a custom service name to be used when calculating a request signature.', + 'default' => [__CLASS__, '_default_signing_name'], + ], + 'signing_region' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'A string representing a custom region name to be used when calculating a request signature.', + 'default' => [__CLASS__, '_default_signing_region'], + ], + 'profile' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'Allows you to specify which profile to use when credentials are created from the AWS credentials file in your HOME directory. This setting overrides the AWS_PROFILE environment variable. Note: Specifying "profile" will cause the "credentials" and "use_aws_shared_config_files" keys to be ignored.', + 'fn' => [__CLASS__, '_apply_profile'], + ], + 'credentials' => [ + 'type' => 'value', + 'valid' => [CredentialsInterface::class, CacheInterface::class, 'array', 'bool', 'callable'], + 'doc' => 'Specifies the credentials used to sign requests. Provide an Aws\Credentials\CredentialsInterface object, an associative array of "key", "secret", and an optional "token" key, `false` to use null credentials, or a callable credentials provider used to create credentials or return null. See Aws\\Credentials\\CredentialProvider for a list of built-in credentials providers. If no credentials are provided, the SDK will attempt to load them from the environment.', + 'fn' => [__CLASS__, '_apply_credentials'], + 'default' => [__CLASS__, '_default_credential_provider'], + ], + 'token' => [ + 'type' => 'value', + 'valid' => [TokenInterface::class, CacheInterface::class, 'array', 'bool', 'callable'], + 'doc' => 'Specifies the token used to authorize requests. Provide an Aws\Token\TokenInterface object, an associative array of "token", and an optional "expiration" key, `false` to use a null token, or a callable token provider used to fetch a token or return null. See Aws\\Token\\TokenProvider for a list of built-in credentials providers. If no token is provided, the SDK will attempt to load one from the environment.', + 'fn' => [__CLASS__, '_apply_token'], + 'default' => [__CLASS__, '_default_token_provider'], + ], + 'endpoint_discovery' => [ + 'type' => 'value', + 'valid' => [ConfigurationInterface::class, CacheInterface::class, 'array', 'callable'], + 'doc' => 'Specifies settings for endpoint discovery. Provide an instance of Aws\EndpointDiscovery\ConfigurationInterface, an instance Aws\CacheInterface, a callable that provides a promise for a Configuration object, or an associative array with the following keys: enabled: (bool) Set to true to enable endpoint discovery, false to explicitly disable it. Defaults to false; cache_limit: (int) The maximum number of keys in the endpoints cache. Defaults to 1000.', + 'fn' => [__CLASS__, '_apply_endpoint_discovery'], + 'default' => [__CLASS__, '_default_endpoint_discovery_provider'] + ], + 'stats' => [ + 'type' => 'value', + 'valid' => ['bool', 'array'], + 'default' => false, + 'doc' => 'Set to true to gather transfer statistics on requests sent. Alternatively, you can provide an associative array with the following keys: retries: (bool) Set to false to disable reporting on retries attempted; http: (bool) Set to true to enable collecting statistics from lower level HTTP adapters (e.g., values returned in GuzzleHttp\TransferStats). HTTP handlers must support an http_stats_receiver option for this to have an effect; timer: (bool) Set to true to enable a command timer that reports the total wall clock time spent on an operation in seconds.', + 'fn' => [__CLASS__, '_apply_stats'], + ], + 'retries' => [ + 'type' => 'value', + 'valid' => ['int', RetryConfigInterface::class, CacheInterface::class, 'callable', 'array'], + 'doc' => "Configures the retry mode and maximum number of allowed retries for a client (pass 0 to disable retries). Provide an integer for 'legacy' mode with the specified number of retries. Otherwise provide an instance of Aws\Retry\ConfigurationInterface, an instance of Aws\CacheInterface, a callable function, or an array with the following keys: mode: (string) Set to 'legacy', 'standard' (uses retry quota management), or 'adapative' (an experimental mode that adds client-side rate limiting to standard mode); max_attempts: (int) The maximum number of attempts for a given request. ", + 'fn' => [__CLASS__, '_apply_retries'], + 'default' => [RetryConfigProvider::class, 'defaultProvider'] + ], + 'validate' => [ + 'type' => 'value', + 'valid' => ['bool', 'array'], + 'default' => true, + 'doc' => 'Set to false to disable client-side parameter validation. Set to true to utilize default validation constraints. Set to an associative array of validation options to enable specific validation constraints.', + 'fn' => [__CLASS__, '_apply_validate'], + ], + 'debug' => [ + 'type' => 'value', + 'valid' => ['bool', 'array'], + 'doc' => 'Set to true to display debug information when sending requests. Alternatively, you can provide an associative array with the following keys: logfn: (callable) Function that is invoked with log messages; stream_size: (int) When the size of a stream is greater than this number, the stream data will not be logged (set to "0" to not log any stream data); scrub_auth: (bool) Set to false to disable the scrubbing of auth data from the logged messages; http: (bool) Set to false to disable the "debug" feature of lower level HTTP adapters (e.g., verbose curl output).', + 'fn' => [__CLASS__, '_apply_debug'], + ], + 'csm' => [ + 'type' => 'value', + 'valid' => [\Aws\ClientSideMonitoring\ConfigurationInterface::class, 'callable', 'array', 'bool'], + 'doc' => 'CSM options for the client. Provides a callable wrapping a promise, a boolean "false", an instance of ConfigurationInterface, or an associative array of "enabled", "host", "port", and "client_id".', + 'fn' => [__CLASS__, '_apply_csm'], + 'default' => [\Aws\ClientSideMonitoring\ConfigurationProvider::class, 'defaultProvider'] + ], + 'http' => [ + 'type' => 'value', + 'valid' => ['array'], + 'default' => [], + 'doc' => 'Set to an array of SDK request options to apply to each request (e.g., proxy, verify, etc.).', + ], + 'http_handler' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'An HTTP handler is a function that accepts a PSR-7 request object and returns a promise that is fulfilled with a PSR-7 response object or rejected with an array of exception data. NOTE: This option supersedes any provided "handler" option.', + 'fn' => [__CLASS__, '_apply_http_handler'] + ], + 'handler' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'A handler that accepts a command object, request object and returns a promise that is fulfilled with an Aws\ResultInterface object or rejected with an Aws\Exception\AwsException. A handler does not accept a next handler as it is terminal and expected to fulfill a command. If no handler is provided, a default Guzzle handler will be utilized.', + 'fn' => [__CLASS__, '_apply_handler'], + 'default' => [__CLASS__, '_default_handler'] + ], + 'ua_append' => [ + 'type' => 'value', + 'valid' => ['string', 'array'], + 'doc' => 'Provide a string or array of strings to send in the User-Agent header.', + 'fn' => [__CLASS__, '_apply_user_agent'], + 'default' => [], + ], + 'idempotency_auto_fill' => [ + 'type' => 'value', + 'valid' => ['bool', 'callable'], + 'doc' => 'Set to false to disable SDK to populate parameters that enabled \'idempotencyToken\' trait with a random UUID v4 value on your behalf. Using default value \'true\' still allows parameter value to be overwritten when provided. Note: auto-fill only works when cryptographically secure random bytes generator functions(random_bytes, openssl_random_pseudo_bytes or mcrypt_create_iv) can be found. You may also provide a callable source of random bytes.', + 'default' => true, + 'fn' => [__CLASS__, '_apply_idempotency_auto_fill'] + ], + 'use_aws_shared_config_files' => [ + 'type' => 'value', + 'valid' => ['bool'], + 'doc' => 'Set to false to disable checking for shared aws config files usually located in \'~/.aws/config\' and \'~/.aws/credentials\'. This will be ignored if you set the \'profile\' setting.', + 'default' => true, + ], + ]; + + /** + * Gets an array of default client arguments, each argument containing a + * hash of the following: + * + * - type: (string, required) option type described as follows: + * - value: The default option type. + * - config: The provided value is made available in the client's + * getConfig() method. + * - valid: (array, required) Valid PHP types or class names. Note: null + * is not an allowed type. + * - required: (bool, callable) Whether or not the argument is required. + * Provide a function that accepts an array of arguments and returns a + * string to provide a custom error message. + * - default: (mixed) The default value of the argument if not provided. If + * a function is provided, then it will be invoked to provide a default + * value. The function is provided the array of options and is expected + * to return the default value of the option. The default value can be a + * closure and can not be a callable string that is not part of the + * defaultArgs array. + * - doc: (string) The argument documentation string. + * - fn: (callable) Function used to apply the argument. The function + * accepts the provided value, array of arguments by reference, and an + * event emitter. + * + * Note: Order is honored and important when applying arguments. + * + * @return array + */ + public static function getDefaultArguments() + { + return self::$defaultArgs; + } + + /** + * @param array $argDefinitions Client arguments. + */ + public function __construct(array $argDefinitions) + { + $this->argDefinitions = $argDefinitions; + } + + /** + * Resolves client configuration options and attached event listeners. + * Check for missing keys in passed arguments + * + * @param array $args Provided constructor arguments. + * @param HandlerList $list Handler list to augment. + * + * @return array Returns the array of provided options. + * @throws \InvalidArgumentException + * @see Aws\AwsClient::__construct for a list of available options. + */ + public function resolve(array $args, HandlerList $list) + { + $args['config'] = []; + foreach ($this->argDefinitions as $key => $a) { + // Add defaults, validate required values, and skip if not set. + if (!isset($args[$key])) { + if (isset($a['default'])) { + // Merge defaults in when not present. + if (is_callable($a['default']) + && ( + is_array($a['default']) + || $a['default'] instanceof \Closure + ) + ) { + $args[$key] = $a['default']($args); + } else { + $args[$key] = $a['default']; + } + } elseif (empty($a['required'])) { + continue; + } else { + $this->throwRequired($args); + } + } + + // Validate the types against the provided value. + foreach ($a['valid'] as $check) { + if (isset(self::$typeMap[$check])) { + $fn = self::$typeMap[$check]; + if ($fn($args[$key])) { + goto is_valid; + } + } elseif ($args[$key] instanceof $check) { + goto is_valid; + } + } + + $this->invalidType($key, $args[$key]); + + // Apply the value + is_valid: + if (isset($a['fn'])) { + $a['fn']($args[$key], $args, $list); + } + + if ($a['type'] === 'config') { + $args['config'][$key] = $args[$key]; + } + } + $this->_apply_client_context_params($args); + + return $args; + } + + /** + * Creates a verbose error message for an invalid argument. + * + * @param string $name Name of the argument that is missing. + * @param array $args Provided arguments + * @param bool $useRequired Set to true to show the required fn text if + * available instead of the documentation. + * @return string + */ + private function getArgMessage($name, $args = [], $useRequired = false) + { + $arg = $this->argDefinitions[$name]; + $msg = ''; + $modifiers = []; + if (isset($arg['valid'])) { + $modifiers[] = implode('|', $arg['valid']); + } + if (isset($arg['choice'])) { + $modifiers[] = 'One of ' . implode(', ', $arg['choice']); + } + if ($modifiers) { + $msg .= '(' . implode('; ', $modifiers) . ')'; + } + $msg = wordwrap("{$name}: {$msg}", 75, "\n "); + + if ($useRequired && is_callable($arg['required'])) { + $msg .= "\n\n "; + $msg .= str_replace("\n", "\n ", call_user_func($arg['required'], $args)); + } elseif (isset($arg['doc'])) { + $msg .= wordwrap("\n\n {$arg['doc']}", 75, "\n "); + } + + return $msg; + } + + /** + * Throw when an invalid type is encountered. + * + * @param string $name Name of the value being validated. + * @param mixed $provided The provided value. + * @throws \InvalidArgumentException + */ + private function invalidType($name, $provided) + { + $expected = implode('|', $this->argDefinitions[$name]['valid']); + $msg = "Invalid configuration value " + . "provided for \"{$name}\". Expected {$expected}, but got " + . describe_type($provided) . "\n\n" + . $this->getArgMessage($name); + throw new IAE($msg); + } + + /** + * Throws an exception for missing required arguments. + * + * @param array $args Passed in arguments. + * @throws \InvalidArgumentException + */ + private function throwRequired(array $args) + { + $missing = []; + foreach ($this->argDefinitions as $k => $a) { + if (empty($a['required']) + || isset($a['default']) + || isset($args[$k]) + ) { + continue; + } + $missing[] = $this->getArgMessage($k, $args, true); + } + $msg = "Missing required client configuration options: \n\n"; + $msg .= implode("\n\n", $missing); + throw new IAE($msg); + } + + public static function _apply_retries($value, array &$args, HandlerList $list) + { + // A value of 0 for the config option disables retries + if ($value) { + $config = RetryConfigProvider::unwrap($value); + + if ($config->getMode() === 'legacy') { + // # of retries is 1 less than # of attempts + $decider = RetryMiddleware::createDefaultDecider( + $config->getMaxAttempts() - 1 + ); + $list->appendSign( + Middleware::retry($decider, null, $args['stats']['retries']), + 'retry' + ); + } else { + $list->appendSign( + RetryMiddlewareV2::wrap( + $config, + ['collect_stats' => $args['stats']['retries']] + ), + 'retry' + ); + } + } + } + + public static function _apply_defaults($value, array &$args, HandlerList $list) + { + $config = ConfigModeProvider::unwrap($value); + if ($config->getMode() !== 'legacy') { + if (!isset($args['retries']) && !is_null($config->getRetryMode())) { + $args['retries'] = ['mode' => $config->getRetryMode()]; + } + if ( + !isset($args['sts_regional_endpoints']) + && !is_null($config->getStsRegionalEndpoints()) + ) { + $args['sts_regional_endpoints'] = ['mode' => $config->getStsRegionalEndpoints()]; + } + if ( + !isset($args['s3_us_east_1_regional_endpoint']) + && !is_null($config->getS3UsEast1RegionalEndpoints()) + ) { + $args['s3_us_east_1_regional_endpoint'] = ['mode' => $config->getS3UsEast1RegionalEndpoints()]; + } + + if (!isset($args['http'])) { + $args['http'] = []; + } + if ( + !isset($args['http']['connect_timeout']) + && !is_null($config->getConnectTimeoutInMillis()) + ) { + $args['http']['connect_timeout'] = $config->getConnectTimeoutInMillis() / 1000; + } + if ( + !isset($args['http']['timeout']) + && !is_null($config->getHttpRequestTimeoutInMillis()) + ) { + $args['http']['timeout'] = $config->getHttpRequestTimeoutInMillis() / 1000; + } + } + } + + public static function _apply_credentials($value, array &$args) + { + if (is_callable($value)) { + return; + } + + if ($value instanceof CredentialsInterface) { + $args['credentials'] = CredentialProvider::fromCredentials($value); + } elseif (is_array($value) + && isset($value['key']) + && isset($value['secret']) + ) { + $args['credentials'] = CredentialProvider::fromCredentials( + new Credentials( + $value['key'], + $value['secret'], + isset($value['token']) ? $value['token'] : null, + isset($value['expires']) ? $value['expires'] : null + ) + ); + } elseif ($value === false) { + $args['credentials'] = CredentialProvider::fromCredentials( + new Credentials('', '') + ); + $args['config']['signature_version'] = 'anonymous'; + } elseif ($value instanceof CacheInterface) { + $args['credentials'] = CredentialProvider::defaultProvider($args); + } else { + throw new IAE('Credentials must be an instance of ' + . 'Aws\Credentials\CredentialsInterface, an associative ' + . 'array that contains "key", "secret", and an optional "token" ' + . 'key-value pairs, a credentials provider function, or false.'); + } + } + + public static function _default_credential_provider(array $args) + { + return CredentialProvider::defaultProvider($args); + } + + public static function _apply_token($value, array &$args) + { + if (is_callable($value)) { + return; + } + + if ($value instanceof Token) { + $args['token'] = TokenProvider::fromToken($value); + } elseif (is_array($value) + && isset($value['token']) + ) { + $args['token'] = TokenProvider::fromToken( + new Token( + $value['token'], + isset($value['expires']) ? $value['expires'] : null + ) + ); + } elseif ($value instanceof CacheInterface) { + $args['token'] = TokenProvider::defaultProvider($args); + } else { + throw new IAE('Token must be an instance of ' + . 'Aws\Token\TokenInterface, an associative ' + . 'array that contains "token" and an optional "expires" ' + . 'key-value pairs, a token provider function, or false.'); + } + } + + public static function _default_token_provider(array $args) + { + return TokenProvider::defaultProvider($args); + } + + public static function _apply_csm($value, array &$args, HandlerList $list) + { + if ($value === false) { + $value = new Configuration( + false, + \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_HOST, + \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_PORT, + \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_CLIENT_ID + ); + $args['csm'] = $value; + } + + $list->appendBuild( + ApiCallMonitoringMiddleware::wrap( + $args['credentials'], + $value, + $args['region'], + $args['api']->getServiceId() + ), + 'ApiCallMonitoringMiddleware' + ); + + $list->appendAttempt( + ApiCallAttemptMonitoringMiddleware::wrap( + $args['credentials'], + $value, + $args['region'], + $args['api']->getServiceId() + ), + 'ApiCallAttemptMonitoringMiddleware' + ); + } + + public static function _apply_api_provider(callable $value, array &$args) + { + $api = new Service( + ApiProvider::resolve( + $value, + 'api', + $args['service'], + $args['version'] + ), + $value + ); + + if ( + empty($args['config']['signing_name']) + && isset($api['metadata']['signingName']) + ) { + $args['config']['signing_name'] = $api['metadata']['signingName']; + } + + $args['api'] = $api; + $args['parser'] = Service::createParser($api); + $args['error_parser'] = Service::createErrorParser($api->getProtocol(), $api); + } + + public static function _apply_endpoint_provider($value, array &$args) + { + if (!isset($args['endpoint'])) { + if ($value instanceof \Aws\EndpointV2\EndpointProviderV2) { + $options = self::getEndpointProviderOptions($args); + $value = PartitionEndpointProvider::defaultProvider($options) + ->getPartition($args['region'], $args['service']); + } + + $endpointPrefix = isset($args['api']['metadata']['endpointPrefix']) + ? $args['api']['metadata']['endpointPrefix'] + : $args['service']; + + // Check region is a valid host label when it is being used to + // generate an endpoint + if (!self::isValidRegion($args['region'])) { + throw new InvalidRegionException('Region must be a valid RFC' + . ' host label.'); + } + $serviceEndpoints = + is_array($value) && isset($value['services'][$args['service']]['endpoints']) + ? $value['services'][$args['service']]['endpoints'] + : null; + if (isset($serviceEndpoints[$args['region']]['deprecated'])) { + trigger_error("The service " . $args['service'] . "has " + . " deprecated the region " . $args['region'] . ".", + E_USER_WARNING + ); + } + + $args['region'] = \Aws\strip_fips_pseudo_regions($args['region']); + + // Invoke the endpoint provider and throw if it does not resolve. + $result = EndpointProvider::resolve($value, [ + 'service' => $endpointPrefix, + 'region' => $args['region'], + 'scheme' => $args['scheme'], + 'options' => self::getEndpointProviderOptions($args), + ]); + + $args['endpoint'] = $result['endpoint']; + + if ( + empty($args['config']['signature_version']) + && isset($result['signatureVersion']) + ) { + $args['config']['signature_version'] + = $result['signatureVersion']; + } + + if ( + empty($args['config']['signing_region']) + && isset($result['signingRegion']) + ) { + $args['config']['signing_region'] = $result['signingRegion']; + } + + if ( + empty($args['config']['signing_name']) + && isset($result['signingName']) + ) { + $args['config']['signing_name'] = $result['signingName']; + } + } + } + + public static function _apply_endpoint_discovery($value, array &$args) { + $args['endpoint_discovery'] = $value; + } + + public static function _default_endpoint_discovery_provider(array $args) + { + return ConfigurationProvider::defaultProvider($args); + } + + public static function _apply_use_fips_endpoint($value, array &$args) { + if ($value instanceof CacheInterface) { + $value = UseFipsConfigProvider::defaultProvider($args); + } + if (is_callable($value)) { + $value = $value(); + } + if ($value instanceof PromiseInterface) { + $value = $value->wait(); + } + if ($value instanceof UseFipsEndpointConfigurationInterface) { + $args['config']['use_fips_endpoint'] = $value; + } else { + // The Configuration class itself will validate other inputs + $args['config']['use_fips_endpoint'] = new UseFipsEndpointConfiguration($value); + } + } + + public static function _default_use_fips_endpoint(array &$args) { + return UseFipsConfigProvider::defaultProvider($args); + } + + public static function _apply_use_dual_stack_endpoint($value, array &$args) { + if ($value instanceof CacheInterface) { + $value = UseDualStackConfigProvider::defaultProvider($args); + } + if (is_callable($value)) { + $value = $value(); + } + if ($value instanceof PromiseInterface) { + $value = $value->wait(); + } + if ($value instanceof UseDualStackEndpointConfigurationInterface) { + $args['config']['use_dual_stack_endpoint'] = $value; + } else { + // The Configuration class itself will validate other inputs + $args['config']['use_dual_stack_endpoint'] = + new UseDualStackEndpointConfiguration($value, $args['region']); + } + } + + public static function _default_use_dual_stack_endpoint(array &$args) { + return UseDualStackConfigProvider::defaultProvider($args); + } + + public static function _apply_debug($value, array &$args, HandlerList $list) + { + if ($value !== false) { + $list->interpose( + new TraceMiddleware( + $value === true ? [] : $value, + $args['api']) + ); + } + } + + public static function _apply_stats($value, array &$args, HandlerList $list) + { + // Create an array of stat collectors that are disabled (set to false) + // by default. If the user has passed in true, enable all stat + // collectors. + $defaults = array_fill_keys( + ['http', 'retries', 'timer'], + $value === true + ); + $args['stats'] = is_array($value) + ? array_replace($defaults, $value) + : $defaults; + + if ($args['stats']['timer']) { + $list->prependInit(Middleware::timer(), 'timer'); + } + } + + public static function _apply_profile($_, array &$args) + { + $args['credentials'] = CredentialProvider::ini($args['profile']); + } + + public static function _apply_validate($value, array &$args, HandlerList $list) + { + if ($value === false) { + return; + } + + $validator = $value === true + ? new Validator() + : new Validator($value); + $list->appendValidate( + Middleware::validation($args['api'], $validator), + 'validation' + ); + } + + public static function _apply_handler($value, array &$args, HandlerList $list) + { + $list->setHandler($value); + } + + public static function _default_handler(array &$args) + { + return new WrappedHttpHandler( + default_http_handler(), + $args['parser'], + $args['error_parser'], + $args['exception_class'], + $args['stats']['http'] + ); + } + + public static function _apply_http_handler($value, array &$args, HandlerList $list) + { + $args['handler'] = new WrappedHttpHandler( + $value, + $args['parser'], + $args['error_parser'], + $args['exception_class'], + $args['stats']['http'] + ); + } + + public static function _apply_user_agent($inputUserAgent, array &$args, HandlerList $list) + { + //Add SDK version + $userAgent = ['aws-sdk-php/' . Sdk::VERSION]; + + //If on HHVM add the HHVM version + if (defined('HHVM_VERSION')) { + $userAgent []= 'HHVM/' . HHVM_VERSION; + } + + //Add OS version + $disabledFunctions = explode(',', ini_get('disable_functions')); + if (function_exists('php_uname') + && !in_array('php_uname', $disabledFunctions, true) + ) { + $osName = "OS/" . php_uname('s') . '/' . php_uname('r'); + if (!empty($osName)) { + $userAgent []= $osName; + } + } + + //Add the language version + $userAgent []= 'lang/php/' . phpversion(); + + //Add exec environment if present + if ($executionEnvironment = getenv('AWS_EXECUTION_ENV')) { + $userAgent []= $executionEnvironment; + } + + //Add the input to the end + if ($inputUserAgent){ + if (!is_array($inputUserAgent)) { + $inputUserAgent = [$inputUserAgent]; + } + $inputUserAgent = array_map('strval', $inputUserAgent); + $userAgent = array_merge($userAgent, $inputUserAgent); + } + + $args['ua_append'] = $userAgent; + + $list->appendBuild(static function (callable $handler) use ($userAgent) { + return function ( + CommandInterface $command, + RequestInterface $request + ) use ($handler, $userAgent) { + return $handler( + $command, + $request->withHeader( + 'X-Amz-User-Agent', + implode(' ', array_merge( + $userAgent, + $request->getHeader('X-Amz-User-Agent') + )) + )->withHeader( + 'User-Agent', + implode(' ', array_merge( + $userAgent, + $request->getHeader('User-Agent') + )) + ) + ); + }; + }); + } + + public static function _apply_endpoint($value, array &$args, HandlerList $list) + { + $args['endpoint'] = $value; + } + + public static function _apply_idempotency_auto_fill( + $value, + array &$args, + HandlerList $list + ) { + $enabled = false; + $generator = null; + + + if (is_bool($value)) { + $enabled = $value; + } elseif (is_callable($value)) { + $enabled = true; + $generator = $value; + } + + if ($enabled) { + $list->prependInit( + IdempotencyTokenMiddleware::wrap($args['api'], $generator), + 'idempotency_auto_fill' + ); + } + } + + public static function _default_endpoint_provider(array $args) + { + $service = isset($args['api']) ? $args['api'] : null; + $serviceName = isset($service) ? $service->getServiceName() : null; + $apiVersion = isset($service) ? $service->getApiVersion() : null; + + if (self::isValidService($serviceName) + && self::isValidApiVersion($serviceName, $apiVersion) + ) { + $ruleset = EndpointDefinitionProvider::getEndpointRuleset( + $service->getServiceName(), + $service->getApiVersion() + ); + return new \Aws\EndpointV2\EndpointProviderV2( + $ruleset, + EndpointDefinitionProvider::getPartitions() + ); + } + $options = self::getEndpointProviderOptions($args); + return PartitionEndpointProvider::defaultProvider($options) + ->getPartition($args['region'], $args['service']); + } + + public static function _default_serializer(array $args) + { + return Service::createSerializer( + $args['api'], + $args['endpoint'] + ); + } + + public static function _default_signature_provider() + { + return SignatureProvider::defaultProvider(); + } + + public static function _default_signature_version(array &$args) + { + if (isset($args['config']['signature_version'])) { + return $args['config']['signature_version']; + } + + $args['__partition_result'] = isset($args['__partition_result']) + ? isset($args['__partition_result']) + : call_user_func(PartitionEndpointProvider::defaultProvider(), [ + 'service' => $args['service'], + 'region' => $args['region'], + ]); + + return isset($args['__partition_result']['signatureVersion']) + ? $args['__partition_result']['signatureVersion'] + : $args['api']->getSignatureVersion(); + } + + public static function _default_signing_name(array &$args) + { + if (isset($args['config']['signing_name'])) { + return $args['config']['signing_name']; + } + + $args['__partition_result'] = isset($args['__partition_result']) + ? isset($args['__partition_result']) + : call_user_func(PartitionEndpointProvider::defaultProvider(), [ + 'service' => $args['service'], + 'region' => $args['region'], + ]); + + if (isset($args['__partition_result']['signingName'])) { + return $args['__partition_result']['signingName']; + } + + if ($signingName = $args['api']->getSigningName()) { + return $signingName; + } + + return $args['service']; + } + + public static function _default_signing_region(array &$args) + { + if (isset($args['config']['signing_region'])) { + return $args['config']['signing_region']; + } + + $args['__partition_result'] = isset($args['__partition_result']) + ? isset($args['__partition_result']) + : call_user_func(PartitionEndpointProvider::defaultProvider(), [ + 'service' => $args['service'], + 'region' => $args['region'], + ]); + + return isset($args['__partition_result']['signingRegion']) + ? $args['__partition_result']['signingRegion'] + : $args['region']; + } + + public static function _missing_version(array $args) + { + $service = isset($args['service']) ? $args['service'] : ''; + $versions = ApiProvider::defaultProvider()->getVersions($service); + $versions = implode("\n", array_map(function ($v) { + return "* \"$v\""; + }, $versions)) ?: '* (none found)'; + + return <<<EOT +A "version" configuration value is required. Specifying a version constraint +ensures that your code will not be affected by a breaking change made to the +service. For example, when using Amazon S3, you can lock your API version to +"2006-03-01". + +Your build of the SDK has the following version(s) of "{$service}": {$versions} + +You may provide "latest" to the "version" configuration value to utilize the +most recent available API version that your client's API provider can find. +Note: Using 'latest' in a production application is not recommended. + +A list of available API versions can be found on each client's API documentation +page: http://docs.aws.amazon.com/aws-sdk-php/v3/api/index.html. If you are +unable to load a specific API version, then you may need to update your copy of +the SDK. +EOT; + } + + public static function _missing_region(array $args) + { + $service = isset($args['service']) ? $args['service'] : ''; + + return <<<EOT +A "region" configuration value is required for the "{$service}" service +(e.g., "us-west-2"). A list of available public regions and endpoints can be +found at http://docs.aws.amazon.com/general/latest/gr/rande.html. +EOT; + } + + /** + * Extracts client options for the endpoint provider to its own array + * + * @param array $args + * @return array + */ + private static function getEndpointProviderOptions(array $args) + { + $options = []; + $optionKeys = [ + 'sts_regional_endpoints', + 's3_us_east_1_regional_endpoint', + ]; + $configKeys = [ + 'use_dual_stack_endpoint', + 'use_fips_endpoint', + ]; + foreach ($optionKeys as $key) { + if (isset($args[$key])) { + $options[$key] = $args[$key]; + } + } + foreach ($configKeys as $key) { + if (isset($args['config'][$key])) { + $options[$key] = $args['config'][$key]; + } + } + return $options; + } + + /** + * Validates a region to be used for endpoint construction + * + * @param $region + * @return bool + */ + private static function isValidRegion($region) + { + return is_valid_hostlabel($region); + } + + private function _apply_client_context_params(array $args) + { + if (isset($args['api']) + && !empty($args['api']->getClientContextParams())) + { + $clientContextParams = $args['api']->getClientContextParams(); + foreach($clientContextParams as $paramName => $paramDefinition) { + $definition = [ + 'type' => 'value', + 'valid' => [$paramDefinition['type']], + 'doc' => isset($paramDefinition['documentation']) ? + $paramDefinition['documentation'] : null + ]; + $this->argDefinitions[$paramName] = $definition; + + if (isset($args[$paramName])) { + $fn = self::$typeMap[$paramDefinition['type']]; + if (!$fn($args[$paramName])) { + $this->invalidType($paramName, $args[$paramName]); + } + } + } + } + } + + private static function isValidService($service) { + if (is_null($service)) { + return false; + } + $services = \Aws\manifest(); + return isset($services[$service]); + } + + private static function isValidApiVersion($service, $apiVersion) { + if (is_null($apiVersion)) { + return false; + } + return is_dir( + __DIR__ . "/data/{$service}/$apiVersion" + ); + } +} |