Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/botocore/args.py: 17%

271 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +0000

1# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"). You 

4# may not use this file except in compliance with the License. A copy of 

5# the License is located at 

6# 

7# http://aws.amazon.com/apache2.0/ 

8# 

9# or in the "license" file accompanying this file. This file is 

10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 

11# ANY KIND, either express or implied. See the License for the specific 

12# language governing permissions and limitations under the License. 

13"""Internal module to help with normalizing botocore client args. 

14 

15This module (and all function/classes within this module) should be 

16considered internal, and *not* a public API. 

17 

18""" 

19import copy 

20import logging 

21import socket 

22 

23import botocore.exceptions 

24import botocore.parsers 

25import botocore.serialize 

26from botocore.config import Config 

27from botocore.endpoint import EndpointCreator 

28from botocore.regions import EndpointResolverBuiltins as EPRBuiltins 

29from botocore.regions import EndpointRulesetResolver 

30from botocore.signers import RequestSigner 

31from botocore.useragent import UserAgentString 

32from botocore.utils import ensure_boolean, is_s3_accelerate_url 

33 

34logger = logging.getLogger(__name__) 

35 

36 

37VALID_REGIONAL_ENDPOINTS_CONFIG = [ 

38 'legacy', 

39 'regional', 

40] 

41LEGACY_GLOBAL_STS_REGIONS = [ 

42 'ap-northeast-1', 

43 'ap-south-1', 

44 'ap-southeast-1', 

45 'ap-southeast-2', 

46 'aws-global', 

47 'ca-central-1', 

48 'eu-central-1', 

49 'eu-north-1', 

50 'eu-west-1', 

51 'eu-west-2', 

52 'eu-west-3', 

53 'sa-east-1', 

54 'us-east-1', 

55 'us-east-2', 

56 'us-west-1', 

57 'us-west-2', 

58] 

59# Maximum allowed length of the ``user_agent_appid`` config field. Longer 

60# values result in a warning-level log message. 

61USERAGENT_APPID_MAXLEN = 50 

62 

63 

64class ClientArgsCreator: 

65 def __init__( 

66 self, 

67 event_emitter, 

68 user_agent, 

69 response_parser_factory, 

70 loader, 

71 exceptions_factory, 

72 config_store, 

73 user_agent_creator=None, 

74 ): 

75 self._event_emitter = event_emitter 

76 self._response_parser_factory = response_parser_factory 

77 self._loader = loader 

78 self._exceptions_factory = exceptions_factory 

79 self._config_store = config_store 

80 if user_agent_creator is None: 

81 self._session_ua_creator = UserAgentString.from_environment() 

82 else: 

83 self._session_ua_creator = user_agent_creator 

84 

85 def get_client_args( 

86 self, 

87 service_model, 

88 region_name, 

89 is_secure, 

90 endpoint_url, 

91 verify, 

92 credentials, 

93 scoped_config, 

94 client_config, 

95 endpoint_bridge, 

96 auth_token=None, 

97 endpoints_ruleset_data=None, 

98 partition_data=None, 

99 ): 

100 final_args = self.compute_client_args( 

101 service_model, 

102 client_config, 

103 endpoint_bridge, 

104 region_name, 

105 endpoint_url, 

106 is_secure, 

107 scoped_config, 

108 ) 

109 

110 service_name = final_args['service_name'] # noqa 

111 parameter_validation = final_args['parameter_validation'] 

112 endpoint_config = final_args['endpoint_config'] 

113 protocol = final_args['protocol'] 

114 config_kwargs = final_args['config_kwargs'] 

115 s3_config = final_args['s3_config'] 

116 partition = endpoint_config['metadata'].get('partition', None) 

117 socket_options = final_args['socket_options'] 

118 configured_endpoint_url = final_args['configured_endpoint_url'] 

119 signing_region = endpoint_config['signing_region'] 

120 endpoint_region_name = endpoint_config['region_name'] 

121 

122 event_emitter = copy.copy(self._event_emitter) 

123 signer = RequestSigner( 

124 service_model.service_id, 

125 signing_region, 

126 endpoint_config['signing_name'], 

127 endpoint_config['signature_version'], 

128 credentials, 

129 event_emitter, 

130 auth_token, 

131 ) 

132 

133 config_kwargs['s3'] = s3_config 

134 new_config = Config(**config_kwargs) 

135 endpoint_creator = EndpointCreator(event_emitter) 

136 

137 endpoint = endpoint_creator.create_endpoint( 

138 service_model, 

139 region_name=endpoint_region_name, 

140 endpoint_url=endpoint_config['endpoint_url'], 

141 verify=verify, 

142 response_parser_factory=self._response_parser_factory, 

143 max_pool_connections=new_config.max_pool_connections, 

144 proxies=new_config.proxies, 

145 timeout=(new_config.connect_timeout, new_config.read_timeout), 

146 socket_options=socket_options, 

147 client_cert=new_config.client_cert, 

148 proxies_config=new_config.proxies_config, 

149 ) 

150 

151 serializer = botocore.serialize.create_serializer( 

152 protocol, parameter_validation 

153 ) 

154 response_parser = botocore.parsers.create_parser(protocol) 

155 

156 ruleset_resolver = self._build_endpoint_resolver( 

157 endpoints_ruleset_data, 

158 partition_data, 

159 client_config, 

160 service_model, 

161 endpoint_region_name, 

162 region_name, 

163 configured_endpoint_url, 

164 endpoint, 

165 is_secure, 

166 endpoint_bridge, 

167 event_emitter, 

168 ) 

169 

170 # Copy the session's user agent factory and adds client configuration. 

171 client_ua_creator = self._session_ua_creator.with_client_config( 

172 new_config 

173 ) 

174 supplied_ua = client_config.user_agent if client_config else None 

175 new_config._supplied_user_agent = supplied_ua 

176 

177 return { 

178 'serializer': serializer, 

179 'endpoint': endpoint, 

180 'response_parser': response_parser, 

181 'event_emitter': event_emitter, 

182 'request_signer': signer, 

183 'service_model': service_model, 

184 'loader': self._loader, 

185 'client_config': new_config, 

186 'partition': partition, 

187 'exceptions_factory': self._exceptions_factory, 

188 'endpoint_ruleset_resolver': ruleset_resolver, 

189 'user_agent_creator': client_ua_creator, 

190 } 

191 

192 def compute_client_args( 

193 self, 

194 service_model, 

195 client_config, 

196 endpoint_bridge, 

197 region_name, 

198 endpoint_url, 

199 is_secure, 

200 scoped_config, 

201 ): 

202 service_name = service_model.endpoint_prefix 

203 protocol = service_model.metadata['protocol'] 

204 parameter_validation = True 

205 if client_config and not client_config.parameter_validation: 

206 parameter_validation = False 

207 elif scoped_config: 

208 raw_value = scoped_config.get('parameter_validation') 

209 if raw_value is not None: 

210 parameter_validation = ensure_boolean(raw_value) 

211 

212 s3_config = self.compute_s3_config(client_config) 

213 

214 configured_endpoint_url = self._compute_configured_endpoint_url( 

215 client_config=client_config, 

216 endpoint_url=endpoint_url, 

217 ) 

218 

219 endpoint_config = self._compute_endpoint_config( 

220 service_name=service_name, 

221 region_name=region_name, 

222 endpoint_url=configured_endpoint_url, 

223 is_secure=is_secure, 

224 endpoint_bridge=endpoint_bridge, 

225 s3_config=s3_config, 

226 ) 

227 endpoint_variant_tags = endpoint_config['metadata'].get('tags', []) 

228 

229 # Some third-party libraries expect the final user-agent string in 

230 # ``client.meta.config.user_agent``. To maintain backwards 

231 # compatibility, the preliminary user-agent string (before any Config 

232 # object modifications and without request-specific user-agent 

233 # components) is stored in the new Config object's ``user_agent`` 

234 # property but not used by Botocore itself. 

235 preliminary_ua_string = self._session_ua_creator.with_client_config( 

236 client_config 

237 ).to_string() 

238 # Create a new client config to be passed to the client based 

239 # on the final values. We do not want the user to be able 

240 # to try to modify an existing client with a client config. 

241 config_kwargs = dict( 

242 region_name=endpoint_config['region_name'], 

243 signature_version=endpoint_config['signature_version'], 

244 user_agent=preliminary_ua_string, 

245 ) 

246 if 'dualstack' in endpoint_variant_tags: 

247 config_kwargs.update(use_dualstack_endpoint=True) 

248 if 'fips' in endpoint_variant_tags: 

249 config_kwargs.update(use_fips_endpoint=True) 

250 if client_config is not None: 

251 config_kwargs.update( 

252 connect_timeout=client_config.connect_timeout, 

253 read_timeout=client_config.read_timeout, 

254 max_pool_connections=client_config.max_pool_connections, 

255 proxies=client_config.proxies, 

256 proxies_config=client_config.proxies_config, 

257 retries=client_config.retries, 

258 client_cert=client_config.client_cert, 

259 inject_host_prefix=client_config.inject_host_prefix, 

260 tcp_keepalive=client_config.tcp_keepalive, 

261 user_agent_extra=client_config.user_agent_extra, 

262 user_agent_appid=client_config.user_agent_appid, 

263 request_min_compression_size_bytes=( 

264 client_config.request_min_compression_size_bytes 

265 ), 

266 disable_request_compression=( 

267 client_config.disable_request_compression 

268 ), 

269 client_context_params=client_config.client_context_params, 

270 ) 

271 self._compute_retry_config(config_kwargs) 

272 self._compute_connect_timeout(config_kwargs) 

273 self._compute_user_agent_appid_config(config_kwargs) 

274 self._compute_request_compression_config(config_kwargs) 

275 s3_config = self.compute_s3_config(client_config) 

276 

277 is_s3_service = self._is_s3_service(service_name) 

278 

279 if is_s3_service and 'dualstack' in endpoint_variant_tags: 

280 if s3_config is None: 

281 s3_config = {} 

282 s3_config['use_dualstack_endpoint'] = True 

283 

284 return { 

285 'service_name': service_name, 

286 'parameter_validation': parameter_validation, 

287 'configured_endpoint_url': configured_endpoint_url, 

288 'endpoint_config': endpoint_config, 

289 'protocol': protocol, 

290 'config_kwargs': config_kwargs, 

291 's3_config': s3_config, 

292 'socket_options': self._compute_socket_options( 

293 scoped_config, client_config 

294 ), 

295 } 

296 

297 def _compute_configured_endpoint_url(self, client_config, endpoint_url): 

298 if endpoint_url is not None: 

299 return endpoint_url 

300 

301 if self._ignore_configured_endpoint_urls(client_config): 

302 logger.debug("Ignoring configured endpoint URLs.") 

303 return endpoint_url 

304 

305 return self._config_store.get_config_variable('endpoint_url') 

306 

307 def _ignore_configured_endpoint_urls(self, client_config): 

308 if ( 

309 client_config 

310 and client_config.ignore_configured_endpoint_urls is not None 

311 ): 

312 return client_config.ignore_configured_endpoint_urls 

313 

314 return self._config_store.get_config_variable( 

315 'ignore_configured_endpoint_urls' 

316 ) 

317 

318 def compute_s3_config(self, client_config): 

319 s3_configuration = self._config_store.get_config_variable('s3') 

320 

321 # Next specific client config values takes precedence over 

322 # specific values in the scoped config. 

323 if client_config is not None: 

324 if client_config.s3 is not None: 

325 if s3_configuration is None: 

326 s3_configuration = client_config.s3 

327 else: 

328 # The current s3_configuration dictionary may be 

329 # from a source that only should be read from so 

330 # we want to be safe and just make a copy of it to modify 

331 # before it actually gets updated. 

332 s3_configuration = s3_configuration.copy() 

333 s3_configuration.update(client_config.s3) 

334 

335 return s3_configuration 

336 

337 def _is_s3_service(self, service_name): 

338 """Whether the service is S3 or S3 Control. 

339 

340 Note that throughout this class, service_name refers to the endpoint 

341 prefix, not the folder name of the service in botocore/data. For 

342 S3 Control, the folder name is 's3control' but the endpoint prefix is 

343 's3-control'. 

344 """ 

345 return service_name in ['s3', 's3-control'] 

346 

347 def _compute_endpoint_config( 

348 self, 

349 service_name, 

350 region_name, 

351 endpoint_url, 

352 is_secure, 

353 endpoint_bridge, 

354 s3_config, 

355 ): 

356 resolve_endpoint_kwargs = { 

357 'service_name': service_name, 

358 'region_name': region_name, 

359 'endpoint_url': endpoint_url, 

360 'is_secure': is_secure, 

361 'endpoint_bridge': endpoint_bridge, 

362 } 

363 if service_name == 's3': 

364 return self._compute_s3_endpoint_config( 

365 s3_config=s3_config, **resolve_endpoint_kwargs 

366 ) 

367 if service_name == 'sts': 

368 return self._compute_sts_endpoint_config(**resolve_endpoint_kwargs) 

369 return self._resolve_endpoint(**resolve_endpoint_kwargs) 

370 

371 def _compute_s3_endpoint_config( 

372 self, s3_config, **resolve_endpoint_kwargs 

373 ): 

374 force_s3_global = self._should_force_s3_global( 

375 resolve_endpoint_kwargs['region_name'], s3_config 

376 ) 

377 if force_s3_global: 

378 resolve_endpoint_kwargs['region_name'] = None 

379 endpoint_config = self._resolve_endpoint(**resolve_endpoint_kwargs) 

380 self._set_region_if_custom_s3_endpoint( 

381 endpoint_config, resolve_endpoint_kwargs['endpoint_bridge'] 

382 ) 

383 # For backwards compatibility reasons, we want to make sure the 

384 # client.meta.region_name will remain us-east-1 if we forced the 

385 # endpoint to be the global region. Specifically, if this value 

386 # changes to aws-global, it breaks logic where a user is checking 

387 # for us-east-1 as the global endpoint such as in creating buckets. 

388 if force_s3_global and endpoint_config['region_name'] == 'aws-global': 

389 endpoint_config['region_name'] = 'us-east-1' 

390 return endpoint_config 

391 

392 def _should_force_s3_global(self, region_name, s3_config): 

393 s3_regional_config = 'legacy' 

394 if s3_config and 'us_east_1_regional_endpoint' in s3_config: 

395 s3_regional_config = s3_config['us_east_1_regional_endpoint'] 

396 self._validate_s3_regional_config(s3_regional_config) 

397 

398 is_global_region = region_name in ('us-east-1', None) 

399 return s3_regional_config == 'legacy' and is_global_region 

400 

401 def _validate_s3_regional_config(self, config_val): 

402 if config_val not in VALID_REGIONAL_ENDPOINTS_CONFIG: 

403 raise botocore.exceptions.InvalidS3UsEast1RegionalEndpointConfigError( 

404 s3_us_east_1_regional_endpoint_config=config_val 

405 ) 

406 

407 def _set_region_if_custom_s3_endpoint( 

408 self, endpoint_config, endpoint_bridge 

409 ): 

410 # If a user is providing a custom URL, the endpoint resolver will 

411 # refuse to infer a signing region. If we want to default to s3v4, 

412 # we have to account for this. 

413 if ( 

414 endpoint_config['signing_region'] is None 

415 and endpoint_config['region_name'] is None 

416 ): 

417 endpoint = endpoint_bridge.resolve('s3') 

418 endpoint_config['signing_region'] = endpoint['signing_region'] 

419 endpoint_config['region_name'] = endpoint['region_name'] 

420 

421 def _compute_sts_endpoint_config(self, **resolve_endpoint_kwargs): 

422 endpoint_config = self._resolve_endpoint(**resolve_endpoint_kwargs) 

423 if self._should_set_global_sts_endpoint( 

424 resolve_endpoint_kwargs['region_name'], 

425 resolve_endpoint_kwargs['endpoint_url'], 

426 endpoint_config, 

427 ): 

428 self._set_global_sts_endpoint( 

429 endpoint_config, resolve_endpoint_kwargs['is_secure'] 

430 ) 

431 return endpoint_config 

432 

433 def _should_set_global_sts_endpoint( 

434 self, region_name, endpoint_url, endpoint_config 

435 ): 

436 has_variant_tags = endpoint_config and endpoint_config.get( 

437 'metadata', {} 

438 ).get('tags') 

439 if endpoint_url or has_variant_tags: 

440 return False 

441 return ( 

442 self._get_sts_regional_endpoints_config() == 'legacy' 

443 and region_name in LEGACY_GLOBAL_STS_REGIONS 

444 ) 

445 

446 def _get_sts_regional_endpoints_config(self): 

447 sts_regional_endpoints_config = self._config_store.get_config_variable( 

448 'sts_regional_endpoints' 

449 ) 

450 if not sts_regional_endpoints_config: 

451 sts_regional_endpoints_config = 'legacy' 

452 if ( 

453 sts_regional_endpoints_config 

454 not in VALID_REGIONAL_ENDPOINTS_CONFIG 

455 ): 

456 raise botocore.exceptions.InvalidSTSRegionalEndpointsConfigError( 

457 sts_regional_endpoints_config=sts_regional_endpoints_config 

458 ) 

459 return sts_regional_endpoints_config 

460 

461 def _set_global_sts_endpoint(self, endpoint_config, is_secure): 

462 scheme = 'https' if is_secure else 'http' 

463 endpoint_config['endpoint_url'] = '%s://sts.amazonaws.com' % scheme 

464 endpoint_config['signing_region'] = 'us-east-1' 

465 

466 def _resolve_endpoint( 

467 self, 

468 service_name, 

469 region_name, 

470 endpoint_url, 

471 is_secure, 

472 endpoint_bridge, 

473 ): 

474 return endpoint_bridge.resolve( 

475 service_name, region_name, endpoint_url, is_secure 

476 ) 

477 

478 def _compute_socket_options(self, scoped_config, client_config=None): 

479 # This disables Nagle's algorithm and is the default socket options 

480 # in urllib3. 

481 socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] 

482 client_keepalive = client_config and client_config.tcp_keepalive 

483 scoped_keepalive = scoped_config and self._ensure_boolean( 

484 scoped_config.get("tcp_keepalive", False) 

485 ) 

486 # Enables TCP Keepalive if specified in client config object or shared config file. 

487 if client_keepalive or scoped_keepalive: 

488 socket_options.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) 

489 return socket_options 

490 

491 def _compute_retry_config(self, config_kwargs): 

492 self._compute_retry_max_attempts(config_kwargs) 

493 self._compute_retry_mode(config_kwargs) 

494 

495 def _compute_retry_max_attempts(self, config_kwargs): 

496 # There's a pre-existing max_attempts client config value that actually 

497 # means max *retry* attempts. There's also a `max_attempts` we pull 

498 # from the config store that means *total attempts*, which includes the 

499 # intitial request. We can't change what `max_attempts` means in 

500 # client config so we try to normalize everything to a new 

501 # "total_max_attempts" variable. We ensure that after this, the only 

502 # configuration for "max attempts" is the 'total_max_attempts' key. 

503 # An explicitly provided max_attempts in the client config 

504 # overrides everything. 

505 retries = config_kwargs.get('retries') 

506 if retries is not None: 

507 if 'total_max_attempts' in retries: 

508 retries.pop('max_attempts', None) 

509 return 

510 if 'max_attempts' in retries: 

511 value = retries.pop('max_attempts') 

512 # client config max_attempts means total retries so we 

513 # have to add one for 'total_max_attempts' to account 

514 # for the initial request. 

515 retries['total_max_attempts'] = value + 1 

516 return 

517 # Otherwise we'll check the config store which checks env vars, 

518 # config files, etc. There is no default value for max_attempts 

519 # so if this returns None and we don't set a default value here. 

520 max_attempts = self._config_store.get_config_variable('max_attempts') 

521 if max_attempts is not None: 

522 if retries is None: 

523 retries = {} 

524 config_kwargs['retries'] = retries 

525 retries['total_max_attempts'] = max_attempts 

526 

527 def _compute_retry_mode(self, config_kwargs): 

528 retries = config_kwargs.get('retries') 

529 if retries is None: 

530 retries = {} 

531 config_kwargs['retries'] = retries 

532 elif 'mode' in retries: 

533 # If there's a retry mode explicitly set in the client config 

534 # that overrides everything. 

535 return 

536 retry_mode = self._config_store.get_config_variable('retry_mode') 

537 if retry_mode is None: 

538 retry_mode = 'legacy' 

539 retries['mode'] = retry_mode 

540 

541 def _compute_connect_timeout(self, config_kwargs): 

542 # Checking if connect_timeout is set on the client config. 

543 # If it is not, we check the config_store in case a 

544 # non legacy default mode has been configured. 

545 connect_timeout = config_kwargs.get('connect_timeout') 

546 if connect_timeout is not None: 

547 return 

548 connect_timeout = self._config_store.get_config_variable( 

549 'connect_timeout' 

550 ) 

551 if connect_timeout: 

552 config_kwargs['connect_timeout'] = connect_timeout 

553 

554 def _compute_request_compression_config(self, config_kwargs): 

555 min_size = config_kwargs.get('request_min_compression_size_bytes') 

556 disabled = config_kwargs.get('disable_request_compression') 

557 if min_size is None: 

558 min_size = self._config_store.get_config_variable( 

559 'request_min_compression_size_bytes' 

560 ) 

561 # conversion func is skipped so input validation must be done here 

562 # regardless if the value is coming from the config store or the 

563 # config object 

564 min_size = self._validate_min_compression_size(min_size) 

565 config_kwargs['request_min_compression_size_bytes'] = min_size 

566 

567 if disabled is None: 

568 disabled = self._config_store.get_config_variable( 

569 'disable_request_compression' 

570 ) 

571 else: 

572 # if the user provided a value we must check if it's a boolean 

573 disabled = ensure_boolean(disabled) 

574 config_kwargs['disable_request_compression'] = disabled 

575 

576 def _validate_min_compression_size(self, min_size): 

577 min_allowed_min_size = 1 

578 max_allowed_min_size = 1048576 

579 if min_size is not None: 

580 error_msg_base = ( 

581 f'Invalid value "{min_size}" for ' 

582 'request_min_compression_size_bytes.' 

583 ) 

584 try: 

585 min_size = int(min_size) 

586 except (ValueError, TypeError): 

587 msg = ( 

588 f'{error_msg_base} Value must be an integer. ' 

589 f'Received {type(min_size)} instead.' 

590 ) 

591 raise botocore.exceptions.InvalidConfigError(error_msg=msg) 

592 if not min_allowed_min_size <= min_size <= max_allowed_min_size: 

593 msg = ( 

594 f'{error_msg_base} Value must be between ' 

595 f'{min_allowed_min_size} and {max_allowed_min_size}.' 

596 ) 

597 raise botocore.exceptions.InvalidConfigError(error_msg=msg) 

598 

599 return min_size 

600 

601 def _ensure_boolean(self, val): 

602 if isinstance(val, bool): 

603 return val 

604 else: 

605 return val.lower() == 'true' 

606 

607 def _build_endpoint_resolver( 

608 self, 

609 endpoints_ruleset_data, 

610 partition_data, 

611 client_config, 

612 service_model, 

613 endpoint_region_name, 

614 region_name, 

615 endpoint_url, 

616 endpoint, 

617 is_secure, 

618 endpoint_bridge, 

619 event_emitter, 

620 ): 

621 if endpoints_ruleset_data is None: 

622 return None 

623 

624 # The legacy EndpointResolver is global to the session, but 

625 # EndpointRulesetResolver is service-specific. Builtins for 

626 # EndpointRulesetResolver must not be derived from the legacy 

627 # endpoint resolver's output, including final_args, s3_config, 

628 # etc. 

629 s3_config_raw = self.compute_s3_config(client_config) or {} 

630 service_name_raw = service_model.endpoint_prefix 

631 # Maintain complex logic for s3 and sts endpoints for backwards 

632 # compatibility. 

633 if service_name_raw in ['s3', 'sts'] or region_name is None: 

634 eprv2_region_name = endpoint_region_name 

635 else: 

636 eprv2_region_name = region_name 

637 resolver_builtins = self.compute_endpoint_resolver_builtin_defaults( 

638 region_name=eprv2_region_name, 

639 service_name=service_name_raw, 

640 s3_config=s3_config_raw, 

641 endpoint_bridge=endpoint_bridge, 

642 client_endpoint_url=endpoint_url, 

643 legacy_endpoint_url=endpoint.host, 

644 ) 

645 # Client context params for s3 conflict with the available settings 

646 # in the `s3` parameter on the `Config` object. If the same parameter 

647 # is set in both places, the value in the `s3` parameter takes priority. 

648 if client_config is not None: 

649 client_context = client_config.client_context_params or {} 

650 else: 

651 client_context = {} 

652 if self._is_s3_service(service_name_raw): 

653 client_context.update(s3_config_raw) 

654 

655 sig_version = ( 

656 client_config.signature_version 

657 if client_config is not None 

658 else None 

659 ) 

660 return EndpointRulesetResolver( 

661 endpoint_ruleset_data=endpoints_ruleset_data, 

662 partition_data=partition_data, 

663 service_model=service_model, 

664 builtins=resolver_builtins, 

665 client_context=client_context, 

666 event_emitter=event_emitter, 

667 use_ssl=is_secure, 

668 requested_auth_scheme=sig_version, 

669 ) 

670 

671 def compute_endpoint_resolver_builtin_defaults( 

672 self, 

673 region_name, 

674 service_name, 

675 s3_config, 

676 endpoint_bridge, 

677 client_endpoint_url, 

678 legacy_endpoint_url, 

679 ): 

680 # EndpointRulesetResolver rulesets may accept an "SDK::Endpoint" as 

681 # input. If the endpoint_url argument of create_client() is set, it 

682 # always takes priority. 

683 if client_endpoint_url: 

684 given_endpoint = client_endpoint_url 

685 # If an endpoints.json data file other than the one bundled within 

686 # the botocore/data directory is used, the output of legacy 

687 # endpoint resolution is provided to EndpointRulesetResolver. 

688 elif not endpoint_bridge.resolver_uses_builtin_data(): 

689 given_endpoint = legacy_endpoint_url 

690 else: 

691 given_endpoint = None 

692 

693 # The endpoint rulesets differ from legacy botocore behavior in whether 

694 # forcing path style addressing in incompatible situations raises an 

695 # exception or silently ignores the config setting. The 

696 # AWS_S3_FORCE_PATH_STYLE parameter is adjusted both here and for each 

697 # operation so that the ruleset behavior is backwards compatible. 

698 if s3_config.get('use_accelerate_endpoint', False): 

699 force_path_style = False 

700 elif client_endpoint_url is not None and not is_s3_accelerate_url( 

701 client_endpoint_url 

702 ): 

703 force_path_style = s3_config.get('addressing_style') != 'virtual' 

704 else: 

705 force_path_style = s3_config.get('addressing_style') == 'path' 

706 

707 return { 

708 EPRBuiltins.AWS_REGION: region_name, 

709 EPRBuiltins.AWS_USE_FIPS: ( 

710 # SDK_ENDPOINT cannot be combined with AWS_USE_FIPS 

711 given_endpoint is None 

712 # use legacy resolver's _resolve_endpoint_variant_config_var() 

713 # or default to False if it returns None 

714 and endpoint_bridge._resolve_endpoint_variant_config_var( 

715 'use_fips_endpoint' 

716 ) 

717 or False 

718 ), 

719 EPRBuiltins.AWS_USE_DUALSTACK: ( 

720 # SDK_ENDPOINT cannot be combined with AWS_USE_DUALSTACK 

721 given_endpoint is None 

722 # use legacy resolver's _resolve_use_dualstack_endpoint() and 

723 # or default to False if it returns None 

724 and endpoint_bridge._resolve_use_dualstack_endpoint( 

725 service_name 

726 ) 

727 or False 

728 ), 

729 EPRBuiltins.AWS_STS_USE_GLOBAL_ENDPOINT: ( 

730 self._should_set_global_sts_endpoint( 

731 region_name=region_name, 

732 endpoint_url=None, 

733 endpoint_config=None, 

734 ) 

735 ), 

736 EPRBuiltins.AWS_S3_USE_GLOBAL_ENDPOINT: ( 

737 self._should_force_s3_global(region_name, s3_config) 

738 ), 

739 EPRBuiltins.AWS_S3_ACCELERATE: s3_config.get( 

740 'use_accelerate_endpoint', False 

741 ), 

742 EPRBuiltins.AWS_S3_FORCE_PATH_STYLE: force_path_style, 

743 EPRBuiltins.AWS_S3_USE_ARN_REGION: s3_config.get( 

744 'use_arn_region', True 

745 ), 

746 EPRBuiltins.AWS_S3CONTROL_USE_ARN_REGION: s3_config.get( 

747 'use_arn_region', False 

748 ), 

749 EPRBuiltins.AWS_S3_DISABLE_MRAP: s3_config.get( 

750 's3_disable_multiregion_access_points', False 

751 ), 

752 EPRBuiltins.SDK_ENDPOINT: given_endpoint, 

753 } 

754 

755 def _compute_user_agent_appid_config(self, config_kwargs): 

756 user_agent_appid = config_kwargs.get('user_agent_appid') 

757 if user_agent_appid is None: 

758 user_agent_appid = self._config_store.get_config_variable( 

759 'user_agent_appid' 

760 ) 

761 if ( 

762 user_agent_appid is not None 

763 and len(user_agent_appid) > USERAGENT_APPID_MAXLEN 

764 ): 

765 logger.warning( 

766 'The configured value for user_agent_appid exceeds the ' 

767 f'maximum length of {USERAGENT_APPID_MAXLEN} characters.' 

768 ) 

769 config_kwargs['user_agent_appid'] = user_agent_appid