Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws;
3
 
4
use Aws\Api\ApiProvider;
5
use Aws\Api\Service;
6
use Aws\Api\Validator;
1441 ariadna 7
use Aws\Auth\AuthResolver;
8
use Aws\Auth\AuthSchemeResolver;
9
use Aws\Auth\AuthSchemeResolverInterface;
1 efrain 10
use Aws\ClientSideMonitoring\ApiCallAttemptMonitoringMiddleware;
11
use Aws\ClientSideMonitoring\ApiCallMonitoringMiddleware;
12
use Aws\ClientSideMonitoring\Configuration;
13
use Aws\Configuration\ConfigurationResolver;
14
use Aws\Credentials\CredentialProvider;
15
use Aws\Credentials\Credentials;
16
use Aws\Credentials\CredentialsInterface;
17
use Aws\DefaultsMode\ConfigurationInterface as ConfigModeInterface;
18
use Aws\DefaultsMode\ConfigurationProvider as ConfigModeProvider;
19
use Aws\Endpoint\EndpointProvider;
20
use Aws\Endpoint\PartitionEndpointProvider;
21
use Aws\Endpoint\UseDualstackEndpoint\Configuration as UseDualStackEndpointConfiguration;
22
use Aws\Endpoint\UseDualstackEndpoint\ConfigurationInterface as UseDualStackEndpointConfigurationInterface;
23
use Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider as UseDualStackConfigProvider;
24
use Aws\Endpoint\UseFipsEndpoint\Configuration as UseFipsEndpointConfiguration;
25
use Aws\Endpoint\UseFipsEndpoint\ConfigurationInterface as UseFipsEndpointConfigurationInterface;
26
use Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider as UseFipsConfigProvider;
27
use Aws\EndpointDiscovery\ConfigurationInterface;
28
use Aws\EndpointDiscovery\ConfigurationProvider;
29
use Aws\EndpointV2\EndpointDefinitionProvider;
30
use Aws\Exception\AwsException;
31
use Aws\Exception\InvalidRegionException;
32
use Aws\Retry\ConfigurationInterface as RetryConfigInterface;
33
use Aws\Retry\ConfigurationProvider as RetryConfigProvider;
34
use Aws\Signature\SignatureProvider;
35
use Aws\Token\Token;
36
use Aws\Token\TokenInterface;
37
use Aws\Token\TokenProvider;
38
use GuzzleHttp\Promise\PromiseInterface;
39
use InvalidArgumentException as IAE;
40
use Psr\Http\Message\RequestInterface;
41
 
42
/**
43
 * @internal Resolves a hash of client arguments to construct a client.
44
 */
45
class ClientResolver
46
{
47
    /** @var array */
48
    private $argDefinitions;
49
 
1441 ariadna 50
    /**
51
     * When using this option as default please make sure that, your config
52
     * has at least one data type defined in `valid` otherwise it will be
53
     * defaulted to `string`. Also, the default value will be the falsy value
54
     * based on the resolved data type. For example, the default for `string`
55
     * will be `''` and for bool will be `false`.
56
     *
57
     * @var string
58
     */
59
    const DEFAULT_FROM_ENV_INI = [
60
        __CLASS__,
61
        '_resolve_from_env_ini'
62
    ];
63
 
1 efrain 64
    /** @var array Map of types to a corresponding function */
65
    private static $typeMap = [
66
        'resource' => 'is_resource',
67
        'callable' => 'is_callable',
68
        'int'      => 'is_int',
69
        'bool'     => 'is_bool',
70
        'boolean'  => 'is_bool',
71
        'string'   => 'is_string',
72
        'object'   => 'is_object',
73
        'array'    => 'is_array',
74
    ];
75
 
76
    private static $defaultArgs = [
77
        'service' => [
78
            'type'     => 'value',
79
            'valid'    => ['string'],
80
            '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).',
81
            'required' => true,
82
            'internal' => true
83
        ],
84
        'exception_class' => [
85
            'type'     => 'value',
86
            'valid'    => ['string'],
87
            'doc'      => 'Exception class to create when an error occurs.',
88
            'default'  => AwsException::class,
89
            'internal' => true
90
        ],
91
        'scheme' => [
92
            'type'     => 'value',
93
            'valid'    => ['string'],
94
            'default'  => 'https',
95
            '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".',
96
        ],
97
        'disable_host_prefix_injection' => [
98
            'type'      => 'value',
99
            'valid'     => ['bool'],
100
            '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.',
101
            'default'   => false,
102
        ],
1441 ariadna 103
        'ignore_configured_endpoint_urls' => [
104
            'type'      => 'value',
105
            'valid'     => ['bool'],
106
            'doc'       => 'Set to true to disable endpoint urls configured using `AWS_ENDPOINT_URL` and `endpoint_url` shared config option.',
107
            'fn'        => [__CLASS__, '_apply_ignore_configured_endpoint_urls'],
108
            'default'   => self::DEFAULT_FROM_ENV_INI,
109
        ],
1 efrain 110
        'endpoint' => [
111
            'type'  => 'value',
112
            'valid' => ['string'],
113
            'doc'   => 'The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of S3).',
114
            'fn'    => [__CLASS__, '_apply_endpoint'],
1441 ariadna 115
            'default'   => [__CLASS__, '_default_endpoint']
1 efrain 116
        ],
117
        'region' => [
118
            'type'     => 'value',
119
            'valid'    => ['string'],
120
            'doc'      => 'Region to connect to. See http://docs.aws.amazon.com/general/latest/gr/rande.html for a list of available regions.',
1441 ariadna 121
            'fn'       => [__CLASS__, '_apply_region'],
122
            'default'  => self::DEFAULT_FROM_ENV_INI
1 efrain 123
        ],
124
        'version' => [
125
            'type'     => 'value',
126
            'valid'    => ['string'],
127
            'doc'      => 'The version of the webservice to utilize (e.g., 2006-03-01).',
128
            'default' => 'latest',
129
        ],
130
        'signature_provider' => [
131
            'type'    => 'value',
132
            'valid'   => ['callable'],
133
            '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',
134
            'default' => [__CLASS__, '_default_signature_provider'],
135
        ],
136
        'api_provider' => [
137
            'type'     => 'value',
138
            'valid'    => ['callable'],
139
            '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.',
140
            'fn'       => [__CLASS__, '_apply_api_provider'],
141
            'default'  => [ApiProvider::class, 'defaultProvider'],
142
        ],
143
        'configuration_mode' => [
144
            'type'    => 'value',
145
            'valid'   => [ConfigModeInterface::class, CacheInterface::class, 'string', 'closure'],
146
            '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",
147
            'fn'      => [__CLASS__, '_apply_defaults'],
148
            'default' => [ConfigModeProvider::class, 'defaultProvider']
149
        ],
150
        'use_fips_endpoint' => [
151
            'type'      => 'value',
152
            'valid'     => ['bool', UseFipsEndpointConfiguration::class, CacheInterface::class, 'callable'],
153
            'doc'       => 'Set to true to enable the use of FIPS pseudo regions',
154
            'fn'        => [__CLASS__, '_apply_use_fips_endpoint'],
155
            'default'   => [__CLASS__, '_default_use_fips_endpoint'],
156
        ],
157
        'use_dual_stack_endpoint' => [
158
            'type'      => 'value',
159
            'valid'     => ['bool', UseDualStackEndpointConfiguration::class, CacheInterface::class, 'callable'],
160
            'doc'       => 'Set to true to enable the use of dual-stack endpoints',
161
            'fn'        => [__CLASS__, '_apply_use_dual_stack_endpoint'],
162
            'default'   => [__CLASS__, '_default_use_dual_stack_endpoint'],
163
        ],
164
        'endpoint_provider' => [
165
            'type'     => 'value',
166
            'valid'    => ['callable', EndpointV2\EndpointProviderV2::class],
167
            'fn'       => [__CLASS__, '_apply_endpoint_provider'],
168
            '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.',
169
            'default'  => [__CLASS__, '_default_endpoint_provider'],
170
        ],
171
        'serializer' => [
172
            'default'   => [__CLASS__, '_default_serializer'],
1441 ariadna 173
            'fn'        => [__CLASS__, '_apply_serializer'],
1 efrain 174
            'internal'  => true,
175
            'type'      => 'value',
176
            'valid'     => ['callable'],
177
        ],
178
        'signature_version' => [
179
            'type'    => 'config',
180
            'valid'   => ['string'],
181
            '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.',
182
            'default' => [__CLASS__, '_default_signature_version'],
183
        ],
184
        'signing_name' => [
185
            'type'    => 'config',
186
            'valid'   => ['string'],
187
            'doc'     => 'A string representing a custom service name to be used when calculating a request signature.',
188
            'default' => [__CLASS__, '_default_signing_name'],
189
        ],
190
        'signing_region' => [
191
            'type'    => 'config',
192
            'valid'   => ['string'],
193
            'doc'     => 'A string representing a custom region name to be used when calculating a request signature.',
194
            'default' => [__CLASS__, '_default_signing_region'],
195
        ],
196
        'profile' => [
197
            'type'  => 'config',
198
            'valid' => ['string'],
199
            '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.',
200
            'fn'    => [__CLASS__, '_apply_profile'],
201
        ],
202
        'credentials' => [
203
            'type'    => 'value',
204
            'valid'   => [CredentialsInterface::class, CacheInterface::class, 'array', 'bool', 'callable'],
205
            '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.',
206
            'fn'      => [__CLASS__, '_apply_credentials'],
207
            'default' => [__CLASS__, '_default_credential_provider'],
208
        ],
209
        'token' => [
210
            'type'    => 'value',
211
            'valid'   => [TokenInterface::class, CacheInterface::class, 'array', 'bool', 'callable'],
212
            '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.',
213
            'fn'      => [__CLASS__, '_apply_token'],
214
            'default' => [__CLASS__, '_default_token_provider'],
215
        ],
1441 ariadna 216
        'auth_scheme_resolver' => [
217
            'type'    => 'value',
218
            'valid'   => [AuthSchemeResolverInterface::class],
219
            'doc'     => 'An instance of Aws\Auth\AuthSchemeResolverInterface which selects a modeled auth scheme and returns a signature version',
220
            'default' => [__CLASS__, '_default_auth_scheme_resolver'],
221
        ],
1 efrain 222
        'endpoint_discovery' => [
223
            'type'     => 'value',
224
            'valid'    => [ConfigurationInterface::class, CacheInterface::class, 'array', 'callable'],
225
            '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.',
226
            'fn'       => [__CLASS__, '_apply_endpoint_discovery'],
227
            'default'  => [__CLASS__, '_default_endpoint_discovery_provider']
228
        ],
229
        'stats' => [
230
            'type'  => 'value',
231
            'valid' => ['bool', 'array'],
232
            'default' => false,
233
            '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.',
234
            'fn'    => [__CLASS__, '_apply_stats'],
235
        ],
236
        'retries' => [
237
            'type'    => 'value',
238
            'valid'   => ['int', RetryConfigInterface::class, CacheInterface::class, 'callable', 'array'],
239
            '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. ",
240
            'fn'      => [__CLASS__, '_apply_retries'],
241
            'default' => [RetryConfigProvider::class, 'defaultProvider']
242
        ],
243
        'validate' => [
244
            'type'    => 'value',
245
            'valid'   => ['bool', 'array'],
246
            'default' => true,
247
            '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.',
248
            'fn'      => [__CLASS__, '_apply_validate'],
249
        ],
250
        'debug' => [
251
            'type'  => 'value',
252
            'valid' => ['bool', 'array'],
253
            '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).',
254
            'fn'    => [__CLASS__, '_apply_debug'],
255
        ],
256
        'disable_request_compression' => [
257
            'type'      => 'value',
258
            'valid'     => ['bool', 'callable'],
259
            'doc'       => 'Set to true to disable request compression for supported operations',
260
            'fn'        => [__CLASS__, '_apply_disable_request_compression'],
1441 ariadna 261
            'default'   => self::DEFAULT_FROM_ENV_INI,
1 efrain 262
        ],
263
        'request_min_compression_size_bytes' => [
264
            'type'      => 'value',
265
            'valid'     => ['int', 'callable'],
266
            'doc'       => 'Set to a value between between 0 and 10485760 bytes, inclusive. This value will be ignored if `disable_request_compression` is set to `true`',
267
            'fn'        => [__CLASS__, '_apply_min_compression_size'],
268
            'default'   => [__CLASS__, '_default_min_compression_size'],
269
        ],
270
        'csm' => [
271
            'type'     => 'value',
272
            'valid'    => [\Aws\ClientSideMonitoring\ConfigurationInterface::class, 'callable', 'array', 'bool'],
273
            '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".',
274
            'fn'       => [__CLASS__, '_apply_csm'],
275
            'default'  => [\Aws\ClientSideMonitoring\ConfigurationProvider::class, 'defaultProvider']
276
        ],
277
        'http' => [
278
            'type'    => 'value',
279
            'valid'   => ['array'],
280
            'default' => [],
281
            'doc'     => 'Set to an array of SDK request options to apply to each request (e.g., proxy, verify, etc.).',
282
        ],
283
        'http_handler' => [
284
            'type'    => 'value',
285
            'valid'   => ['callable'],
286
            '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.',
287
            'fn'      => [__CLASS__, '_apply_http_handler']
288
        ],
289
        'handler' => [
290
            'type'     => 'value',
291
            'valid'    => ['callable'],
292
            '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.',
293
            'fn'       => [__CLASS__, '_apply_handler'],
294
            'default'  => [__CLASS__, '_default_handler']
295
        ],
1441 ariadna 296
        'app_id' => [
297
            'type' => 'value',
298
            'valid' => ['string'],
299
            'doc' => 'app_id(AppId) is an optional application specific identifier that can be set.
300
             When set it will be appended to the User-Agent header of every request in the form of App/{AppId}.
301
             This value is also sourced from environment variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.',
302
            'fn' => [__CLASS__, '_apply_app_id'],
303
            'default' => [__CLASS__, '_default_app_id']
304
        ],
1 efrain 305
        'ua_append' => [
306
            'type'     => 'value',
307
            'valid'    => ['string', 'array'],
308
            'doc'      => 'Provide a string or array of strings to send in the User-Agent header.',
309
            'fn'       => [__CLASS__, '_apply_user_agent'],
310
            'default'  => [],
311
        ],
312
        'idempotency_auto_fill' => [
313
            'type'      => 'value',
314
            'valid'     => ['bool', 'callable'],
315
            '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.',
316
            'default'   => true,
317
            'fn'        => [__CLASS__, '_apply_idempotency_auto_fill']
318
        ],
319
        'use_aws_shared_config_files' => [
320
            'type'      => 'value',
321
            'valid'     => ['bool'],
322
            '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.',
323
            'default'   => true,
324
        ],
325
        'suppress_php_deprecation_warning' => [
326
            'type'      => 'value',
327
            'valid'     => ['bool'],
1441 ariadna 328
            'doc' => 'Set to true to suppress PHP runtime deprecation warnings. The current deprecation campaign is PHP versions 8.0.x and below, taking effect on 1/13/2025.',
329
            'default' => false,
330
            'fn' => [__CLASS__, '_apply_suppress_php_deprecation_warning']
1 efrain 331
        ],
1441 ariadna 332
        'account_id_endpoint_mode' => [
333
            'type'      => 'value',
334
            'valid'     => ['string'],
335
            'doc'       => 'Decides whether account_id must a be a required resolved credentials property. If this configuration is set to disabled, then account_id is not required. If set to preferred a warning will be logged when account_id is not resolved, and when set to required an exception will be thrown if account_id is not resolved.',
336
            'default'  => [__CLASS__, '_default_account_id_endpoint_mode'],
337
            'fn'       => [__CLASS__, '_apply_account_id_endpoint_mode']
338
        ],
339
        'sigv4a_signing_region_set' => [
340
            'type' => 'value',
341
            'valid' => ['string', 'array'],
342
            'doc' => 'A comma-delimited list of supported regions sent in sigv4a requests.',
343
            'fn' => [__CLASS__, '_apply_sigv4a_signing_region_set'],
344
            'default' => self::DEFAULT_FROM_ENV_INI
345
        ]
1 efrain 346
    ];
347
 
348
    /**
349
     * Gets an array of default client arguments, each argument containing a
350
     * hash of the following:
351
     *
352
     * - type: (string, required) option type described as follows:
353
     *   - value: The default option type.
354
     *   - config: The provided value is made available in the client's
355
     *     getConfig() method.
356
     * - valid: (array, required) Valid PHP types or class names. Note: null
357
     *   is not an allowed type.
358
     * - required: (bool, callable) Whether or not the argument is required.
359
     *   Provide a function that accepts an array of arguments and returns a
360
     *   string to provide a custom error message.
361
     * - default: (mixed) The default value of the argument if not provided. If
362
     *   a function is provided, then it will be invoked to provide a default
363
     *   value. The function is provided the array of options and is expected
364
     *   to return the default value of the option. The default value can be a
365
     *   closure and can not be a callable string that is not  part of the
366
     *   defaultArgs array.
367
     * - doc: (string) The argument documentation string.
368
     * - fn: (callable) Function used to apply the argument. The function
369
     *   accepts the provided value, array of arguments by reference, and an
370
     *   event emitter.
371
     *
372
     * Note: Order is honored and important when applying arguments.
373
     *
374
     * @return array
375
     */
376
    public static function getDefaultArguments()
377
    {
378
        return self::$defaultArgs;
379
    }
380
 
381
    /**
382
     * @param array $argDefinitions Client arguments.
383
     */
384
    public function __construct(array $argDefinitions)
385
    {
386
        $this->argDefinitions = $argDefinitions;
387
    }
388
 
389
    /**
390
     * Resolves client configuration options and attached event listeners.
391
     * Check for missing keys in passed arguments
392
     *
393
     * @param array       $args Provided constructor arguments.
394
     * @param HandlerList $list Handler list to augment.
395
     *
396
     * @return array Returns the array of provided options.
397
     * @throws \InvalidArgumentException
398
     * @see Aws\AwsClient::__construct for a list of available options.
399
     */
400
    public function resolve(array $args, HandlerList $list)
401
    {
402
        $args['config'] = [];
403
        foreach ($this->argDefinitions as $key => $a) {
404
            // Add defaults, validate required values, and skip if not set.
405
            if (!isset($args[$key])) {
406
                if (isset($a['default'])) {
407
                    // Merge defaults in when not present.
408
                    if (is_callable($a['default'])
409
                        && (
410
                            is_array($a['default'])
411
                            || $a['default'] instanceof \Closure
412
                        )
413
                    ) {
1441 ariadna 414
                        if ($a['default'] === self::DEFAULT_FROM_ENV_INI) {
415
                            $args[$key] = $a['default'](
416
                                $key,
417
                                $a['valid'][0] ?? 'string',
418
                                $args
419
                            );
420
                        } else {
421
                            $args[$key] = $a['default']($args);
422
                        }
1 efrain 423
                    } else {
424
                        $args[$key] = $a['default'];
425
                    }
426
                } elseif (empty($a['required'])) {
427
                    continue;
428
                } else {
429
                    $this->throwRequired($args);
430
                }
431
            }
432
 
433
            // Validate the types against the provided value.
434
            foreach ($a['valid'] as $check) {
435
                if (isset(self::$typeMap[$check])) {
436
                    $fn = self::$typeMap[$check];
437
                    if ($fn($args[$key])) {
438
                        goto is_valid;
439
                    }
440
                } elseif ($args[$key] instanceof $check) {
441
                    goto is_valid;
442
                }
443
            }
444
 
445
            $this->invalidType($key, $args[$key]);
446
 
447
            // Apply the value
448
            is_valid:
449
            if (isset($a['fn'])) {
450
                $a['fn']($args[$key], $args, $list);
451
            }
452
 
453
            if ($a['type'] === 'config') {
454
                $args['config'][$key] = $args[$key];
455
            }
456
        }
457
        $this->_apply_client_context_params($args);
458
 
459
        return $args;
460
    }
461
 
462
    /**
463
     * Creates a verbose error message for an invalid argument.
464
     *
465
     * @param string $name        Name of the argument that is missing.
466
     * @param array  $args        Provided arguments
467
     * @param bool   $useRequired Set to true to show the required fn text if
468
     *                            available instead of the documentation.
469
     * @return string
470
     */
471
    private function getArgMessage($name, $args = [], $useRequired = false)
472
    {
473
        $arg = $this->argDefinitions[$name];
474
        $msg = '';
475
        $modifiers = [];
476
        if (isset($arg['valid'])) {
477
            $modifiers[] = implode('|', $arg['valid']);
478
        }
479
        if (isset($arg['choice'])) {
480
            $modifiers[] = 'One of ' . implode(', ', $arg['choice']);
481
        }
482
        if ($modifiers) {
483
            $msg .= '(' . implode('; ', $modifiers) . ')';
484
        }
485
        $msg = wordwrap("{$name}: {$msg}", 75, "\n  ");
486
 
487
        if ($useRequired && is_callable($arg['required'])) {
488
            $msg .= "\n\n  ";
489
            $msg .= str_replace("\n", "\n  ", call_user_func($arg['required'], $args));
490
        } elseif (isset($arg['doc'])) {
491
            $msg .= wordwrap("\n\n  {$arg['doc']}", 75, "\n  ");
492
        }
493
 
494
        return $msg;
495
    }
496
 
497
    /**
498
     * Throw when an invalid type is encountered.
499
     *
500
     * @param string $name     Name of the value being validated.
501
     * @param mixed  $provided The provided value.
502
     * @throws \InvalidArgumentException
503
     */
504
    private function invalidType($name, $provided)
505
    {
506
        $expected = implode('|', $this->argDefinitions[$name]['valid']);
507
        $msg = "Invalid configuration value "
508
            . "provided for \"{$name}\". Expected {$expected}, but got "
509
            . describe_type($provided) . "\n\n"
510
            . $this->getArgMessage($name);
511
        throw new IAE($msg);
512
    }
513
 
514
    /**
515
     * Throws an exception for missing required arguments.
516
     *
517
     * @param array $args Passed in arguments.
518
     * @throws \InvalidArgumentException
519
     */
520
    private function throwRequired(array $args)
521
    {
522
        $missing = [];
523
        foreach ($this->argDefinitions as $k => $a) {
524
            if (empty($a['required'])
525
                || isset($a['default'])
526
                || isset($args[$k])
527
            ) {
528
                continue;
529
            }
530
            $missing[] = $this->getArgMessage($k, $args, true);
531
        }
532
        $msg = "Missing required client configuration options: \n\n";
533
        $msg .= implode("\n\n", $missing);
534
        throw new IAE($msg);
535
    }
536
 
537
    public static function _apply_retries($value, array &$args, HandlerList $list)
538
    {
539
        // A value of 0 for the config option disables retries
540
        if ($value) {
541
            $config = RetryConfigProvider::unwrap($value);
542
 
543
            if ($config->getMode() === 'legacy') {
544
                // # of retries is 1 less than # of attempts
545
                $decider = RetryMiddleware::createDefaultDecider(
546
                    $config->getMaxAttempts() - 1
547
                );
548
                $list->appendSign(
549
                    Middleware::retry($decider, null, $args['stats']['retries']),
550
                    'retry'
551
                );
552
            } else {
553
                $list->appendSign(
554
                    RetryMiddlewareV2::wrap(
555
                        $config,
556
                        ['collect_stats' => $args['stats']['retries']]
557
                    ),
558
                    'retry'
559
                );
560
            }
561
        }
562
    }
563
 
564
    public static function _apply_defaults($value, array &$args, HandlerList $list)
565
    {
566
        $config = ConfigModeProvider::unwrap($value);
567
        if ($config->getMode() !== 'legacy') {
568
            if (!isset($args['retries']) && !is_null($config->getRetryMode())) {
569
                $args['retries'] = ['mode' => $config->getRetryMode()];
570
            }
571
            if (
572
                !isset($args['sts_regional_endpoints'])
573
                && !is_null($config->getStsRegionalEndpoints())
574
            ) {
575
                $args['sts_regional_endpoints'] = ['mode' => $config->getStsRegionalEndpoints()];
576
            }
577
            if (
578
                !isset($args['s3_us_east_1_regional_endpoint'])
579
                && !is_null($config->getS3UsEast1RegionalEndpoints())
580
            ) {
581
                $args['s3_us_east_1_regional_endpoint'] = ['mode' => $config->getS3UsEast1RegionalEndpoints()];
582
            }
583
 
584
            if (!isset($args['http'])) {
585
                $args['http'] = [];
586
            }
587
            if (
588
                !isset($args['http']['connect_timeout'])
589
                && !is_null($config->getConnectTimeoutInMillis())
590
            ) {
591
                $args['http']['connect_timeout'] = $config->getConnectTimeoutInMillis() / 1000;
592
            }
593
            if (
594
                !isset($args['http']['timeout'])
595
                && !is_null($config->getHttpRequestTimeoutInMillis())
596
            ) {
597
                $args['http']['timeout'] = $config->getHttpRequestTimeoutInMillis() / 1000;
598
            }
599
        }
600
    }
601
 
602
    public static function _apply_disable_request_compression($value, array &$args) {
603
        if (is_callable($value)) {
604
            $value = $value();
605
        }
606
        if (!is_bool($value)) {
1441 ariadna 607
            throw new IAE(
608
                "Invalid configuration value provided for 'disable_request_compression'."
609
                . " value must be a bool."
610
            );
1 efrain 611
        }
612
        $args['config']['disable_request_compression'] = $value;
613
    }
614
 
615
    public static function _apply_min_compression_size($value, array &$args) {
616
        if (is_callable($value)) {
617
            $value = $value();
618
        }
619
        if (!is_int($value)
620
            || (is_int($value)
1441 ariadna 621
                && ($value < 0 || $value > 10485760))
1 efrain 622
        ) {
623
            throw new IAE(" Invalid configuration value provided for 'min_compression_size_bytes'."
1441 ariadna 624
                . " value must be an integer between 0 and 10485760, inclusive.");
1 efrain 625
        }
626
        $args['config']['request_min_compression_size_bytes'] = $value;
627
    }
628
 
629
    public static function _default_min_compression_size(array &$args) {
630
        return ConfigurationResolver::resolve(
631
            'request_min_compression_size_bytes',
632
            10240,
633
            'int',
634
            $args
635
        );
636
    }
637
 
638
    public static function _apply_credentials($value, array &$args)
639
    {
640
        if (is_callable($value)) {
641
            return;
642
        }
643
 
644
        if ($value instanceof CredentialsInterface) {
645
            $args['credentials'] = CredentialProvider::fromCredentials($value);
646
        } elseif (is_array($value)
647
            && isset($value['key'])
648
            && isset($value['secret'])
649
        ) {
650
            $args['credentials'] = CredentialProvider::fromCredentials(
651
                new Credentials(
652
                    $value['key'],
653
                    $value['secret'],
1441 ariadna 654
                    $value['token'] ?? null,
655
                    $value['expires'] ?? null,
656
                    $value['accountId'] ?? null
1 efrain 657
                )
658
            );
659
        } elseif ($value === false) {
660
            $args['credentials'] = CredentialProvider::fromCredentials(
661
                new Credentials('', '')
662
            );
663
            $args['config']['signature_version'] = 'anonymous';
1441 ariadna 664
            $args['config']['configured_signature_version'] = true;
1 efrain 665
        } elseif ($value instanceof CacheInterface) {
666
            $args['credentials'] = CredentialProvider::defaultProvider($args);
667
        } else {
668
            throw new IAE('Credentials must be an instance of '
669
                . "'" . CredentialsInterface::class . ', an associative '
670
                . 'array that contains "key", "secret", and an optional "token" '
671
                . 'key-value pairs, a credentials provider function, or false.');
672
        }
673
    }
674
 
675
    public static function _default_credential_provider(array $args)
676
    {
677
        return CredentialProvider::defaultProvider($args);
678
    }
679
 
680
    public static function _apply_token($value, array &$args)
681
    {
682
        if (is_callable($value)) {
683
            return;
684
        }
685
 
686
        if ($value instanceof Token) {
687
            $args['token'] = TokenProvider::fromToken($value);
688
        } elseif (is_array($value)
689
            && isset($value['token'])
690
        ) {
691
            $args['token'] = TokenProvider::fromToken(
692
                new Token(
693
                    $value['token'],
1441 ariadna 694
                    $value['expires'] ?? null
1 efrain 695
                )
696
            );
697
        } elseif ($value instanceof CacheInterface) {
698
            $args['token'] = TokenProvider::defaultProvider($args);
699
        } else {
700
            throw new IAE('Token must be an instance of '
701
                . TokenInterface::class . ', an associative '
702
                . 'array that contains "token" and an optional "expires" '
703
                . 'key-value pairs, a token provider function, or false.');
704
        }
705
    }
706
 
707
    public static function _default_token_provider(array $args)
708
    {
709
        return TokenProvider::defaultProvider($args);
710
    }
711
 
712
    public static function _apply_csm($value, array &$args, HandlerList $list)
713
    {
714
        if ($value === false) {
715
            $value = new Configuration(
716
                false,
717
                \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_HOST,
718
                \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_PORT,
719
                \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_CLIENT_ID
720
            );
721
            $args['csm'] = $value;
722
        }
723
 
724
        $list->appendBuild(
725
            ApiCallMonitoringMiddleware::wrap(
726
                $args['credentials'],
727
                $value,
728
                $args['region'],
729
                $args['api']->getServiceId()
730
            ),
731
            'ApiCallMonitoringMiddleware'
732
        );
733
 
734
        $list->appendAttempt(
735
            ApiCallAttemptMonitoringMiddleware::wrap(
736
                $args['credentials'],
737
                $value,
738
                $args['region'],
739
                $args['api']->getServiceId()
740
            ),
741
            'ApiCallAttemptMonitoringMiddleware'
742
        );
743
    }
744
 
745
    public static function _apply_api_provider(callable $value, array &$args)
746
    {
747
        $api = new Service(
748
            ApiProvider::resolve(
749
                $value,
750
                'api',
751
                $args['service'],
752
                $args['version']
753
            ),
754
            $value
755
        );
756
 
757
        if (
758
            empty($args['config']['signing_name'])
759
            && isset($api['metadata']['signingName'])
760
        ) {
761
            $args['config']['signing_name'] = $api['metadata']['signingName'];
762
        }
763
 
764
        $args['api'] = $api;
765
        $args['parser'] = Service::createParser($api);
766
        $args['error_parser'] = Service::createErrorParser($api->getProtocol(), $api);
767
    }
768
 
769
    public static function _apply_endpoint_provider($value, array &$args)
770
    {
771
        if (!isset($args['endpoint'])) {
772
            if ($value instanceof \Aws\EndpointV2\EndpointProviderV2) {
773
                $options = self::getEndpointProviderOptions($args);
774
                $value = PartitionEndpointProvider::defaultProvider($options)
775
                    ->getPartition($args['region'], $args['service']);
776
            }
777
 
1441 ariadna 778
            $endpointPrefix = $args['api']['metadata']['endpointPrefix'] ?? $args['service'];
1 efrain 779
 
780
            // Check region is a valid host label when it is being used to
781
            // generate an endpoint
782
            if (!self::isValidRegion($args['region'])) {
783
                throw new InvalidRegionException('Region must be a valid RFC'
784
                    . ' host label.');
785
            }
786
            $serviceEndpoints =
787
                is_array($value) && isset($value['services'][$args['service']]['endpoints'])
788
                    ? $value['services'][$args['service']]['endpoints']
789
                    : null;
790
            if (isset($serviceEndpoints[$args['region']]['deprecated'])) {
791
                trigger_error("The service " . $args['service'] . "has "
792
                    . " deprecated the region " . $args['region'] . ".",
793
                    E_USER_WARNING
794
                );
795
            }
796
 
797
            $args['region'] = \Aws\strip_fips_pseudo_regions($args['region']);
798
 
799
            // Invoke the endpoint provider and throw if it does not resolve.
800
            $result = EndpointProvider::resolve($value, [
801
                'service' => $endpointPrefix,
802
                'region'  => $args['region'],
803
                'scheme'  => $args['scheme'],
804
                'options' => self::getEndpointProviderOptions($args),
805
            ]);
806
 
807
            $args['endpoint'] = $result['endpoint'];
808
 
809
            if (empty($args['config']['signature_version'])) {
810
                if (
811
                    isset($args['api'])
812
                    && $args['api']->getSignatureVersion() == 'bearer'
813
                ) {
814
                    $args['config']['signature_version'] = 'bearer';
815
                } elseif (isset($result['signatureVersion'])) {
816
                    $args['config']['signature_version'] = $result['signatureVersion'];
817
                }
818
            }
819
 
820
            if (
821
                empty($args['config']['signing_region'])
822
                && isset($result['signingRegion'])
823
            ) {
824
                $args['config']['signing_region'] = $result['signingRegion'];
825
            }
826
 
827
            if (
828
                empty($args['config']['signing_name'])
829
                && isset($result['signingName'])
830
            ) {
831
                $args['config']['signing_name'] = $result['signingName'];
832
            }
833
        }
834
    }
835
 
836
    public static function _apply_endpoint_discovery($value, array &$args) {
837
        $args['endpoint_discovery'] = $value;
838
    }
839
 
840
    public static function _default_endpoint_discovery_provider(array $args)
841
    {
842
        return ConfigurationProvider::defaultProvider($args);
843
    }
844
 
845
    public static function _apply_use_fips_endpoint($value, array &$args) {
846
        if ($value instanceof CacheInterface) {
847
            $value = UseFipsConfigProvider::defaultProvider($args);
848
        }
849
        if (is_callable($value)) {
850
            $value = $value();
851
        }
852
        if ($value instanceof PromiseInterface) {
853
            $value = $value->wait();
854
        }
855
        if ($value instanceof UseFipsEndpointConfigurationInterface) {
856
            $args['config']['use_fips_endpoint'] = $value;
857
        } else {
858
            // The Configuration class itself will validate other inputs
859
            $args['config']['use_fips_endpoint'] = new UseFipsEndpointConfiguration($value);
860
        }
861
    }
862
 
863
    public static function _default_use_fips_endpoint(array &$args) {
864
        return UseFipsConfigProvider::defaultProvider($args);
865
    }
866
 
867
    public static function _apply_use_dual_stack_endpoint($value, array &$args) {
868
        if ($value instanceof CacheInterface) {
869
            $value = UseDualStackConfigProvider::defaultProvider($args);
870
        }
871
        if (is_callable($value)) {
872
            $value = $value();
873
        }
874
        if ($value instanceof PromiseInterface) {
875
            $value = $value->wait();
876
        }
877
        if ($value instanceof UseDualStackEndpointConfigurationInterface) {
878
            $args['config']['use_dual_stack_endpoint'] = $value;
879
        } else {
880
            // The Configuration class itself will validate other inputs
881
            $args['config']['use_dual_stack_endpoint'] =
882
                new UseDualStackEndpointConfiguration($value, $args['region']);
883
        }
884
    }
885
 
886
    public static function _default_use_dual_stack_endpoint(array &$args) {
887
        return UseDualStackConfigProvider::defaultProvider($args);
888
    }
889
 
1441 ariadna 890
    public static function _apply_serializer($value, array &$args, HandlerList $list)
891
    {
892
        $list->prependBuild(Middleware::requestBuilder($value), 'builder');
893
    }
894
 
1 efrain 895
    public static function _apply_debug($value, array &$args, HandlerList $list)
896
    {
897
        if ($value !== false) {
898
            $list->interpose(
899
                new TraceMiddleware(
900
                    $value === true ? [] : $value,
901
                    $args['api'])
902
            );
903
        }
904
    }
905
 
906
    public static function _apply_stats($value, array &$args, HandlerList $list)
907
    {
908
        // Create an array of stat collectors that are disabled (set to false)
909
        // by default. If the user has passed in true, enable all stat
910
        // collectors.
911
        $defaults = array_fill_keys(
912
            ['http', 'retries', 'timer'],
913
            $value === true
914
        );
915
        $args['stats'] = is_array($value)
916
            ? array_replace($defaults, $value)
917
            : $defaults;
918
 
919
        if ($args['stats']['timer']) {
920
            $list->prependInit(Middleware::timer(), 'timer');
921
        }
922
    }
923
 
924
    public static function _apply_profile($_, array &$args)
925
    {
926
        $args['credentials'] = CredentialProvider::ini($args['profile']);
927
    }
928
 
929
    public static function _apply_validate($value, array &$args, HandlerList $list)
930
    {
931
        if ($value === false) {
932
            return;
933
        }
934
 
935
        $validator = $value === true
936
            ? new Validator()
937
            : new Validator($value);
938
        $list->appendValidate(
939
            Middleware::validation($args['api'], $validator),
940
            'validation'
941
        );
942
    }
943
 
944
    public static function _apply_handler($value, array &$args, HandlerList $list)
945
    {
946
        $list->setHandler($value);
947
    }
948
 
949
    public static function _default_handler(array &$args)
950
    {
951
        return new WrappedHttpHandler(
952
            default_http_handler(),
953
            $args['parser'],
954
            $args['error_parser'],
955
            $args['exception_class'],
956
            $args['stats']['http']
957
        );
958
    }
959
 
960
    public static function _apply_http_handler($value, array &$args, HandlerList $list)
961
    {
962
        $args['handler'] = new WrappedHttpHandler(
963
            $value,
964
            $args['parser'],
965
            $args['error_parser'],
966
            $args['exception_class'],
967
            $args['stats']['http']
968
        );
969
    }
970
 
1441 ariadna 971
    public static function _apply_app_id($value, array &$args)
1 efrain 972
    {
1441 ariadna 973
        // AppId should not be longer than 50 chars
974
        static $MAX_APP_ID_LENGTH = 50;
975
        if (strlen($value) > $MAX_APP_ID_LENGTH) {
976
            trigger_error("The provided or configured value for `AppId`, "
977
                ."which is an user agent parameter, exceeds the maximum length of "
978
            ."$MAX_APP_ID_LENGTH characters.", E_USER_WARNING);
1 efrain 979
        }
980
 
1441 ariadna 981
        $args['app_id'] = $value;
982
    }
1 efrain 983
 
1441 ariadna 984
    public static function _default_app_id(array $args)
985
    {
986
        return ConfigurationResolver::resolve(
987
            'sdk_ua_app_id',
988
            '',
989
            'string',
990
            $args
991
        );
992
    }
1 efrain 993
 
1441 ariadna 994
    public static function _apply_user_agent(
995
        $inputUserAgent,
996
        array &$args,
997
        HandlerList $list
998
    ): void
999
    {
1000
        // Add endpoint discovery if set
1001
        $userAgent = [];
1002
        // Add the input to the end
1 efrain 1003
        if ($inputUserAgent){
1004
            if (!is_array($inputUserAgent)) {
1005
                $inputUserAgent = [$inputUserAgent];
1006
            }
1007
            $inputUserAgent = array_map('strval', $inputUserAgent);
1008
            $userAgent = array_merge($userAgent, $inputUserAgent);
1009
        }
1010
 
1011
        $args['ua_append'] = $userAgent;
1012
 
1441 ariadna 1013
        $list->appendBuild(
1014
            Middleware::mapRequest(function (RequestInterface $request) use ($userAgent) {
1015
                return $request->withHeader(
1016
                    'X-Amz-User-Agent',
1017
                    implode(' ', array_merge(
1018
                        $userAgent,
1019
                        $request->getHeader('X-Amz-User-Agent')
1020
                    ))
1 efrain 1021
                );
1441 ariadna 1022
            })
1023
        );
1 efrain 1024
    }
1025
 
1026
    public static function _apply_endpoint($value, array &$args, HandlerList $list)
1027
    {
1441 ariadna 1028
        if (empty($value)) {
1029
            unset($args['endpoint']);
1030
            return;
1031
        }
1032
 
1033
        $args['endpoint_override'] = true;
1 efrain 1034
        $args['endpoint'] = $value;
1035
    }
1036
 
1037
    public static function _apply_idempotency_auto_fill(
1038
        $value,
1039
        array &$args,
1040
        HandlerList $list
1041
    ) {
1042
        $enabled = false;
1043
        $generator = null;
1044
 
1045
 
1046
        if (is_bool($value)) {
1047
            $enabled = $value;
1048
        } elseif (is_callable($value)) {
1049
            $enabled = true;
1050
            $generator = $value;
1051
        }
1052
 
1053
        if ($enabled) {
1054
            $list->prependInit(
1055
                IdempotencyTokenMiddleware::wrap($args['api'], $generator),
1056
                'idempotency_auto_fill'
1057
            );
1058
        }
1059
    }
1060
 
1441 ariadna 1061
    public static function _default_account_id_endpoint_mode($args)
1062
    {
1063
        return ConfigurationResolver::resolve(
1064
            'account_id_endpoint_mode',
1065
            'preferred',
1066
            'string',
1067
            $args
1068
        );
1069
    }
1070
 
1071
    public static function _apply_account_id_endpoint_mode($value, array &$args)
1072
    {
1073
        static $accountIdEndpointModes = ['disabled', 'required', 'preferred'];
1074
        if (!in_array($value, $accountIdEndpointModes)) {
1075
            throw new IAE(
1076
                "The value provided for the config account_id_endpoint_mode is invalid."
1077
                ."Valid values are: " . implode(", ", $accountIdEndpointModes)
1078
            );
1 efrain 1079
        }
1441 ariadna 1080
 
1081
        $args['account_id_endpoint_mode'] = $value;
1 efrain 1082
    }
1083
 
1084
    public static function _default_endpoint_provider(array $args)
1085
    {
1441 ariadna 1086
        $service = $args['api'] ?? null;
1 efrain 1087
        $serviceName = isset($service) ? $service->getServiceName() : null;
1088
        $apiVersion = isset($service) ? $service->getApiVersion() : null;
1089
 
1090
        if (self::isValidService($serviceName)
1091
            && self::isValidApiVersion($serviceName, $apiVersion)
1092
        ) {
1093
            $ruleset = EndpointDefinitionProvider::getEndpointRuleset(
1094
                $service->getServiceName(),
1095
                $service->getApiVersion()
1096
            );
1097
            return new \Aws\EndpointV2\EndpointProviderV2(
1098
                $ruleset,
1099
                EndpointDefinitionProvider::getPartitions()
1100
            );
1101
        }
1102
        $options = self::getEndpointProviderOptions($args);
1103
        return PartitionEndpointProvider::defaultProvider($options)
1104
            ->getPartition($args['region'], $args['service']);
1105
    }
1106
 
1107
    public static function _default_serializer(array $args)
1108
    {
1109
        return Service::createSerializer(
1110
            $args['api'],
1111
            $args['endpoint']
1112
        );
1113
    }
1114
 
1115
    public static function _default_signature_provider()
1116
    {
1117
        return SignatureProvider::defaultProvider();
1118
    }
1119
 
1441 ariadna 1120
    public static function _default_auth_scheme_resolver(array $args)
1121
    {
1122
        return new AuthSchemeResolver($args['credentials'], $args['token']);
1123
    }
1124
 
1 efrain 1125
    public static function _default_signature_version(array &$args)
1126
    {
1127
        if (isset($args['config']['signature_version'])) {
1128
            return $args['config']['signature_version'];
1129
        }
1130
 
1131
        $args['__partition_result'] = isset($args['__partition_result'])
1132
            ? isset($args['__partition_result'])
1133
            : call_user_func(PartitionEndpointProvider::defaultProvider(), [
1134
                'service' => $args['service'],
1135
                'region' => $args['region'],
1136
            ]);
1137
 
1138
        return isset($args['__partition_result']['signatureVersion'])
1139
            ? $args['__partition_result']['signatureVersion']
1140
            : $args['api']->getSignatureVersion();
1141
    }
1142
 
1143
    public static function _default_signing_name(array &$args)
1144
    {
1145
        if (isset($args['config']['signing_name'])) {
1146
            return $args['config']['signing_name'];
1147
        }
1148
 
1149
        $args['__partition_result'] = isset($args['__partition_result'])
1150
            ? isset($args['__partition_result'])
1151
            : call_user_func(PartitionEndpointProvider::defaultProvider(), [
1152
                'service' => $args['service'],
1153
                'region' => $args['region'],
1154
            ]);
1155
 
1156
        if (isset($args['__partition_result']['signingName'])) {
1157
            return $args['__partition_result']['signingName'];
1158
        }
1159
 
1160
        if ($signingName = $args['api']->getSigningName()) {
1161
            return $signingName;
1162
        }
1163
 
1164
        return $args['service'];
1165
    }
1166
 
1167
    public static function _default_signing_region(array &$args)
1168
    {
1169
        if (isset($args['config']['signing_region'])) {
1170
            return $args['config']['signing_region'];
1171
        }
1172
 
1173
        $args['__partition_result'] = isset($args['__partition_result'])
1174
            ? isset($args['__partition_result'])
1175
            : call_user_func(PartitionEndpointProvider::defaultProvider(), [
1176
                'service' => $args['service'],
1177
                'region' => $args['region'],
1178
            ]);
1179
 
1441 ariadna 1180
        return $args['__partition_result']['signingRegion'] ?? $args['region'];
1 efrain 1181
    }
1182
 
1441 ariadna 1183
    public static function _apply_ignore_configured_endpoint_urls($value, array &$args)
1184
    {
1185
        $args['config']['ignore_configured_endpoint_urls'] = $value;
1186
    }
1187
 
1188
    public static function _apply_suppress_php_deprecation_warning($value, &$args)
1189
    {
1190
        if ($value)  {
1191
            $args['suppress_php_deprecation_warning'] = true;
1192
        } elseif (!empty(getenv("AWS_SUPPRESS_PHP_DEPRECATION_WARNING"))) {
1193
            $args['suppress_php_deprecation_warning']
1194
                = \Aws\boolean_value(getenv("AWS_SUPPRESS_PHP_DEPRECATION_WARNING"));
1195
        } elseif (!empty($_SERVER["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"])) {
1196
            $args['suppress_php_deprecation_warning'] =
1197
                \Aws\boolean_value($_SERVER["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"]);
1198
        } elseif (!empty($_ENV["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"])) {
1199
            $args['suppress_php_deprecation_warning'] =
1200
                \Aws\boolean_value($_ENV["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"]);
1201
        }
1202
 
1203
        if ($args['suppress_php_deprecation_warning'] === false
1204
            && PHP_VERSION_ID < 80100
1205
        ) {
1206
            self::emitDeprecationWarning();
1207
        }
1208
    }
1209
 
1210
    public static function _default_endpoint(array &$args)
1211
    {
1212
        if ($args['config']['ignore_configured_endpoint_urls']
1213
            || !self::isValidService($args['service'])
1214
        ) {
1215
            return '';
1216
        }
1217
 
1218
        $serviceIdentifier = \Aws\manifest($args['service'])['serviceIdentifier'];
1219
        $value =  ConfigurationResolver::resolve(
1220
            'endpoint_url_' . $serviceIdentifier,
1221
            '',
1222
            'string',
1223
            $args + [
1224
                'ini_resolver_options' => [
1225
                    'section' => 'services',
1226
                    'subsection' => $serviceIdentifier,
1227
                    'key' => 'endpoint_url'
1228
                ]
1229
            ]
1230
        );
1231
 
1232
        if (empty($value)) {
1233
            $value = ConfigurationResolver::resolve(
1234
                'endpoint_url',
1235
                '',
1236
                'string',
1237
                $args
1238
            );
1239
        }
1240
 
1241
        if (!empty($value)) {
1242
            $args['config']['configured_endpoint_url'] = true;
1243
        }
1244
 
1245
        return $value;
1246
    }
1247
 
1248
    public static function _apply_sigv4a_signing_region_set($value, array &$args)
1249
    {
1250
        if (empty($value)) {
1251
            $args['sigv4a_signing_region_set'] = null;
1252
        } elseif (is_array($value)) {
1253
            $args['sigv4a_signing_region_set'] = implode(', ', $value);
1254
        } else {
1255
            $args['sigv4a_signing_region_set'] = $value;
1256
        }
1257
    }
1258
 
1259
    public static function _apply_region($value, array &$args)
1260
    {
1261
        if (empty($value)) {
1262
            self::_missing_region($args);
1263
        }
1264
        $args['region'] = $value;
1265
    }
1266
 
1 efrain 1267
    public static function _missing_region(array $args)
1268
    {
1441 ariadna 1269
        $service = $args['service'] ?? '';
1 efrain 1270
 
1441 ariadna 1271
        $msg = <<<EOT
1272
Missing required client configuration options:
1273
 
1274
region: (string)
1275
 
1 efrain 1276
A "region" configuration value is required for the "{$service}" service
1277
(e.g., "us-west-2"). A list of available public regions and endpoints can be
1278
found at http://docs.aws.amazon.com/general/latest/gr/rande.html.
1279
EOT;
1441 ariadna 1280
        throw new IAE($msg);
1 efrain 1281
    }
1282
 
1283
    /**
1441 ariadna 1284
     * Resolves a value from env or config.
1285
     *
1286
     * @param $key
1287
     * @param $expectedType
1288
     * @param $args
1289
     *
1290
     * @return mixed|string
1291
     */
1292
    private static function _resolve_from_env_ini(
1293
        string $key,
1294
        string $expectedType,
1295
        array $args
1296
    ) {
1297
        static $typeDefaultMap = [
1298
            'int' => 0,
1299
            'bool' => false,
1300
            'boolean' => false,
1301
            'string' => '',
1302
        ];
1303
 
1304
        return ConfigurationResolver::resolve(
1305
            $key,
1306
            $typeDefaultMap[$expectedType] ?? '',
1307
            $expectedType,
1308
            $args
1309
        );
1310
    }
1311
 
1312
    /**
1 efrain 1313
     * Extracts client options for the endpoint provider to its own array
1314
     *
1315
     * @param array $args
1316
     * @return array
1317
     */
1318
    private static function getEndpointProviderOptions(array $args)
1319
    {
1320
        $options = [];
1321
        $optionKeys = [
1322
            'sts_regional_endpoints',
1323
            's3_us_east_1_regional_endpoint',
1441 ariadna 1324
        ];
1 efrain 1325
        $configKeys = [
1326
            'use_dual_stack_endpoint',
1327
            'use_fips_endpoint',
1328
        ];
1329
        foreach ($optionKeys as $key) {
1330
            if (isset($args[$key])) {
1331
                $options[$key] = $args[$key];
1332
            }
1333
        }
1334
        foreach ($configKeys as $key) {
1335
            if (isset($args['config'][$key])) {
1336
                $options[$key] = $args['config'][$key];
1337
            }
1338
        }
1339
        return $options;
1340
    }
1341
 
1342
    /**
1343
     * Validates a region to be used for endpoint construction
1344
     *
1345
     * @param $region
1346
     * @return bool
1347
     */
1348
    private static function isValidRegion($region)
1349
    {
1350
        return is_valid_hostlabel($region);
1351
    }
1352
 
1353
    private function _apply_client_context_params(array $args)
1354
    {
1355
        if (isset($args['api'])
1441 ariadna 1356
            && !empty($args['api']->getClientContextParams()))
1 efrain 1357
        {
1358
            $clientContextParams = $args['api']->getClientContextParams();
1359
            foreach($clientContextParams as $paramName => $paramDefinition) {
1360
                $definition = [
1361
                    'type' => 'value',
1362
                    'valid' => [$paramDefinition['type']],
1441 ariadna 1363
                    'doc' => $paramDefinition['documentation'] ?? null
1 efrain 1364
                ];
1365
                $this->argDefinitions[$paramName] = $definition;
1366
 
1367
                if (isset($args[$paramName])) {
1368
                    $fn = self::$typeMap[$paramDefinition['type']];
1369
                    if (!$fn($args[$paramName])) {
1370
                        $this->invalidType($paramName, $args[$paramName]);
1371
                    }
1372
                }
1373
            }
1374
        }
1375
    }
1376
 
1441 ariadna 1377
    private static function isValidService($service)
1378
    {
1 efrain 1379
        if (is_null($service)) {
1380
            return false;
1381
        }
1382
        $services = \Aws\manifest();
1383
        return isset($services[$service]);
1384
    }
1385
 
1441 ariadna 1386
    private static function isValidApiVersion($service, $apiVersion)
1387
    {
1 efrain 1388
        if (is_null($apiVersion)) {
1389
            return false;
1390
        }
1391
        return is_dir(
1441 ariadna 1392
            __DIR__ . "/data/{$service}/$apiVersion"
1 efrain 1393
        );
1394
    }
1441 ariadna 1395
 
1396
    private static function emitDeprecationWarning()
1397
    {
1398
        $phpVersionString = phpversion();
1399
        trigger_error(
1400
            "This installation of the SDK is using PHP version"
1401
            .  " {$phpVersionString}, which will be deprecated on January"
1402
            .  " 13th, 2025.\nPlease upgrade your PHP version to a minimum of"
1403
            .  " 8.1.x to continue receiving updates for the AWS"
1404
            .  " SDK for PHP.\nTo disable this warning, set"
1405
            .  " suppress_php_deprecation_warning to true on the client constructor"
1406
            .  " or set the environment variable AWS_SUPPRESS_PHP_DEPRECATION_WARNING"
1407
            .  " to true.\nMore information can be found at: "
1408
            .   "https://aws.amazon.com/blogs/developer/announcing-the-end-of-support-for-php-runtimes-8-0-x-and-below-in-the-aws-sdk-for-php/\n",
1409
            E_USER_DEPRECATED
1410
        );
1411
    }
1 efrain 1412
}