def __init__(self, region_name, host, auth, user_agent, signature_version, endpoint_prefix, event_emitter, proxies=None, verify=True, timeout=DEFAULT_TIMEOUT): self._endpoint_prefix = endpoint_prefix self._signature_version = signature_version self._event_emitter = event_emitter self._user_agent = user_agent self.region_name = region_name self.host = host self.verify = verify self.auth = auth if proxies is None: proxies = {} self.proxies = proxies self.http_session = Session() self.timeout = timeout self._lock = threading.Lock()
class Endpoint(object): """ Represents an endpoint for a particular service in a specific region. Only an endpoint can make requests. :ivar service: The Service object that describes this endpoints service. :ivar host: The fully qualified endpoint hostname. :ivar session: The session object. """ def __init__(self, region_name, host, auth, user_agent, signature_version, endpoint_prefix, event_emitter, proxies=None, verify=True, timeout=DEFAULT_TIMEOUT): self._endpoint_prefix = endpoint_prefix self._signature_version = signature_version self._event_emitter = event_emitter self._user_agent = user_agent self.region_name = region_name self.host = host self.verify = verify self.auth = auth if proxies is None: proxies = {} self.proxies = proxies self.http_session = Session() self.timeout = timeout self._lock = threading.Lock() def __repr__(self): return '%s(%s)' % (self._endpoint_prefix, self.host) def make_request(self, operation_model, request_dict): logger.debug("Making request for %s (verify_ssl=%s) with params: %s", operation_model, self.verify, request_dict) prepared_request = self.create_request(request_dict) return self._send_request(prepared_request, operation_model) def create_request(self, params, signer=None): # To decide if we need to do auth or not we check the # signature_version attribute on both the service and # the operation are not None and we make sure there is an # auth class associated with the endpoint. # If any of these are not true, we skip auth. if signer is not None: # If the user explicitly specifies a signer, then we will sign # the request. signer = signer else: do_auth = self._signature_version and self.auth if do_auth: signer = self.auth else: # If we're not suppose to sign the request, then we set the signer # to None. signer = None request = self._create_request_object(params) prepared_request = self.prepare_request(request, signer) return prepared_request def _create_request_object(self, request_dict): r = request_dict user_agent = self._user_agent headers = r['headers'] headers['User-Agent'] = user_agent url = urljoin(self.host, r['url_path']) if r['query_string']: encoded_query_string = percent_encode_sequence(r['query_string']) if '?' not in url: url += '?%s' % encoded_query_string else: url += '&%s' % encoded_query_string request = AWSRequest(method=r['method'], url=url, data=r['body'], headers=headers) return request def prepare_request(self, request, signer): if signer is not None: with self._lock: # Parts of the auth signing code aren't thread safe (things # that manipulate .auth_path), so we're using a lock here to # prevent race conditions. event_name = 'before-auth.%s' % self._endpoint_prefix self._event_emitter.emit( event_name, endpoint=self, request=request, auth=signer) signer.add_auth(request=request) prepared_request = request.prepare() return prepared_request def _send_request(self, request, operation_model): attempts = 1 response, exception = self._get_response(request, operation_model, attempts) while self._needs_retry(attempts, operation_model, response, exception): attempts += 1 # If there is a stream associated with the request, we need # to reset it before attempting to send the request again. # This will ensure that we resend the entire contents of the # body. request.reset_stream() response, exception = self._get_response(request, operation_model, attempts) return response def _get_response(self, request, operation_model, attempts): try: logger.debug("Sending http request: %s", request) http_response = self.http_session.send( request, verify=self.verify, stream=operation_model.has_streaming_output, proxies=self.proxies, timeout=self.timeout) except Exception as e: logger.debug("Exception received when sending HTTP request.", exc_info=True) return (None, e) # This returns the http_response and the parsed_data. return (botocore_eb.response.get_response(operation_model, http_response), None) def _needs_retry(self, attempts, operation_model, response=None, caught_exception=None): event_name = 'needs-retry.%s.%s' % (self._endpoint_prefix, operation_model.name) responses = self._event_emitter.emit( event_name, response=response, endpoint=self, operation=operation_model, attempts=attempts, caught_exception=caught_exception) handler_response = first_non_none_response(responses) if handler_response is None: return False else: # Request needs to be retried, and we need to sleep # for the specified number of times. logger.debug("Response received to retry, sleeping for " "%s seconds", handler_response) time.sleep(handler_response) return True
class Endpoint(object): """ Represents an endpoint for a particular service in a specific region. Only an endpoint can make requests. :ivar service: The Service object that describes this endpoints service. :ivar host: The fully qualified endpoint hostname. :ivar session: The session object. """ def __init__(self, region_name, host, auth, user_agent, signature_version, endpoint_prefix, event_emitter, proxies=None, verify=True, timeout=DEFAULT_TIMEOUT): self._endpoint_prefix = endpoint_prefix self._signature_version = signature_version self._event_emitter = event_emitter self._user_agent = user_agent self.region_name = region_name self.host = host self.verify = verify self.auth = auth if proxies is None: proxies = {} self.proxies = proxies self.http_session = Session() self.timeout = timeout self._lock = threading.Lock() def __repr__(self): return '%s(%s)' % (self._endpoint_prefix, self.host) def make_request(self, operation_model, request_dict): logger.debug("Making request for %s (verify_ssl=%s) with params: %s", operation_model, self.verify, request_dict) prepared_request = self.create_request(request_dict) return self._send_request(prepared_request, operation_model) def create_request(self, params, signer=None): # To decide if we need to do auth or not we check the # signature_version attribute on both the service and # the operation are not None and we make sure there is an # auth class associated with the endpoint. # If any of these are not true, we skip auth. if signer is not None: # If the user explicitly specifies a signer, then we will sign # the request. signer = signer else: do_auth = self._signature_version and self.auth if do_auth: signer = self.auth else: # If we're not suppose to sign the request, then we set the signer # to None. signer = None request = self._create_request_object(params) prepared_request = self.prepare_request(request, signer) return prepared_request def _create_request_object(self, request_dict): r = request_dict user_agent = self._user_agent headers = r['headers'] headers['User-Agent'] = user_agent url = urljoin(self.host, r['url_path']) if r['query_string']: encoded_query_string = percent_encode_sequence(r['query_string']) if '?' not in url: url += '?%s' % encoded_query_string else: url += '&%s' % encoded_query_string request = AWSRequest(method=r['method'], url=url, data=r['body'], headers=headers) return request def prepare_request(self, request, signer): if signer is not None: with self._lock: # Parts of the auth signing code aren't thread safe (things # that manipulate .auth_path), so we're using a lock here to # prevent race conditions. event_name = 'before-auth.%s' % self._endpoint_prefix self._event_emitter.emit(event_name, endpoint=self, request=request, auth=signer) signer.add_auth(request=request) prepared_request = request.prepare() return prepared_request def _send_request(self, request, operation_model): attempts = 1 response, exception = self._get_response(request, operation_model, attempts) while self._needs_retry(attempts, operation_model, response, exception): attempts += 1 # If there is a stream associated with the request, we need # to reset it before attempting to send the request again. # This will ensure that we resend the entire contents of the # body. request.reset_stream() response, exception = self._get_response(request, operation_model, attempts) return response def _get_response(self, request, operation_model, attempts): try: logger.debug("Sending http request: %s", request) http_response = self.http_session.send( request, verify=self.verify, stream=operation_model.has_streaming_output, proxies=self.proxies, timeout=self.timeout) except Exception as e: logger.debug("Exception received when sending HTTP request.", exc_info=True) return (None, e) # This returns the http_response and the parsed_data. return (botocore_eb.response.get_response(operation_model, http_response), None) def _needs_retry(self, attempts, operation_model, response=None, caught_exception=None): event_name = 'needs-retry.%s.%s' % (self._endpoint_prefix, operation_model.name) responses = self._event_emitter.emit(event_name, response=response, endpoint=self, operation=operation_model, attempts=attempts, caught_exception=caught_exception) handler_response = first_non_none_response(responses) if handler_response is None: return False else: # Request needs to be retried, and we need to sleep # for the specified number of times. logger.debug( "Response received to retry, sleeping for " "%s seconds", handler_response) time.sleep(handler_response) return True