"""Helper methods for CORS and CSRF checks. """
import logging
import urlparse
import contextlib

from django.conf import settings

log = logging.getLogger(__name__)


def is_cross_domain_request_allowed(request):
    """Check whether we should allow the cross-domain request.

    We allow a cross-domain request only if:

    1) The request is made securely and the referer has "https://" as the protocol.
    2) The referer domain has been whitelisted.

    Arguments:
        request (HttpRequest)

    Returns:
        bool

    """
    referer = request.META.get('HTTP_REFERER')
    referer_parts = urlparse.urlparse(referer) if referer else None
    referer_hostname = referer_parts.hostname if referer_parts is not None else None

    # Use CORS_ALLOW_INSECURE *only* for development and testing environments;
    # it should never be enabled in production.
    if not getattr(settings, 'CORS_ALLOW_INSECURE', False):
        if not request.is_secure():
            log.debug(
                u"Request is not secure, so we cannot send the CSRF token. "
                u"For testing purposes, you can disable this check by setting "
                u"`CORS_ALLOW_INSECURE` to True in the settings"
            )
            return False

        if not referer:
            log.debug(u"No referer provided over a secure connection, so we cannot check the protocol.")
            return False

        if not referer_parts.scheme == 'https':
            log.debug(u"Referer '%s' must have the scheme 'https'")
            return False

    domain_is_whitelisted = (
        getattr(settings, 'CORS_ORIGIN_ALLOW_ALL', False) or
        referer_hostname in getattr(settings, 'CORS_ORIGIN_WHITELIST', [])
    )
    if not domain_is_whitelisted:
        if referer_hostname is None:
            # If no referer is specified, we can't check if it's a cross-domain
            # request or not.
            log.debug(u"Referrer hostname is `None`, so it is not on the whitelist.")
        elif referer_hostname != request.get_host():
            log.info(
                (
                    u"Domain '%s' is not on the cross domain whitelist.  "
                    u"Add the domain to `CORS_ORIGIN_WHITELIST` or set "
                    u"`CORS_ORIGIN_ALLOW_ALL` to True in the settings."
                ), referer_hostname
            )
        else:
            log.debug(
                (
                    u"Domain '%s' is the same as the hostname in the request, "
                    u"so we are not going to treat it as a cross-domain request."
                ), referer_hostname
            )
        return False

    return True


@contextlib.contextmanager
def skip_cross_domain_referer_check(request):
    """Skip the cross-domain CSRF referer check.

    Django's CSRF middleware performs the referer check
    only when the request is made over a secure connection.
    To skip the check, we patch `request.is_secure()` to
    False.
    """
    is_secure_default = request.is_secure
    request.is_secure = lambda: False
    try:
        yield
    finally:
        request.is_secure = is_secure_default