Try 3 times to request the content.

    :param headers: The HTTP headers
    :type headers: dict
    :param body: The body of the HTTP post
    :type body: str
    :param retries: The number of times to retry before giving up
    :type retries: int
    :param timeout: The time to wait for the post to complete, before timing
        out
    :type timeout: float

def _post(url, headers, body, retries=3, timeout=3.0):
    """Try 3 times to request the content.

    :param headers: The HTTP headers
    :type headers: dict
    :param body: The body of the HTTP post
    :type body: str
    :param retries: The number of times to retry before giving up
    :type retries: int
    :param timeout: The time to wait for the post to complete, before timing
        out
    :type timeout: float
    """
    retry = 0
    out = None
    while out is None:
        try:
            out = requests.post(url, headers=headers, data=body,
                                timeout=timeout)
        # Due to a bug in requests, the post command will sometimes fail to
        # properly wrap a socket.timeout exception in requests own exception.
        # See https://github.com/kennethreitz/requests/issues/2045
        # Until this is fixed, we need to catch both types of exceptions
        except (requests.exceptions.Timeout, socket.timeout) as exception:
            retry += 1
            if retry == retries:
                # pylint: disable=maybe-no-member
                raise requests.exceptions.Timeout(exception.message)
    return out