docs: def _rest_op(self, operation, suburi, request_headers, request_body):
          """Generic REST Operation handler."""
  
          url = urlparse.urlparse('https://' + self.host + suburi)
          # Used for logging on redirection error.
          start_url = url.geturl()
  
          LOG.debug(self._("%(operation)s %(url)s"),
                    {'operation': operation, 'url': start_url})
  
          if request_headers is None or not isinstance(request_headers, dict):
              request_headers = {}
  
          # Use self.login/self.password and Basic Auth
          if self.login is not None and self.password is not None:
              auth_data = self.login + ":" + self.password
              hr = "BASIC " + base64.b64encode(
                  auth_data.encode('ascii')).decode("utf-8")
              request_headers['Authorization'] = hr
  
          if request_body is not None:
              if (isinstance(request_body, dict)
                      or isinstance(request_body, list)):
                  request_headers['Content-Type'] = 'application/json'
              else:
                  request_headers['Content-Type'] = ('application/'
                                                     'x-www-form-urlencoded')
  
          """Helper methods to retry and keep retrying on redirection - START"""
  
          def retry_if_response_asks_for_redirection(response):
              # NOTE:Do not assume every HTTP operation will return a JSON
              # request_body. For example, ExtendedError structures are only
              # required for HTTP 400 errors and are optional elsewhere as they
              # are mostly redundant for many of the other HTTP status code.
              # In particular, 200 OK responses should not have to return any
              # request_body.
  
              # NOTE:  this makes sure the headers names are all lower cases
              # because HTTP says they are case insensitive
              # Follow HTTP redirect
              if response.status_code == 301 and 'location' in response.headers:
                  retry_if_response_asks_for_redirection.url = (
                      urlparse.urlparse(response.headers['location']))
                  LOG.debug(self._("Request redirected to %s."),
                            retry_if_response_asks_for_redirection.url.geturl())
                  return True
              return False
  
          @retrying.retry(
              # Note(deray): Return True if we should retry, False otherwise.
              # In our case, when the url response we receive asks for
              # redirection then we retry.
              retry_on_result=retry_if_response_asks_for_redirection,
              # Note(deray): Return True if we should retry, False otherwise.
              # In our case, when it's an IloConnectionError we don't retry.
              # ``requests`` already takes care of issuing max number of
              # retries if the URL service is unavailable.
              retry_on_exception=(
                  lambda e: not isinstance(e, exception.IloConnectionError)),
              stop_max_attempt_number=REDIRECTION_ATTEMPTS)
          def _fetch_response():
  
              url = retry_if_response_asks_for_redirection.url
  
              kwargs = {'headers': request_headers,
                        'data': json.dumps(request_body)}
              if self.cacert is not None:
                  kwargs['verify'] = self.cacert
              else:
                  kwargs['verify'] = False
  
              LOG.debug(self._('\n\tHTTP REQUEST: %(restreq_method)s'
                               '\n\tPATH: %(restreq_path)s'
                               '\n\tBODY: %(restreq_body)s'
                               '\n'),
                        {'restreq_method': operation,
                         'restreq_path': url.geturl(),
                         'restreq_body': request_body})
  
              request_method = getattr(requests, operation.lower())
              try:
                  response = request_method(url.geturl(), **kwargs)
              except Exception as e:
                  LOG.debug(self._("Unable to connect to iLO. %s"), e)
                  raise exception.IloConnectionError(e)
  
              return response
  
          """Helper methods to retry and keep retrying on redirection - END"""
  
          try:
              # Note(deray): This is a trick to use the function attributes
              # to overwrite variable/s (in our case ``url``) and use the
              # modified one in nested functions, i.e. :func:`_fetch_response`
              # and :func:`retry_if_response_asks_for_redirection`
              retry_if_response_asks_for_redirection.url = url
  
              response = _fetch_response()
          except retrying.RetryError as e:
              # Redirected for REDIRECTION_ATTEMPTS - th time. Throw error
              msg = (self._("URL Redirected %(times)s times continuously. "
                            "URL used: %(start_url)s More info: %(error)s") %
                     {'start_url': start_url, 'times': REDIRECTION_ATTEMPTS,
                      'error': str(e)})
              LOG.debug(msg)
              raise exception.IloConnectionError(msg)
  
          response_body = {}
          if response.text:
              try:
                  response_body = json.loads(response.text)
              except (TypeError, ValueError):
                  # Note(deray): If it doesn't decode as json, then
                  # resources may return gzipped content.
                  # ``json.loads`` on python3 raises TypeError when
                  # ``response.text`` is gzipped one.
                  response_body = (
                      self._get_response_body_from_gzipped_content(url,
                                                                   response))
  
          LOG.debug(self._('\n\tHTTP RESPONSE for %(restreq_path)s:'
                           '\n\tCode: %(status_code)s'
                           '\n\tResponse Body: %(response_body)s'
                           '\n'),
                    {'restreq_path': url.geturl(),
                     'status_code': response.status_code,
                     'response_body': response_body})
          return response.status_code, response.headers, response_body