From 637adc3095e13d07b634978d9a2d194b2af0f4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 6 Oct 2015 18:19:53 +0200 Subject: [PATCH] Fix: LargeResponseHandler was wrongly caching ETag value ETag values returned with download responses were cached internally within the LargeResponseHandler class, with the file's path as key. That let to problems once the content changed and hence the ETag value actually becoming invalid. Since the path however stayed the same, the same ETag value for the modified file was assumed and a 304 Not Modified response was generated. This patch changes the behaviour of LargeResponseHandler to use the last modified date of the file as the ETag value and alternatively allowing an etag generator function to be provided as constructor parameter as well to use for calculating (or disabling) the ETag header dependant on the situation. --- src/octoprint/server/util/tornado.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/octoprint/server/util/tornado.py b/src/octoprint/server/util/tornado.py index ce1bdd00..14ace0da 100644 --- a/src/octoprint/server/util/tornado.py +++ b/src/octoprint/server/util/tornado.py @@ -776,13 +776,19 @@ class LargeResponseHandler(tornado.web.StaticFileHandler): with the requested path as parameter. Should raise a ``tornado.web.HTTPError`` (e.g. an 404) if the requested path does not pass validation in which case the request will not be further processed. Defaults to ``None`` and hence no path validation being performed. + etag_generator (function): Callback to call for generating the value of the ETag response header. Will be + called with the response handler as parameter. May return ``None`` to prevent the ETag response header + from being set. If not provided the last modified time of the file in question will be used as returned + by ``get_content_version``. """ - def initialize(self, path, default_filename=None, as_attachment=False, access_validation=None, path_validation=None): + def initialize(self, path, default_filename=None, as_attachment=False, + 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._access_validation = access_validation self._path_validation = path_validation + self._etag_generator = etag_generator def get(self, path, include_body=True): if self._access_validation is not None: @@ -796,6 +802,12 @@ class LargeResponseHandler(tornado.web.StaticFileHandler): if self._as_attachment: self.set_header("Content-Disposition", "attachment") + def compute_etag(self): + if self._etag_generator is not None: + return self._etag_generator(self) + else: + return self.get_content_version(self.absolute_path) + @classmethod def get_content_version(cls, abspath): import os