'Send a HTTP request with keystone auth and using the catalog
This method will send an HTTP request using keystone auth in the
headers and the catalog to determine the endpoint to use for the
baseurl to send the request to. Additionally
When a response is received it will check it to see if an error
response was received. If it was an exception will be raised to enable
it to be handled quickly.
This method will also handle rate-limiting, if a 413 response code is
received it will retry the request after waiting the \'retry-after\'
duration from the header.
:param str method: The HTTP verb to use for the request
:param str url: Relative url to send the request to
:param bool extra_headers: Boolean value than indicates if the headers
returned by the get_headers() method are to
be used but additional headers are needed in
the request pass them in as a dict.
:param dict headers: Headers to use for the request if none are
specifed the headers returned from the
get_headers() method are used. If the request
explicitly requires no headers use an empty dict.
:param str body: Body to send with the request
:param bool chunked: sends the body with chunked encoding
:rtype: tuple
:return: a tuple with the first entry containing the response headers
and the second the response body
:raises UnexpectedContentType: If the content-type of the response
isn\'t an expect type
:raises Unauthorized: If a 401 response code is received
:raises Forbidden: If a 403 response code is received
:raises NotFound: If a 404 response code is received
:raises BadRequest: If a 400 response code is received
:raises Gone: If a 410 response code is received
:raises Conflict: If a 409 response code is received
:raises PreconditionFailed: If a 412 response code is received
:raises OverLimit: If a 413 response code is received and over_limit is
not in the response body
:raises RateLimitExceeded: If a 413 response code is received and
over_limit is in the response body
:raises InvalidContentType: If a 415 response code is received
:raises UnprocessableEntity: If a 422 response code is received
:raises InvalidHTTPResponseBody: The response body wasn\'t valid JSON
and couldn\'t be parsed
:raises NotImplemented: If a 501 response code is received
:raises ServerFault: If a 500 response code is received
:raises UnexpectedResponseCode: If a response code above 400 is
received and it doesn\'t fall into any
of the handled checks'

def request(self, method, url, extra_headers=False, headers=None, body=None, chunked=False):

    retry = 0
    if (headers is None):
        headers = self.get_headers()
    elif extra_headers:
        try:
            headers.update(self.get_headers())
        except (ValueError, TypeError):
            headers = self.get_headers()
    (resp, resp_body) = self._request(method, url, headers=headers, body=body, chunked=chunked)
    while ((resp.status == 413) and ('retry-after' in resp) and (not self.is_absolute_limit(resp, self._parse_resp(resp_body))) and (retry < MAX_RECURSION_DEPTH)):
        retry += 1
        delay = self._get_retry_after_delay(resp)
        self.LOG.debug('Sleeping    %s    seconds    based    on    retry-after    header', delay)
        time.sleep(delay)
        (resp, resp_body) = self._request(method, url, headers=headers, body=body)
    self._error_checker(resp, resp_body)
    return (resp, resp_body)
