Exemple #1
0
def get_cors_headers(options, request_headers, request_method):
    origins_to_set = get_cors_origins(options, request_headers.get('Origin'))
    headers = CIMultiDict()

    if not origins_to_set:  # CORS is not enabled for this route
        return headers

    for origin in origins_to_set:
        # TODO, with CIDict, with will only allow one origin
        # With CIMultiDict it should work with multiple
        headers[ACL_ORIGIN] = origin

    headers[ACL_EXPOSE_HEADERS] = options.get('expose_headers')

    if options.get('supports_credentials'):
        headers[ACL_CREDENTIALS] = 'true'  # case sensative

    # This is a preflight request
    # http://www.w3.org/TR/cors/#resource-preflight-requests
    if request_method == 'OPTIONS':
        acl_request_method = request_headers.get(ACL_REQUEST_METHOD,
                                                 '').upper()

        # If there is no Access-Control-Request-Method header or if parsing
        # failed, do not set any additional headers
        if acl_request_method and acl_request_method in options.get('methods'):

            # If method is not a case-sensitive match for any of the values in
            # list of methods do not set any additional headers and terminate
            # this set of steps.
            headers[ACL_ALLOW_HEADERS] = get_allow_headers(
                options, request_headers.get(ACL_REQUEST_HEADERS))
            headers[ACL_MAX_AGE] = str(options.get(
                'max_age'))  # sanic cannot handle integers in header values.
            headers[ACL_METHODS] = options.get('methods')
        else:
            LOG.info(
                "The request's Access-Control-Request-Method header does not match allowed methods. "
                "CORS headers will not be applied.")

    # http://www.w3.org/TR/cors/#resource-implementation
    if options.get('vary_header'):
        # Only set header if the origin returned will vary dynamically,
        # i.e. if we are not returning an asterisk, and there are multiple
        # origins that can be matched.
        if headers[ACL_ORIGIN] == '*':
            pass
        elif (len(options.get('origins')) > 1 or len(origins_to_set) > 1
              or any(map(probably_regex, options.get('origins')))):
            headers['Vary'] = 'Origin'

    return CIMultiDict((k, v) for k, v in headers.items() if v)
Exemple #2
0
def set_cors_headers(req, resp, context, options):
    """
    Performs the actual evaluation of Sanic-CORS options and actually
    modifies the response object.

    This function is used both in the decorator and the after_request
    callback
    :param sanic.request.Request req:

    """
    try:
        request_context = context.request[id(req)]
    except AttributeError:
        LOG.debug(
            "Cannot find the request context. Is request already finished?")
        return resp
    # If CORS has already been evaluated via the decorator, skip
    evaluated = request_context.get(SANIC_CORS_EVALUATED, False)
    if evaluated:
        LOG.debug('CORS have been already evaluated, skipping')
        return resp

    # `resp` can be None or [] in the case of using Websockets
    # however this case should have been handled in the `extension` and `decorator` methods
    # before getting here. This is a final failsafe check to prevent crashing
    if not resp:
        return None

    if resp.headers is None:
        resp.headers = CIMultiDict()

    headers_to_set = get_cors_headers(options, req.headers, req.method)

    LOG.debug('Settings CORS headers: %s', str(headers_to_set))

    for k, v in headers_to_set.items():
        try:
            resp.headers.add(k, v)
        except Exception as e2:
            resp.headers[k] = v
    return resp
Exemple #3
0
    def source(self, request):
        '''
        Pulls values off the request in the provided location
        :param request: The flask request object to parse arguments from
        '''
        if isinstance(self.location, str):
            value = getattr(request, self.location, CIMultiDict())
            if callable(value):
                value = value()
            if value is not None:
                return value
        else:
            values = CIMultiDict()
            for l in self.location:
                value = getattr(request, l, None)
                if callable(value):
                    value = value()
                if value is not None:
                    values.update(
                        CIMultiDict([(k, a) for k, v in value.items()
                                     for a in v]))
            return values

        return CIMultiDict()
Exemple #4
0
 def test_existing_vary_headers(request):
     return HTTPResponse('',
                         status=200,
                         headers=CIMultiDict(
                             {'Vary': 'Accept-Encoding'}))
Exemple #5
0
 def test_multiple_set_cookie_headers(request):
     resp = HTTPResponse(body="Foo bar baz")
     resp.headers = CIMultiDict()
     resp.headers['set-cookie'] = 'foo'
     resp.headers.add('set-cookie', 'bar')
     return resp