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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

271 statements  

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""" 

19 

20import copy 

21import logging 

22import socket 

23 

24import botocore.exceptions 

25import botocore.parsers 

26import botocore.serialize 

27from botocore.config import Config 

28from botocore.endpoint import EndpointCreator 

29from botocore.regions import EndpointResolverBuiltins as EPRBuiltins 

30from botocore.regions import EndpointRulesetResolver 

31from botocore.signers import RequestSigner 

32from botocore.useragent import UserAgentString 

33from botocore.utils import ensure_boolean, is_s3_accelerate_url 

34 

35logger = logging.getLogger(__name__) 

36 

37 

38VALID_REGIONAL_ENDPOINTS_CONFIG = [ 

39 'legacy', 

40 'regional', 

41] 

42LEGACY_GLOBAL_STS_REGIONS = [ 

43 'ap-northeast-1', 

44 'ap-south-1', 

45 'ap-southeast-1', 

46 'ap-southeast-2', 

47 'aws-global', 

48 'ca-central-1', 

49 'eu-central-1', 

50 'eu-north-1', 

51 'eu-west-1', 

52 'eu-west-2', 

53 'eu-west-3', 

54 'sa-east-1', 

55 'us-east-1', 

56 'us-east-2', 

57 'us-west-1', 

58 'us-west-2', 

59] 

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

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

62USERAGENT_APPID_MAXLEN = 50 

63 

64 

65class ClientArgsCreator: 

66 def __init__( 

67 self, 

68 event_emitter, 

69 user_agent, 

70 response_parser_factory, 

71 loader, 

72 exceptions_factory, 

73 config_store, 

74 user_agent_creator=None, 

75 ): 

76 self._event_emitter = event_emitter 

77 self._response_parser_factory = response_parser_factory 

78 self._loader = loader 

79 self._exceptions_factory = exceptions_factory 

80 self._config_store = config_store 

81 if user_agent_creator is None: 

82 self._session_ua_creator = UserAgentString.from_environment() 

83 else: 

84 self._session_ua_creator = user_agent_creator 

85 

86 def get_client_args( 

87 self, 

88 service_model, 

89 region_name, 

90 is_secure, 

91 endpoint_url, 

92 verify, 

93 credentials, 

94 scoped_config, 

95 client_config, 

96 endpoint_bridge, 

97 auth_token=None, 

98 endpoints_ruleset_data=None, 

99 partition_data=None, 

100 ): 

101 final_args = self.compute_client_args( 

102 service_model, 

103 client_config, 

104 endpoint_bridge, 

105 region_name, 

106 endpoint_url, 

107 is_secure, 

108 scoped_config, 

109 ) 

110 

111 service_name = final_args['service_name'] # noqa 

112 parameter_validation = final_args['parameter_validation'] 

113 endpoint_config = final_args['endpoint_config'] 

114 protocol = final_args['protocol'] 

115 config_kwargs = final_args['config_kwargs'] 

116 s3_config = final_args['s3_config'] 

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

118 socket_options = final_args['socket_options'] 

119 configured_endpoint_url = final_args['configured_endpoint_url'] 

120 signing_region = endpoint_config['signing_region'] 

121 endpoint_region_name = endpoint_config['region_name'] 

122 

123 event_emitter = copy.copy(self._event_emitter) 

124 signer = RequestSigner( 

125 service_model.service_id, 

126 signing_region, 

127 endpoint_config['signing_name'], 

128 endpoint_config['signature_version'], 

129 credentials, 

130 event_emitter, 

131 auth_token, 

132 ) 

133 

134 config_kwargs['s3'] = s3_config 

135 new_config = Config(**config_kwargs) 

136 endpoint_creator = EndpointCreator(event_emitter) 

137 

138 endpoint = endpoint_creator.create_endpoint( 

139 service_model, 

140 region_name=endpoint_region_name, 

141 endpoint_url=endpoint_config['endpoint_url'], 

142 verify=verify, 

143 response_parser_factory=self._response_parser_factory, 

144 max_pool_connections=new_config.max_pool_connections, 

145 proxies=new_config.proxies, 

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

147 socket_options=socket_options, 

148 client_cert=new_config.client_cert, 

149 proxies_config=new_config.proxies_config, 

150 ) 

151 

152 serializer = botocore.serialize.create_serializer( 

153 protocol, parameter_validation 

154 ) 

155 response_parser = botocore.parsers.create_parser(protocol) 

156 

157 ruleset_resolver = self._build_endpoint_resolver( 

158 endpoints_ruleset_data, 

159 partition_data, 

160 client_config, 

161 service_model, 

162 endpoint_region_name, 

163 region_name, 

164 configured_endpoint_url, 

165 endpoint, 

166 is_secure, 

167 endpoint_bridge, 

168 event_emitter, 

169 ) 

170 

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

172 client_ua_creator = self._session_ua_creator.with_client_config( 

173 new_config 

174 ) 

175 supplied_ua = client_config.user_agent if client_config else None 

176 new_config._supplied_user_agent = supplied_ua 

177 

178 return { 

179 'serializer': serializer, 

180 'endpoint': endpoint, 

181 'response_parser': response_parser, 

182 'event_emitter': event_emitter, 

183 'request_signer': signer, 

184 'service_model': service_model, 

185 'loader': self._loader, 

186 'client_config': new_config, 

187 'partition': partition, 

188 'exceptions_factory': self._exceptions_factory, 

189 'endpoint_ruleset_resolver': ruleset_resolver, 

190 'user_agent_creator': client_ua_creator, 

191 } 

192 

193 def compute_client_args( 

194 self, 

195 service_model, 

196 client_config, 

197 endpoint_bridge, 

198 region_name, 

199 endpoint_url, 

200 is_secure, 

201 scoped_config, 

202 ): 

203 service_name = service_model.endpoint_prefix 

204 protocol = service_model.metadata['protocol'] 

205 parameter_validation = True 

206 if client_config and not client_config.parameter_validation: 

207 parameter_validation = False 

208 elif scoped_config: 

209 raw_value = scoped_config.get('parameter_validation') 

210 if raw_value is not None: 

211 parameter_validation = ensure_boolean(raw_value) 

212 

213 s3_config = self.compute_s3_config(client_config) 

214 

215 configured_endpoint_url = self._compute_configured_endpoint_url( 

216 client_config=client_config, 

217 endpoint_url=endpoint_url, 

218 ) 

219 

220 endpoint_config = self._compute_endpoint_config( 

221 service_name=service_name, 

222 region_name=region_name, 

223 endpoint_url=configured_endpoint_url, 

224 is_secure=is_secure, 

225 endpoint_bridge=endpoint_bridge, 

226 s3_config=s3_config, 

227 ) 

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

229 

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

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

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

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

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

235 # property but not used by Botocore itself. 

236 preliminary_ua_string = self._session_ua_creator.with_client_config( 

237 client_config 

238 ).to_string() 

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

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

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

242 config_kwargs = dict( 

243 region_name=endpoint_config['region_name'], 

244 signature_version=endpoint_config['signature_version'], 

245 user_agent=preliminary_ua_string, 

246 ) 

247 if 'dualstack' in endpoint_variant_tags: 

248 config_kwargs.update(use_dualstack_endpoint=True) 

249 if 'fips' in endpoint_variant_tags: 

250 config_kwargs.update(use_fips_endpoint=True) 

251 if client_config is not None: 

252 config_kwargs.update( 

253 connect_timeout=client_config.connect_timeout, 

254 read_timeout=client_config.read_timeout, 

255 max_pool_connections=client_config.max_pool_connections, 

256 proxies=client_config.proxies, 

257 proxies_config=client_config.proxies_config, 

258 retries=client_config.retries, 

259 client_cert=client_config.client_cert, 

260 inject_host_prefix=client_config.inject_host_prefix, 

261 tcp_keepalive=client_config.tcp_keepalive, 

262 user_agent_extra=client_config.user_agent_extra, 

263 user_agent_appid=client_config.user_agent_appid, 

264 request_min_compression_size_bytes=( 

265 client_config.request_min_compression_size_bytes 

266 ), 

267 disable_request_compression=( 

268 client_config.disable_request_compression 

269 ), 

270 client_context_params=client_config.client_context_params, 

271 sigv4a_signing_region_set=( 

272 client_config.sigv4a_signing_region_set 

273 ), 

274 ) 

275 self._compute_retry_config(config_kwargs) 

276 self._compute_connect_timeout(config_kwargs) 

277 self._compute_user_agent_appid_config(config_kwargs) 

278 self._compute_request_compression_config(config_kwargs) 

279 s3_config = self.compute_s3_config(client_config) 

280 

281 is_s3_service = self._is_s3_service(service_name) 

282 

283 if is_s3_service and 'dualstack' in endpoint_variant_tags: 

284 if s3_config is None: 

285 s3_config = {} 

286 s3_config['use_dualstack_endpoint'] = True 

287 

288 return { 

289 'service_name': service_name, 

290 'parameter_validation': parameter_validation, 

291 'configured_endpoint_url': configured_endpoint_url, 

292 'endpoint_config': endpoint_config, 

293 'protocol': protocol, 

294 'config_kwargs': config_kwargs, 

295 's3_config': s3_config, 

296 'socket_options': self._compute_socket_options( 

297 scoped_config, client_config 

298 ), 

299 } 

300 

301 def _compute_configured_endpoint_url(self, client_config, endpoint_url): 

302 if endpoint_url is not None: 

303 return endpoint_url 

304 

305 if self._ignore_configured_endpoint_urls(client_config): 

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

307 return endpoint_url 

308 

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

310 

311 def _ignore_configured_endpoint_urls(self, client_config): 

312 if ( 

313 client_config 

314 and client_config.ignore_configured_endpoint_urls is not None 

315 ): 

316 return client_config.ignore_configured_endpoint_urls 

317 

318 return self._config_store.get_config_variable( 

319 'ignore_configured_endpoint_urls' 

320 ) 

321 

322 def compute_s3_config(self, client_config): 

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

324 

325 # Next specific client config values takes precedence over 

326 # specific values in the scoped config. 

327 if client_config is not None: 

328 if client_config.s3 is not None: 

329 if s3_configuration is None: 

330 s3_configuration = client_config.s3 

331 else: 

332 # The current s3_configuration dictionary may be 

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

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

335 # before it actually gets updated. 

336 s3_configuration = s3_configuration.copy() 

337 s3_configuration.update(client_config.s3) 

338 

339 return s3_configuration 

340 

341 def _is_s3_service(self, service_name): 

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

343 

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

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

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

347 's3-control'. 

348 """ 

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

350 

351 def _compute_endpoint_config( 

352 self, 

353 service_name, 

354 region_name, 

355 endpoint_url, 

356 is_secure, 

357 endpoint_bridge, 

358 s3_config, 

359 ): 

360 resolve_endpoint_kwargs = { 

361 'service_name': service_name, 

362 'region_name': region_name, 

363 'endpoint_url': endpoint_url, 

364 'is_secure': is_secure, 

365 'endpoint_bridge': endpoint_bridge, 

366 } 

367 if service_name == 's3': 

368 return self._compute_s3_endpoint_config( 

369 s3_config=s3_config, **resolve_endpoint_kwargs 

370 ) 

371 if service_name == 'sts': 

372 return self._compute_sts_endpoint_config(**resolve_endpoint_kwargs) 

373 return self._resolve_endpoint(**resolve_endpoint_kwargs) 

374 

375 def _compute_s3_endpoint_config( 

376 self, s3_config, **resolve_endpoint_kwargs 

377 ): 

378 force_s3_global = self._should_force_s3_global( 

379 resolve_endpoint_kwargs['region_name'], s3_config 

380 ) 

381 if force_s3_global: 

382 resolve_endpoint_kwargs['region_name'] = None 

383 endpoint_config = self._resolve_endpoint(**resolve_endpoint_kwargs) 

384 self._set_region_if_custom_s3_endpoint( 

385 endpoint_config, resolve_endpoint_kwargs['endpoint_bridge'] 

386 ) 

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

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

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

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

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

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

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

394 return endpoint_config 

395 

396 def _should_force_s3_global(self, region_name, s3_config): 

397 s3_regional_config = 'legacy' 

398 if s3_config and 'us_east_1_regional_endpoint' in s3_config: 

399 s3_regional_config = s3_config['us_east_1_regional_endpoint'] 

400 self._validate_s3_regional_config(s3_regional_config) 

401 

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

403 return s3_regional_config == 'legacy' and is_global_region 

404 

405 def _validate_s3_regional_config(self, config_val): 

406 if config_val not in VALID_REGIONAL_ENDPOINTS_CONFIG: 

407 raise botocore.exceptions.InvalidS3UsEast1RegionalEndpointConfigError( 

408 s3_us_east_1_regional_endpoint_config=config_val 

409 ) 

410 

411 def _set_region_if_custom_s3_endpoint( 

412 self, endpoint_config, endpoint_bridge 

413 ): 

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

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

416 # we have to account for this. 

417 if ( 

418 endpoint_config['signing_region'] is None 

419 and endpoint_config['region_name'] is None 

420 ): 

421 endpoint = endpoint_bridge.resolve('s3') 

422 endpoint_config['signing_region'] = endpoint['signing_region'] 

423 endpoint_config['region_name'] = endpoint['region_name'] 

424 

425 def _compute_sts_endpoint_config(self, **resolve_endpoint_kwargs): 

426 endpoint_config = self._resolve_endpoint(**resolve_endpoint_kwargs) 

427 if self._should_set_global_sts_endpoint( 

428 resolve_endpoint_kwargs['region_name'], 

429 resolve_endpoint_kwargs['endpoint_url'], 

430 endpoint_config, 

431 ): 

432 self._set_global_sts_endpoint( 

433 endpoint_config, resolve_endpoint_kwargs['is_secure'] 

434 ) 

435 return endpoint_config 

436 

437 def _should_set_global_sts_endpoint( 

438 self, region_name, endpoint_url, endpoint_config 

439 ): 

440 has_variant_tags = endpoint_config and endpoint_config.get( 

441 'metadata', {} 

442 ).get('tags') 

443 if endpoint_url or has_variant_tags: 

444 return False 

445 return ( 

446 self._get_sts_regional_endpoints_config() == 'legacy' 

447 and region_name in LEGACY_GLOBAL_STS_REGIONS 

448 ) 

449 

450 def _get_sts_regional_endpoints_config(self): 

451 sts_regional_endpoints_config = self._config_store.get_config_variable( 

452 'sts_regional_endpoints' 

453 ) 

454 if not sts_regional_endpoints_config: 

455 sts_regional_endpoints_config = 'legacy' 

456 if ( 

457 sts_regional_endpoints_config 

458 not in VALID_REGIONAL_ENDPOINTS_CONFIG 

459 ): 

460 raise botocore.exceptions.InvalidSTSRegionalEndpointsConfigError( 

461 sts_regional_endpoints_config=sts_regional_endpoints_config 

462 ) 

463 return sts_regional_endpoints_config 

464 

465 def _set_global_sts_endpoint(self, endpoint_config, is_secure): 

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

467 endpoint_config['endpoint_url'] = f'{scheme}://sts.amazonaws.com' 

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

469 

470 def _resolve_endpoint( 

471 self, 

472 service_name, 

473 region_name, 

474 endpoint_url, 

475 is_secure, 

476 endpoint_bridge, 

477 ): 

478 return endpoint_bridge.resolve( 

479 service_name, region_name, endpoint_url, is_secure 

480 ) 

481 

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

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

484 # in urllib3. 

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

486 client_keepalive = client_config and client_config.tcp_keepalive 

487 scoped_keepalive = scoped_config and self._ensure_boolean( 

488 scoped_config.get("tcp_keepalive", False) 

489 ) 

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

491 if client_keepalive or scoped_keepalive: 

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

493 return socket_options 

494 

495 def _compute_retry_config(self, config_kwargs): 

496 self._compute_retry_max_attempts(config_kwargs) 

497 self._compute_retry_mode(config_kwargs) 

498 

499 def _compute_retry_max_attempts(self, config_kwargs): 

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

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

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

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

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

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

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

507 # An explicitly provided max_attempts in the client config 

508 # overrides everything. 

509 retries = config_kwargs.get('retries') 

510 if retries is not None: 

511 if 'total_max_attempts' in retries: 

512 retries.pop('max_attempts', None) 

513 return 

514 if 'max_attempts' in retries: 

515 value = retries.pop('max_attempts') 

516 # client config max_attempts means total retries so we 

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

518 # for the initial request. 

519 retries['total_max_attempts'] = value + 1 

520 return 

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

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

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

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

525 if max_attempts is not None: 

526 if retries is None: 

527 retries = {} 

528 config_kwargs['retries'] = retries 

529 retries['total_max_attempts'] = max_attempts 

530 

531 def _compute_retry_mode(self, config_kwargs): 

532 retries = config_kwargs.get('retries') 

533 if retries is None: 

534 retries = {} 

535 config_kwargs['retries'] = retries 

536 elif 'mode' in retries: 

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

538 # that overrides everything. 

539 return 

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

541 if retry_mode is None: 

542 retry_mode = 'legacy' 

543 retries['mode'] = retry_mode 

544 

545 def _compute_connect_timeout(self, config_kwargs): 

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

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

548 # non legacy default mode has been configured. 

549 connect_timeout = config_kwargs.get('connect_timeout') 

550 if connect_timeout is not None: 

551 return 

552 connect_timeout = self._config_store.get_config_variable( 

553 'connect_timeout' 

554 ) 

555 if connect_timeout: 

556 config_kwargs['connect_timeout'] = connect_timeout 

557 

558 def _compute_request_compression_config(self, config_kwargs): 

559 min_size = config_kwargs.get('request_min_compression_size_bytes') 

560 disabled = config_kwargs.get('disable_request_compression') 

561 if min_size is None: 

562 min_size = self._config_store.get_config_variable( 

563 'request_min_compression_size_bytes' 

564 ) 

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

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

567 # config object 

568 min_size = self._validate_min_compression_size(min_size) 

569 config_kwargs['request_min_compression_size_bytes'] = min_size 

570 

571 if disabled is None: 

572 disabled = self._config_store.get_config_variable( 

573 'disable_request_compression' 

574 ) 

575 else: 

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

577 disabled = ensure_boolean(disabled) 

578 config_kwargs['disable_request_compression'] = disabled 

579 

580 def _validate_min_compression_size(self, min_size): 

581 min_allowed_min_size = 1 

582 max_allowed_min_size = 1048576 

583 if min_size is not None: 

584 error_msg_base = ( 

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

586 'request_min_compression_size_bytes.' 

587 ) 

588 try: 

589 min_size = int(min_size) 

590 except (ValueError, TypeError): 

591 msg = ( 

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

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

594 ) 

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

596 if not min_allowed_min_size <= min_size <= max_allowed_min_size: 

597 msg = ( 

598 f'{error_msg_base} Value must be between ' 

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

600 ) 

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

602 

603 return min_size 

604 

605 def _ensure_boolean(self, val): 

606 if isinstance(val, bool): 

607 return val 

608 else: 

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

610 

611 def _build_endpoint_resolver( 

612 self, 

613 endpoints_ruleset_data, 

614 partition_data, 

615 client_config, 

616 service_model, 

617 endpoint_region_name, 

618 region_name, 

619 endpoint_url, 

620 endpoint, 

621 is_secure, 

622 endpoint_bridge, 

623 event_emitter, 

624 ): 

625 if endpoints_ruleset_data is None: 

626 return None 

627 

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

629 # EndpointRulesetResolver is service-specific. Builtins for 

630 # EndpointRulesetResolver must not be derived from the legacy 

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

632 # etc. 

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

634 service_name_raw = service_model.endpoint_prefix 

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

636 # compatibility. 

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

638 eprv2_region_name = endpoint_region_name 

639 else: 

640 eprv2_region_name = region_name 

641 resolver_builtins = self.compute_endpoint_resolver_builtin_defaults( 

642 region_name=eprv2_region_name, 

643 service_name=service_name_raw, 

644 s3_config=s3_config_raw, 

645 endpoint_bridge=endpoint_bridge, 

646 client_endpoint_url=endpoint_url, 

647 legacy_endpoint_url=endpoint.host, 

648 ) 

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

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

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

652 if client_config is not None: 

653 client_context = client_config.client_context_params or {} 

654 else: 

655 client_context = {} 

656 if self._is_s3_service(service_name_raw): 

657 client_context.update(s3_config_raw) 

658 

659 sig_version = ( 

660 client_config.signature_version 

661 if client_config is not None 

662 else None 

663 ) 

664 return EndpointRulesetResolver( 

665 endpoint_ruleset_data=endpoints_ruleset_data, 

666 partition_data=partition_data, 

667 service_model=service_model, 

668 builtins=resolver_builtins, 

669 client_context=client_context, 

670 event_emitter=event_emitter, 

671 use_ssl=is_secure, 

672 requested_auth_scheme=sig_version, 

673 ) 

674 

675 def compute_endpoint_resolver_builtin_defaults( 

676 self, 

677 region_name, 

678 service_name, 

679 s3_config, 

680 endpoint_bridge, 

681 client_endpoint_url, 

682 legacy_endpoint_url, 

683 ): 

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

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

686 # always takes priority. 

687 if client_endpoint_url: 

688 given_endpoint = client_endpoint_url 

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

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

691 # endpoint resolution is provided to EndpointRulesetResolver. 

692 elif not endpoint_bridge.resolver_uses_builtin_data(): 

693 given_endpoint = legacy_endpoint_url 

694 else: 

695 given_endpoint = None 

696 

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

698 # forcing path style addressing in incompatible situations raises an 

699 # exception or silently ignores the config setting. The 

700 # AWS_S3_FORCE_PATH_STYLE parameter is adjusted both here and for each 

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

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

703 force_path_style = False 

704 elif client_endpoint_url is not None and not is_s3_accelerate_url( 

705 client_endpoint_url 

706 ): 

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

708 else: 

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

710 

711 return { 

712 EPRBuiltins.AWS_REGION: region_name, 

713 EPRBuiltins.AWS_USE_FIPS: ( 

714 # SDK_ENDPOINT cannot be combined with AWS_USE_FIPS 

715 given_endpoint is None 

716 # use legacy resolver's _resolve_endpoint_variant_config_var() 

717 # or default to False if it returns None 

718 and endpoint_bridge._resolve_endpoint_variant_config_var( 

719 'use_fips_endpoint' 

720 ) 

721 or False 

722 ), 

723 EPRBuiltins.AWS_USE_DUALSTACK: ( 

724 # SDK_ENDPOINT cannot be combined with AWS_USE_DUALSTACK 

725 given_endpoint is None 

726 # use legacy resolver's _resolve_use_dualstack_endpoint() and 

727 # or default to False if it returns None 

728 and endpoint_bridge._resolve_use_dualstack_endpoint( 

729 service_name 

730 ) 

731 or False 

732 ), 

733 EPRBuiltins.AWS_STS_USE_GLOBAL_ENDPOINT: ( 

734 self._should_set_global_sts_endpoint( 

735 region_name=region_name, 

736 endpoint_url=None, 

737 endpoint_config=None, 

738 ) 

739 ), 

740 EPRBuiltins.AWS_S3_USE_GLOBAL_ENDPOINT: ( 

741 self._should_force_s3_global(region_name, s3_config) 

742 ), 

743 EPRBuiltins.AWS_S3_ACCELERATE: s3_config.get( 

744 'use_accelerate_endpoint', False 

745 ), 

746 EPRBuiltins.AWS_S3_FORCE_PATH_STYLE: force_path_style, 

747 EPRBuiltins.AWS_S3_USE_ARN_REGION: s3_config.get( 

748 'use_arn_region', True 

749 ), 

750 EPRBuiltins.AWS_S3CONTROL_USE_ARN_REGION: s3_config.get( 

751 'use_arn_region', False 

752 ), 

753 EPRBuiltins.AWS_S3_DISABLE_MRAP: s3_config.get( 

754 's3_disable_multiregion_access_points', False 

755 ), 

756 EPRBuiltins.SDK_ENDPOINT: given_endpoint, 

757 } 

758 

759 def _compute_user_agent_appid_config(self, config_kwargs): 

760 user_agent_appid = config_kwargs.get('user_agent_appid') 

761 if user_agent_appid is None: 

762 user_agent_appid = self._config_store.get_config_variable( 

763 'user_agent_appid' 

764 ) 

765 if ( 

766 user_agent_appid is not None 

767 and len(user_agent_appid) > USERAGENT_APPID_MAXLEN 

768 ): 

769 logger.warning( 

770 'The configured value for user_agent_appid exceeds the ' 

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

772 ) 

773 config_kwargs['user_agent_appid'] = user_agent_appid