diff --git a/superset/utils/decorators.py b/superset/utils/decorators.py index d85bf41812818..ae4c5726d8ee7 100644 --- a/superset/utils/decorators.py +++ b/superset/utils/decorators.py @@ -51,7 +51,6 @@ def etag_cache( check_perms: Callable[..., Any], get_last_modified: Optional[Callable[..., Any]] = None, skip: Optional[Callable[..., Any]] = None, - must_revalidate: Optional[bool] = False, ) -> Callable[..., Any]: """ A decorator for caching views and handling etag conditional requests. @@ -79,8 +78,6 @@ def wrapper(*args: Any, **kwargs: Any) -> ETagResponseMixin: 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 @@ -97,37 +94,32 @@ def wrapper(*args: Any, **kwargs: Any) -> ETagResponseMixin: raise logger.exception("Exception possibly due to cache backend.") - # if cache is stale? + # if cache is stale? + if get_last_modified: + content_changed_time = get_last_modified(*args, **kwargs) if ( response - and last_modified and response.last_modified - and response.last_modified < 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: - # 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() + # 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 ) - - # 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 diff --git a/superset/views/core.py b/superset/views/core.py index fd6a1133997db..5e5ff051d9528 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -171,13 +171,6 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods logger = logging.getLogger(__name__) - def __repr__(self) -> str: - """Determinate string representation of the view instance for etag_cache.""" - return "Superset.views.core.Superset@v{}{}".format( - self.appbuilder.app.config["VERSION_STRING"], - self.appbuilder.app.config["VERSION_SHA"], - ) - @has_access_api @expose("/datasources/") def datasources(self) -> FlaskResponse: @@ -1612,7 +1605,6 @@ def publish( # pylint: disable=no-self-use skip=lambda _self, dashboard_id_or_slug: not is_feature_enabled( "ENABLE_DASHBOARD_ETAG_HEADER" ), - must_revalidate=True, ) @expose("/dashboard//") def dashboard( # pylint: disable=too-many-locals