docs: def _perform_request(self, request, parser=None, parser_args=None, operation_context=None):
          '''
          Sends the request and return response. Catches HTTPError and hands it
          to error handler
          '''
          operation_context = operation_context or _OperationContext()
          retry_context = RetryContext()
  
          # Apply the appropriate host based on the location mode
          self._apply_host(request, operation_context, retry_context)
  
          # Apply common settings to the request
          _update_request(request)
  
          while(True):
              try:
                  try:
                      # Execute the request callback 
                      if self.request_callback:
                          self.request_callback(request)
  
                      # Add date and auth after the callback so date doesn't get too old and 
                      # authentication is still correct if signed headers are added in the request 
                      # callback. This also ensures retry policies with long back offs 
                      # will work as it resets the time sensitive headers.
                      _add_date_header(request)
                      self.authentication.sign_request(request)
  
                      # Set the request context
                      retry_context.request = request
  
                      # Perform the request
                      response = self._httpclient.perform_request(request)
  
                      # Execute the response callback
                      if self.response_callback:
                          self.response_callback(response)
  
                      # Set the response context
                      retry_context.response = response
  
                      # Parse and wrap HTTP errors in AzureHttpError which inherits from AzureException
                      if response.status >= 300:
                          # This exception will be caught by the general error handler
                          # and raised as an azure http exception
                          _http_error_handler(HTTPError(response.status, response.message, response.headers, response.body))
  
                      # Parse the response
                      if parser:
                          if parser_args:
                              args = [response]
                              args.extend(parser_args)
                              return parser(*args)
                          else:
                              return parser(response)
                      else:
                          return
                  except AzureException as ex:
                      raise ex
                  except Exception as ex:
                      if sys.version_info >= (3,):
                          # Automatic chaining in Python 3 means we keep the trace
                          raise AzureException(ex.args[0])
                      else:
                          # There isn't a good solution in 2 for keeping the stack trace 
                          # in general, or that will not result in an error in 3
                          # However, we can keep the previous error type and message
                          # TODO: In the future we will log the trace
                          msg = ""
                          if len(ex.args) > 0:
                              msg = ex.args[0]
                          raise AzureException('{}: {}'.format(ex.__class__.__name__, msg))
  
  
              except AzureException as ex:
                  # Decryption failures (invalid objects, invalid algorithms, data unencrypted in strict mode, etc)
                  # will not be resolved with retries.
                  if str(ex) == _ERROR_DECRYPTION_FAILURE:
                      raise ex
                  # Determine whether a retry should be performed and if so, how 
                  # long to wait before performing retry.
                  retry_interval = self.retry(retry_context)
                  if retry_interval is not None:
                      # Execute the callback
                      if self.retry_callback:
                          self.retry_callback(retry_context)
  
                      # Sleep for the desired retry interval
                      sleep(retry_interval)
                  else:
                      raise ex
              finally:
                  # If this is a location locked operation and the location is not set, 
                  # this is the first request of that operation. Set the location to 
                  # be used for subsequent requests in the operation.
                  if operation_context.location_lock and not operation_context.host_location:
                      operation_context.host_location = {retry_context.location_mode: request.host}