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
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
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.
15This module (and all function/classes within this module) should be
16considered internal, and *not* a public API.
18"""
20import copy
21import logging
22import socket
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
35logger = logging.getLogger(__name__)
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
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
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 )
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']
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 )
134 config_kwargs['s3'] = s3_config
135 new_config = Config(**config_kwargs)
136 endpoint_creator = EndpointCreator(event_emitter)
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 )
152 serializer = botocore.serialize.create_serializer(
153 protocol, parameter_validation
154 )
155 response_parser = botocore.parsers.create_parser(protocol)
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 )
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
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 }
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)
213 s3_config = self.compute_s3_config(client_config)
215 configured_endpoint_url = self._compute_configured_endpoint_url(
216 client_config=client_config,
217 endpoint_url=endpoint_url,
218 )
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', [])
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)
281 is_s3_service = self._is_s3_service(service_name)
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
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 }
301 def _compute_configured_endpoint_url(self, client_config, endpoint_url):
302 if endpoint_url is not None:
303 return endpoint_url
305 if self._ignore_configured_endpoint_urls(client_config):
306 logger.debug("Ignoring configured endpoint URLs.")
307 return endpoint_url
309 return self._config_store.get_config_variable('endpoint_url')
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
318 return self._config_store.get_config_variable(
319 'ignore_configured_endpoint_urls'
320 )
322 def compute_s3_config(self, client_config):
323 s3_configuration = self._config_store.get_config_variable('s3')
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)
339 return s3_configuration
341 def _is_s3_service(self, service_name):
342 """Whether the service is S3 or S3 Control.
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']
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)
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
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)
402 is_global_region = region_name in ('us-east-1', None)
403 return s3_regional_config == 'legacy' and is_global_region
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 )
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']
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
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 )
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
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'
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 )
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
495 def _compute_retry_config(self, config_kwargs):
496 self._compute_retry_max_attempts(config_kwargs)
497 self._compute_retry_mode(config_kwargs)
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
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
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
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
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
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)
603 return min_size
605 def _ensure_boolean(self, val):
606 if isinstance(val, bool):
607 return val
608 else:
609 return val.lower() == 'true'
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
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)
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 )
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
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'
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 }
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