ClientResolver.php 59 KB

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