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)
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
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()
def test_existing_vary_headers(request): return HTTPResponse('', status=200, headers=CIMultiDict( {'Vary': 'Accept-Encoding'}))
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