def decorator(f): @wraps(f) def wrapper(*args, **kwargs): # check if the user can access the resource check_perms(*args, **kwargs) # for POST requests we can't set cache headers, use the response # cache nor use conditional requests; this will still use the # dataframe cache in `superset/viz.py`, though. if request.method == "POST": return f(*args, **kwargs) response = None if cache: try: # build the cache key from the function arguments and any # other additional GET arguments (like `form_data`, eg). key_args = list(args) key_kwargs = kwargs.copy() key_kwargs.update(request.args) cache_key = wrapper.make_cache_key(f, *key_args, **key_kwargs) response = cache.get(cache_key) except Exception: # pylint: disable=broad-except if app.debug: raise logging.exception("Exception possibly due to cache backend.") # if no response was cached, compute it using the wrapped function if response is None: response = f(*args, **kwargs) # add headers for caching: Last Modified, Expires and ETag response.cache_control.public = True response.last_modified = datetime.utcnow() expiration = max_age if max_age != 0 else FAR_FUTURE response.expires = response.last_modified + timedelta( seconds=expiration ) response.add_etag() # if we have a cache, store the response from the request if cache: try: cache.set(cache_key, response, timeout=max_age) except Exception: # pylint: disable=broad-except if app.debug: raise logging.exception("Exception possibly due to cache backend.") return response.make_conditional(request) if cache: wrapper.uncached = f wrapper.cache_timeout = max_age wrapper.make_cache_key = cache._memoize_make_cache_key( # pylint: disable=protected-access make_name=None, timeout=max_age ) return wrapper
def decorator(f): @wraps(f) def wrapper(*args, **kwargs): # check if the user can access the resource check_perms(*args, **kwargs) # for POST requests we can't set cache headers, use the response # cache nor use conditional requests; this will still use the # dataframe cache in `superset/viz.py`, though. if request.method == 'POST': return f(*args, **kwargs) response = None if cache: try: # build the cache key from the function arguments and any # other additional GET arguments (like `form_data`, eg). key_args = list(args) key_kwargs = kwargs.copy() key_kwargs.update(request.args) cache_key = wrapper.make_cache_key(f, *key_args, **key_kwargs) response = cache.get(cache_key) except Exception: # pylint: disable=broad-except if app.debug: raise logging.exception('Exception possibly due to cache backend.') # if no response was cached, compute it using the wrapped function if response is None: response = f(*args, **kwargs) # add headers for caching: Last Modified, Expires and ETag response.cache_control.public = True response.last_modified = datetime.utcnow() expiration = max_age if max_age != 0 else FAR_FUTURE response.expires = \ response.last_modified + timedelta(seconds=expiration) response.add_etag() # if we have a cache, store the response from the request if cache: try: cache.set(cache_key, response, timeout=max_age) except Exception: # pylint: disable=broad-except if app.debug: raise logging.exception('Exception possibly due to cache backend.') return response.make_conditional(request) if cache: wrapper.uncached = f wrapper.cache_timeout = max_age wrapper.make_cache_key = \ cache._memoize_make_cache_key( # pylint: disable=protected-access make_name=None, timeout=max_age) return wrapper
def decorator(f: Callable[..., Any]) -> Callable[..., Any]: @wraps(f) def wrapper(*args: Any, **kwargs: Any) -> ETagResponseMixin: # check if the user can access the resource check_perms(*args, **kwargs) # for POST requests we can't set cache headers, use the response # cache nor use conditional requests; this will still use the # dataframe cache in `superset/viz.py`, though. if request.method == "POST" or (skip and skip(*args, **kwargs)): return f(*args, **kwargs) response = None last_modified = get_last_modified and get_last_modified(*args, **kwargs) if cache: try: # build the cache key from the function arguments and any # other additional GET arguments (like `form_data`, eg). key_args = list(args) key_kwargs = kwargs.copy() key_kwargs.update(request.args) cache_key = wrapper.make_cache_key( # type: ignore f, *key_args, **key_kwargs ) response = cache.get(cache_key) except Exception: # pylint: disable=broad-except if app.debug: raise logger.exception("Exception possibly due to cache backend.") # if cache is stale? if ( response and last_modified and response.last_modified and response.last_modified < last_modified ): response = None if response is None: # if no response was cached, compute it using the wrapped function response = f(*args, **kwargs) # set expiration headers: # Last-Modified, Expires, Cache-Control, ETag response.last_modified = last_modified or datetime.utcnow() expiration = max_age if max_age != 0 else FAR_FUTURE response.expires = response.last_modified + timedelta( seconds=expiration ) # when needed, instruct the browser to always revalidate cache if must_revalidate: # `Cache-Control: no-cache` asks the browser to always store # the cache, but also must validate it with the server. response.cache_control.no_cache = True else: # `Cache-Control: Public` asks the browser to always store # the cache. response.cache_control.public = True response.add_etag() # if we have a cache, store the response from the request if cache: try: cache.set(cache_key, response, timeout=max_age) except Exception: # pylint: disable=broad-except if app.debug: raise logger.exception("Exception possibly due to cache backend.") return response.make_conditional(request) if cache: wrapper.uncached = f # type: ignore wrapper.cache_timeout = max_age # type: ignore wrapper.make_cache_key = cache._memoize_make_cache_key( # type: ignore # pylint: disable=protected-access make_name=None, timeout=max_age ) return wrapper
def decorator(f: Callable[..., Any]) -> Callable[..., Any]: @wraps(f) def wrapper(*args: Any, **kwargs: Any) -> ETagResponseMixin: # check if the user can access the resource check_perms(*args, **kwargs) # for POST requests we can't set cache headers, use the response # cache nor use conditional requests; this will still use the # dataframe cache in `superset/viz.py`, though. if request.method == "POST" or (skip and skip(*args, **kwargs)): return f(*args, **kwargs) response = None if cache: try: # build the cache key from the function arguments and any # other additional GET arguments (like `form_data`, eg). key_args = list(args) key_kwargs = kwargs.copy() key_kwargs.update(request.args) cache_key = wrapper.make_cache_key( # type: ignore f, *key_args, **key_kwargs ) response = cache.get(cache_key) except Exception: # pylint: disable=broad-except if app.debug: raise logger.exception("Exception possibly due to cache backend.") # if cache is stale? if get_last_modified: content_changed_time = get_last_modified(*args, **kwargs) if ( response and response.last_modified and response.last_modified.timestamp() < content_changed_time.timestamp() ): response = None else: # if caller didn't provide content's last_modified time, assume # its cache won't be stale. content_changed_time = datetime.utcnow() # if no response was cached, compute it using the wrapped function if response is None: response = f(*args, **kwargs) # add headers for caching: Last Modified, Expires and ETag response.cache_control.public = True response.last_modified = content_changed_time expiration = max_age if max_age != 0 else FAR_FUTURE response.expires = response.last_modified + timedelta( seconds=expiration ) response.add_etag() # if we have a cache, store the response from the request if cache: try: cache.set(cache_key, response, timeout=max_age) except Exception: # pylint: disable=broad-except if app.debug: raise logger.exception("Exception possibly due to cache backend.") return response.make_conditional(request) if cache: wrapper.uncached = f # type: ignore wrapper.cache_timeout = max_age # type: ignore wrapper.make_cache_key = cache._memoize_make_cache_key( # type: ignore # pylint: disable=protected-access make_name=None, timeout=max_age ) return wrapper