diff --git a/aiobotocore/client.py b/aiobotocore/client.py index 75498409..38df2e33 100644 --- a/aiobotocore/client.py +++ b/aiobotocore/client.py @@ -52,21 +52,40 @@ def _get_client_args(self, service_model, region_name, is_secure, response_parser_factory=self._response_parser_factory) response_parser = botocore.parsers.create_parser(protocol) - # This is only temporary in the sense that we should remove any - # region_name logic from endpoints and put it into clients. - # But that can only happen once operation objects are deprecated. - region_name = endpoint.region_name + # Determine what region the user provided either via the + # region_name argument or the client_config. + if region_name is None: + if client_config and client_config.region_name is not None: + region_name = client_config.region_name + signature_version, region_name = \ self._get_signature_version_and_region( - service_model, region_name, is_secure, scoped_config) + service_model, region_name, is_secure, scoped_config, + endpoint_url) if client_config and client_config.signature_version is not None: signature_version = client_config.signature_version + # Override the user agent if specified in the client config. + user_agent = self._user_agent + if client_config is not None: + if client_config.user_agent is not None: + user_agent = client_config.user_agent + if client_config.user_agent_extra is not None: + user_agent += ' %s' % client_config.user_agent_extra + signer = RequestSigner(service_model.service_name, region_name, service_model.signing_name, signature_version, credentials, event_emitter) + + # Create a new client config to be passed to the client based + # on the final values. We do not want the user to be able + # to try to modify an existing client with a client config. + client_config = botocore.client.Config(region_name=region_name, + signature_version=signature_version, + user_agent=user_agent) + return { 'serializer': serializer, 'endpoint': endpoint, @@ -75,6 +94,7 @@ def _get_client_args(self, service_model, region_name, is_secure, 'request_signer': signer, 'service_model': service_model, 'loader': self._loader, + 'client_config': client_config } def _create_client_class(self, service_name, service_model): diff --git a/aiobotocore/endpoint.py b/aiobotocore/endpoint.py index ee5adda2..2277b979 100644 --- a/aiobotocore/endpoint.py +++ b/aiobotocore/endpoint.py @@ -1,11 +1,26 @@ import asyncio import aiohttp +import os from aiohttp.client_reqrep import ClientResponse import botocore.endpoint -from botocore.endpoint import _get_proxies, _get_verify_value, DEFAULT_TIMEOUT +from botocore.endpoint import get_environ_proxies, DEFAULT_TIMEOUT from botocore.exceptions import EndpointConnectionError +def _get_verify_value(verify): + # This is to account for: + # https://github.com/kennethreitz/requests/issues/1436 + # where we need to honor REQUESTS_CA_BUNDLE because we're creating our + # own request objects. + # First, if verify is not None, then the user explicitly specified + # a value so this automatically wins. + if verify is not None: + return verify + # Otherwise use the value from REQUESTS_CA_BUNDLE, or default to + # True if the env var does not exist. + return os.environ.get('REQUESTS_CA_BUNDLE', True) + + def text_(s, encoding='utf-8', errors='strict'): if isinstance(s, bytes): return s.decode(encoding, errors) @@ -56,12 +71,12 @@ def read(self): class AioEndpoint(botocore.endpoint.Endpoint): - def __init__(self, region_name, host, user_agent, + def __init__(self, host, endpoint_prefix, event_emitter, proxies=None, verify=True, timeout=DEFAULT_TIMEOUT, response_parser_factory=None, loop=None): - super().__init__(region_name, host, user_agent, endpoint_prefix, + super().__init__(host, endpoint_prefix, event_emitter, proxies=proxies, verify=verify, timeout=timeout, response_parser_factory=response_parser_factory) @@ -101,6 +116,9 @@ def _send_request(self, request_dict, operation_model): success_response, exception = yield from self._get_response( request, operation_model, attempts) + if exception is not None: + raise exception + return success_response @asyncio.coroutine @@ -147,32 +165,27 @@ class AioEndpointCreator(botocore.endpoint.EndpointCreator): def __init__(self, endpoint_resolver, configured_region, event_emitter, user_agent, loop): - super().__init__(endpoint_resolver, configured_region, event_emitter, - user_agent) + super().__init__(endpoint_resolver, configured_region, event_emitter) self._loop = loop - def _get_endpoint(self, service_model, region_name, endpoint_url, + def _get_endpoint(self, service_model, endpoint_url, verify, response_parser_factory): - service_name = service_model.signing_name endpoint_prefix = service_model.endpoint_prefix - user_agent = self._user_agent event_emitter = self._event_emitter - user_agent = self._user_agent - return get_endpoint_complex(service_name, endpoint_prefix, - region_name, endpoint_url, - verify, user_agent, event_emitter, + return get_endpoint_complex(endpoint_prefix, + endpoint_url, + verify, event_emitter, response_parser_factory, loop=self._loop) -def get_endpoint_complex(service_name, endpoint_prefix, - region_name, endpoint_url, verify, - user_agent, event_emitter, +def get_endpoint_complex(endpoint_prefix, + endpoint_url, verify, + event_emitter, response_parser_factory=None, loop=None): - proxies = _get_proxies(endpoint_url) + proxies = get_environ_proxies(endpoint_url) verify = _get_verify_value(verify) return AioEndpoint( - region_name, endpoint_url, - user_agent=user_agent, + endpoint_url, endpoint_prefix=endpoint_prefix, event_emitter=event_emitter, proxies=proxies, diff --git a/aiobotocore/session.py b/aiobotocore/session.py index 679cf387..1612e905 100644 --- a/aiobotocore/session.py +++ b/aiobotocore/session.py @@ -1,6 +1,6 @@ import asyncio import botocore.session -from botocore import retryhandler, translate +from botocore import retryhandler, translate, utils from .client import AioClientCreator @@ -11,15 +11,20 @@ def __init__(self, session_vars=None, event_hooks=None, include_builtin_handlers=True, loader=None, loop=None): super().__init__(session_vars=session_vars, event_hooks=event_hooks, - include_builtin_handlers=include_builtin_handlers, - loader=loader) + include_builtin_handlers=include_builtin_handlers) self._loop = loop + self._loader = loader def create_client(self, service_name, region_name=None, api_version=None, use_ssl=True, verify=None, endpoint_url=None, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, config=None): + # work around stupid bug in botocore where fix_s3_host destroys specified + # endpoint url + if endpoint_url is not None: + self.unregister('before-sign.s3', utils.fix_s3_host) + if region_name is None: region_name = self.get_config_variable('region') loader = self.get_component('data_loader')