def on_response(response): exception = response.exception() if exception: awz_error = self._awz_error(exception) if awz_error: if self._credentials_error(awz_error): self._auth_config.reset() if not self._auth_config.local_credentials: if not _recursed: def on_retry(retry): if not self._future_exception( retry, future): future.set_result(retry.result()) request = self.fetch(method, path, query_args, headers, body, True) self._ioloop.add_future(request, on_retry) return msg = awz_error.get('message', awz_error.get('Message')) if not msg: LOGGER.debug('awz_error without message: %r', awz_error) exception = exceptions.AWSError(type=awz_error['__type'], message=msg) future.set_exception(exception) else: future.set_result(response.result())
def _process_error(self, error): """Attempt to process the error coming from AWS. Returns ``True`` if the client should attempt to fetch credentials and the AWSError exception to raise if the client did not have an authentication error. :param tornado.httpclient.HTTPError error: The HTTP error :rtype: (tuple, tornado_aws.exceptions.AWSError) """ LOGGER.error('Error: %r', error) if error.code == 599: return False, None elif error.code == 400 and self._awz_response(error.response): awz_error = self._parse_awz_error(error.response.body) return ((awz_error and awz_error['__type'] in _REFRESH_EXCEPTIONS), exceptions.AWSError(type=awz_error['__type'], message=awz_error.get( 'message', '(null)'))) try: xml_error = self._parse_xml_error(error.response.body) except ValueError: LOGGER.debug('Could not fallback to XML: %r', error) return False, None return ((xml_error and xml_error['Code'] in _REFRESH_XML_EXCEPTIONS), self._aws_error_from_xml(xml_error))
def _aws_error_from_xml(error): """Return an AWSError exception for an XML error response, given the variation in field names. :param dict error: The parsed XML error :rtype: tornado_aws.exceptions.AWSError """ return exceptions.AWSError(type=error['Code'], message=error['Message'], request_id=error.get( 'RequestId', error.get('x-amzn-RequestId')), resource=error.get('Resource'))
def fetch(self, method, path='/', query_args=None, headers=None, body=b'', _recursed=False): """Executes a request, returning an :py:class:`HTTPResponse <tornado.httpclient.HTTPResponse>`. If an error occurs during the fetch, we raise an :py:class:`HTTPError <tornado.httpclient.HTTPError>` unless the ``raise_error`` keyword argument is set to ``False``. :param str method: HTTP request method :param str path: The request path :param dict query_args: Request query arguments :param dict headers: Request headers :param bytes body: The request body :rtype: :class:`~tornado.httpclient.HTTPResponse` :raises: :class:`~tornado.httpclient.HTTPError` :raises: :class:`~tornado_aws.exceptions.NoCredentialsError` :raises: :class:`~tornado_aws.exceptions.AWSError` """ if self._auth_config.needs_credentials(): self._auth_config.refresh() request = self._create_request(method, path, query_args, headers, body) try: result = self._client.fetch(request, raise_error=True) return result except httpclient.HTTPError as error: awz_error = self._awz_error(error) if awz_error: if self._credentials_error(awz_error): if not self._auth_config.local_credentials: if not _recursed: self._auth_config.refresh() return self.fetch(method, path, query_args, headers, body, True) else: self._auth_config.reset() raise exceptions.AWSError(type=awz_error['__type'], message=awz_error['message']) raise