Also set caching headers for downloads to discourage client-side caching
At least if necessary (added new boolean flag to the constructor of LargeResponseHandler for that). While at it also rename UrlForwardHandler to UrlProxyHandler (it does not forward, it proxies) and make it aware of ETag and Expires headers.
This commit is contained in:
parent
637adc3095
commit
9cf21aa036
2 changed files with 31 additions and 8 deletions
|
|
@ -330,13 +330,29 @@ class Server():
|
|||
|
||||
upload_suffixes = dict(name=s.get(["server", "uploads", "nameSuffix"]), path=s.get(["server", "uploads", "pathSuffix"]))
|
||||
|
||||
download_handler_kwargs = dict(
|
||||
as_attachment=True,
|
||||
allow_client_caching=False
|
||||
)
|
||||
admin_validator = dict(access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))
|
||||
no_hidden_files_validator = dict(path_validation=util.tornado.path_validation_factory(lambda path: not os.path.basename(path).startswith("."), status_code=404))
|
||||
|
||||
def joined_dict(*dicts):
|
||||
if not len(dicts):
|
||||
return dict()
|
||||
|
||||
joined = dict()
|
||||
for d in dicts:
|
||||
joined.update(d)
|
||||
return joined
|
||||
|
||||
server_routes = self._router.urls + [
|
||||
# various downloads
|
||||
(r"/downloads/timelapse/([^/]*\.mpg)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("timelapse"), as_attachment=True)),
|
||||
(r"/downloads/files/local/(.*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("uploads"), as_attachment=True, path_validation=util.tornado.path_validation_factory(lambda path: not os.path.basename(path).startswith("."), status_code=404))),
|
||||
(r"/downloads/logs/([^/]*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("logs"), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.admin_validator))),
|
||||
(r"/downloads/timelapse/([^/]*\.mpg)", util.tornado.LargeResponseHandler, joined_dict(dict(path=s.getBaseFolder("timelapse")), download_handler_kwargs, no_hidden_files_validator)),
|
||||
(r"/downloads/files/local/(.*)", util.tornado.LargeResponseHandler, joined_dict(dict(path=s.getBaseFolder("uploads")), download_handler_kwargs, no_hidden_files_validator)),
|
||||
(r"/downloads/logs/([^/]*)", util.tornado.LargeResponseHandler, joined_dict(dict(path=s.getBaseFolder("logs")), download_handler_kwargs, admin_validator)),
|
||||
# camera snapshot
|
||||
(r"/downloads/camera/current", util.tornado.UrlForwardHandler, dict(url=s.get(["webcam", "snapshot"]), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))),
|
||||
(r"/downloads/camera/current", util.tornado.UrlProxyHandler, dict(url=s.get(["webcam", "snapshot"]), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))),
|
||||
# generated webassets
|
||||
(r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=os.path.join(s.getBaseFolder("generated"), "webassets")))
|
||||
]
|
||||
|
|
|
|||
|
|
@ -768,6 +768,8 @@ class LargeResponseHandler(tornado.web.StaticFileHandler):
|
|||
:class:``~tornado.web.StaticFileHandler`` as the ``default_filename`` keyword parameter). Defaults to ``None``.
|
||||
as_attachment (bool): Whether to serve requested files with ``Content-Disposition: attachment`` header (``True``)
|
||||
or not. Defaults to ``False``.
|
||||
allow_client_caching (bool): Whether to allow the client to cache (by not setting any ``Cache-Control`` or
|
||||
``Expires`` headers on the response) or not.
|
||||
access_validation (function): Callback to call in the ``get`` method to validate access to the resource. Will
|
||||
be called with ``self.request`` as parameter which contains the full tornado request object. Should raise
|
||||
a ``tornado.web.HTTPError`` if access is not allowed in which case the request will not be further processed.
|
||||
|
|
@ -782,10 +784,11 @@ class LargeResponseHandler(tornado.web.StaticFileHandler):
|
|||
by ``get_content_version``.
|
||||
"""
|
||||
|
||||
def initialize(self, path, default_filename=None, as_attachment=False,
|
||||
def initialize(self, path, default_filename=None, as_attachment=False, allow_client_caching=True,
|
||||
access_validation=None, path_validation=None, etag_generator=None):
|
||||
tornado.web.StaticFileHandler.initialize(self, os.path.abspath(path), default_filename)
|
||||
self._as_attachment = as_attachment
|
||||
self._allow_client_caching = allow_client_caching
|
||||
self._access_validation = access_validation
|
||||
self._path_validation = path_validation
|
||||
self._etag_generator = etag_generator
|
||||
|
|
@ -802,6 +805,10 @@ class LargeResponseHandler(tornado.web.StaticFileHandler):
|
|||
if self._as_attachment:
|
||||
self.set_header("Content-Disposition", "attachment")
|
||||
|
||||
if not self._allow_client_caching:
|
||||
self.set_header("Cache-Control", "max-age=0, must-revalidate, private")
|
||||
self.set_header("Expires", "-1")
|
||||
|
||||
def compute_etag(self):
|
||||
if self._etag_generator is not None:
|
||||
return self._etag_generator(self)
|
||||
|
|
@ -817,7 +824,7 @@ class LargeResponseHandler(tornado.web.StaticFileHandler):
|
|||
##~~ URL Forward Handler for forwarding requests to a preconfigured static URL
|
||||
|
||||
|
||||
class UrlForwardHandler(tornado.web.RequestHandler):
|
||||
class UrlProxyHandler(tornado.web.RequestHandler):
|
||||
"""
|
||||
`tornado.web.RequestHandler <http://tornado.readthedocs.org/en/branch4.0/web.html#request-handlers>`_ that proxies
|
||||
requests to a preconfigured url and returns the response. Allows delivery of the requested content as attachment
|
||||
|
|
@ -827,7 +834,7 @@ class UrlForwardHandler(tornado.web.RequestHandler):
|
|||
for making the request to the configured endpoint and return the body of the client response with the status code
|
||||
from the client response and the following headers:
|
||||
|
||||
* ``Date``, ``Cache-Control``, ``Server``, ``Content-Type`` and ``Location`` will be copied over.
|
||||
* ``Date``, ``Cache-Control``, ``Expires``, ``ETag``, ``Server``, ``Content-Type`` and ``Location`` will be copied over.
|
||||
* If ``as_attachment`` is set to True, ``Content-Disposition`` will be set to ``attachment``. If ``basename`` is
|
||||
set including the attachement's ``filename`` attribute will be set to the base name followed by the extension
|
||||
guessed based on the MIME type from the ``Content-Type`` header of the response. If no extension can be guessed
|
||||
|
|
@ -877,7 +884,7 @@ class UrlForwardHandler(tornado.web.RequestHandler):
|
|||
filename = None
|
||||
|
||||
self.set_status(response.code)
|
||||
for name in ("Date", "Cache-Control", "Server", "Content-Type", "Location"):
|
||||
for name in ("Date", "Cache-Control", "Server", "Content-Type", "Location", "Expires", "ETag"):
|
||||
value = response.headers.get(name)
|
||||
if value:
|
||||
self.set_header(name, value)
|
||||
|
|
|
|||
Loading…
Reference in a new issue