'Connects to the server and issues a request.  Handles converting
any returned HTTP error status codes to OpenStack/Glance exceptions
and closing the server connection. Returns the result data, or
raises an appropriate exception.
:param method: HTTP method ("GET", "POST", "PUT", etc...)
:param url: urlparse.ParsedResult object with URL information
:param body: data to send (as string, filelike or iterable),
or None (default)
:param headers: mapping of key/value pairs to add as headers
:note
If the body param has a read attribute, and method is either
POST or PUT, this method will automatically conduct a chunked-transfer
encoding and use the body as a file object or iterable, transferring
chunks of data using the connection\'s send() method. This allows large
objects to be transferred efficiently without buffering the entire
body in memory.'

@handle_redirects
def _do_request(self, method, url, body, headers):

    if url.query:
        path = ((url.path + '?') + url.query)
    else:
        path = url.path
    try:
        connection_type = self.get_connection_type()
        headers = self._encode_headers((headers or {}))
        headers.update(osprofiler.web.get_trace_id_headers())
        if (('x-auth-token' not in headers) and self.auth_token):
            headers['x-auth-token'] = self.auth_token
        c = connection_type(url.hostname, url.port, **self.connect_kwargs)
        def _pushing(method):
            return (method.lower() in ('post', 'put'))
        def _simple(body):
            return ((body is None) or isinstance(body, bytes))
        def _filelike(body):
            return hasattr(body, 'read')
        def _sendbody(connection, iter):
            connection.endheaders()
            for sent in iter:
                pass
        def _chunkbody(connection, iter):
            connection.putheader('Transfer-Encoding', 'chunked')
            connection.endheaders()
            for chunk in iter:
                connection.send(('%x\r\n%s\r\n' % (len(chunk), chunk)))
            connection.send('0\r\n\r\n')
        if ((not _pushing(method)) or _simple(body)):
            c.request(method, path, body, headers)
        elif (_filelike(body) or self._iterable(body)):
            c.putrequest(method, path)
            use_sendfile = self._sendable(body)
            for (header, value) in headers.items():
                if (use_sendfile or (header.lower() != 'content-length')):
                    c.putheader(header, str(value))
            iter = utils.chunkreadable(body)
            if use_sendfile:
                _sendbody(c, iter)
            else:
                _chunkbody(c, iter)
        else:
            raise TypeError(('Unsupported    image    type:    %s' % body.__class__))
        res = c.getresponse()
        def _retry(res):
            return res.getheader('Retry-After')
        def read_body(res):
            body = res.read()
            if six.PY3:
                body = body.decode('utf-8')
            return body
        status_code = self.get_status_code(res)
        if (status_code in self.OK_RESPONSE_CODES):
            return res
        elif (status_code in self.REDIRECT_RESPONSE_CODES):
            raise exception.RedirectException(res.getheader('Location'))
        elif (status_code == http_client.UNAUTHORIZED):
            raise exception.NotAuthenticated(read_body(res))
        elif (status_code == http_client.FORBIDDEN):
            raise exception.Forbidden(read_body(res))
        elif (status_code == http_client.NOT_FOUND):
            raise exception.NotFound(read_body(res))
        elif (status_code == http_client.CONFLICT):
            raise exception.Duplicate(read_body(res))
        elif (status_code == http_client.BAD_REQUEST):
            raise exception.Invalid(read_body(res))
        elif (status_code == http_client.MULTIPLE_CHOICES):
            raise exception.MultipleChoices(body=read_body(res))
        elif (status_code == http_client.REQUEST_ENTITY_TOO_LARGE):
            raise exception.LimitExceeded(retry=_retry(res), body=read_body(res))
        elif (status_code == http_client.INTERNAL_SERVER_ERROR):
            raise exception.ServerError()
        elif (status_code == http_client.SERVICE_UNAVAILABLE):
            raise exception.ServiceUnavailable(retry=_retry(res))
        else:
            raise exception.UnexpectedStatus(status=status_code, body=read_body(res))
    except (socket.error, IOError) as e:
        raise exception.ClientConnectionError(e)
