revert removal of cache control headers (#2118)

* revert removal of cache control headers

* always generate cache header for health route
This commit is contained in:
Bruce Martin
2021-03-26 08:49:44 -07:00
committed by GitHub
parent 78c9d24ed4
commit b494dd31f4
6 changed files with 60 additions and 1 deletions
+52
View File
@@ -21,6 +21,42 @@ from backend.common.utils.utils import Float32JSONEncoder
webbp = Blueprint("webapp", "backend.server.common.web", template_folder="templates")
ONE_WEEK = 7 * 24 * 60 * 60
def _cache_control(always, **cache_kwargs):
"""
Used to easily manage cache control headers on responses.
See Werkzeug for attributes that can be set, eg, no_cache, private, max_age, etc.
https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.ResponseCacheControl
"""
def inner_cache_control(f):
@wraps(f)
def wrapper(*args, **kwargs):
response = make_response(f(*args, **kwargs))
if not always and not current_app.app_config.server_config.app__generate_cache_control_headers:
return response
if response.status_code >= 400:
return response
for k, v in cache_kwargs.items():
setattr(response.cache_control, k, v)
return response
return wrapper
return inner_cache_control
def cache_control(**cache_kwargs):
""" config driven """
return _cache_control(False, **cache_kwargs)
def cache_control_always(**cache_kwargs):
""" always generate headers, regardless of the config """
return _cache_control(True, **cache_kwargs)
@webbp.route("/", methods=["GET"])
def dataset_index():
@@ -71,6 +107,7 @@ def rest_get_data_adaptor(func):
class HealthAPI(Resource):
@cache_control_always(no_store=True)
def get(self):
config = current_app.app_config
return health_check(config)
@@ -78,78 +115,92 @@ class HealthAPI(Resource):
class SchemaAPI(Resource):
# TODO @mdunitz separate dataset schema and user schema
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.schema_get(data_adaptor)
class ConfigAPI(Resource):
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.config_get(current_app.app_config, data_adaptor)
class UserInfoAPI(Resource):
@cache_control_always(no_store=True)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.userinfo_get(current_app.app_config, data_adaptor)
class AnnotationsObsAPI(Resource):
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.annotations_obs_get(request, data_adaptor)
@requires_authentication
@cache_control(no_store=True)
@rest_get_data_adaptor
def put(self, data_adaptor):
return common_rest.annotations_obs_put(request, data_adaptor)
class AnnotationsVarAPI(Resource):
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.annotations_var_get(request, data_adaptor)
class DataVarAPI(Resource):
@cache_control(no_store=True)
@rest_get_data_adaptor
def put(self, data_adaptor):
return common_rest.data_var_put(request, data_adaptor)
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.data_var_get(request, data_adaptor)
class ColorsAPI(Resource):
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.colors_get(data_adaptor)
class DiffExpObsAPI(Resource):
@cache_control(no_store=True)
@rest_get_data_adaptor
def post(self, data_adaptor):
return common_rest.diffexp_obs_post(request, data_adaptor)
class LayoutObsAPI(Resource):
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.layout_obs_get(request, data_adaptor)
@cache_control(no_store=True)
@rest_get_data_adaptor
def put(self, data_adaptor):
return common_rest.layout_obs_put(request, data_adaptor)
class GenesetsAPI(Resource):
@cache_control(public=True, max_age=ONE_WEEK)
@rest_get_data_adaptor
def get(self, data_adaptor):
return common_rest.genesets_get(request, data_adaptor)
@requires_authentication
@cache_control(no_store=True)
@rest_get_data_adaptor
def put(self, data_adaptor):
return common_rest.genesets_put(request, data_adaptor)
@@ -157,6 +208,7 @@ class GenesetsAPI(Resource):
class GenesetSummaryAPI(Resource):
@rest_get_data_adaptor
@cache_control(no_store=True)
def get(self, data_adaptor):
return common_rest.geneset_summary_get(request, data_adaptor)
@@ -27,6 +27,7 @@ class ServerConfig(BaseConfig):
self.app__open_browser = default_config["app"]["open_browser"]
self.app__force_https = default_config["app"]["force_https"]
self.app__flask_secret_key = default_config["app"]["flask_secret_key"]
self.app__generate_cache_control_headers = default_config["app"]["generate_cache_control_headers"]
self.authentication__type = default_config["authentication"]["type"]
self.authentication__insecure_test_environment = default_config["authentication"][
@@ -73,6 +74,7 @@ class ServerConfig(BaseConfig):
self.validate_correct_type_of_configuration_attribute("app__open_browser", bool)
self.validate_correct_type_of_configuration_attribute("app__force_https", bool)
self.validate_correct_type_of_configuration_attribute("app__flask_secret_key", str)
self.validate_correct_type_of_configuration_attribute("app__generate_cache_control_headers", bool)
if self.app__port:
try:
+1
View File
@@ -10,6 +10,7 @@ server:
open_browser: false
force_https: false
flask_secret_key: null
generate_cache_control_headers: false
authentication:
# The authentication types may be "none" or "session"
+1
View File
@@ -7,6 +7,7 @@ f"""server:
open_browser: {open_browser}
force_https: {force_https}
flask_secret_key: {flask_secret_key}
generate_cache_control_headers: {generate_cache_control_headers}
authentication:
type: {auth_type}
insecure_test_environment: {insecure_test_environment}
@@ -32,6 +32,7 @@ class ConfigTests(unittest.TestCase):
open_browser="false",
force_https="false",
flask_secret_key="secret",
generate_cache_control_headers="false",
auth_type="session",
insecure_test_environment="false",
index="false",
@@ -67,6 +68,7 @@ class ConfigTests(unittest.TestCase):
open_browser="false",
force_https="false",
flask_secret_key="secret",
generate_cache_control_headers="false",
auth_type="session",
index="false",
allowed_matrix_types=[],
@@ -116,6 +118,7 @@ class ConfigTests(unittest.TestCase):
open_browser=open_browser,
force_https=force_https,
flask_secret_key=flask_secret_key,
generate_cache_control_headers=generate_cache_control_headers,
auth_type=auth_type,
index=index,
allowed_matrix_types=allowed_matrix_types,
@@ -49,7 +49,7 @@ class TestServerConfig(ConfigTests):
def test_complete_config_checks_all_attr(self, mock_check_attrs):
mock_check_attrs.side_effect = BaseConfig.validate_correct_type_of_configuration_attribute()
self.server_config.complete_config(self.context)
self.assertEqual(mock_check_attrs.call_count, 20)
self.assertEqual(mock_check_attrs.call_count, 21)
def test_handle_app__throws_error_if_port_doesnt_exist(self):
config = self.get_config(port=99999999)