[devserver] Update staged.timestamp when accessing static content.

When accessing static content, the staged.timestamp file will now
be updated to reflect the fact the data was recently accessed.

This only impacts content accessed through Cherrypy not through
Apache.

BUG=chromium:390228
TEST=Verified stage.timestamp is updated when content is accessed
directly. Ran a suite on Moblab using this change.

Change-Id: Ic8c69c10d0f2d5fbce3b5c1372fb27ca18b025d8
Reviewed-on: https://chromium-review.googlesource.com/215132
Reviewed-by: Simran Basi <sbasi@chromium.org>
Tested-by: Simran Basi <sbasi@chromium.org>
Commit-Queue: Simran Basi <sbasi@chromium.org>
diff --git a/devserver.py b/devserver.py
index d0f1e1d..fe7a76f 100755
--- a/devserver.py
+++ b/devserver.py
@@ -61,6 +61,7 @@
 import build_artifact
 import cherrypy_ext
 import common_util
+import devserver_constants
 import downloader
 import gsutil_util
 import log_util
@@ -134,6 +135,27 @@
   return '\n'.join(html_doc)
 
 
+def _GetUpdateTimestampHandler(static_dir):
+  """Returns a handler to update directory staged.timestamp.
+
+  This handler resets the stage.timestamp whenever static content is accessed.
+
+  Args:
+    static_dir: Directory from which static content is being staged.
+
+  Returns:
+      A cherrypy handler to update the timestamp of accessed content.
+  """
+  def UpdateTimestampHandler():
+    if not '404' in cherrypy.response.status:
+      build_match = re.match(devserver_constants.STAGED_BUILD_REGEX,
+                             cherrypy.request.path_info)
+      if build_match:
+        build_dir = os.path.join(static_dir, build_match.group('build'))
+        downloader.Downloader.TouchTimestampForStaged(build_dir)
+  return UpdateTimestampHandler
+
+
 def _GetConfig(options):
   """Returns the configuration for the devserver."""
 
@@ -142,6 +164,12 @@
   if not socket.has_ipv6:
     socket_host = '0.0.0.0'
 
+  # Adds the UpdateTimestampHandler to cherrypy's tools. This tools executes
+  # on the on_end_resource hook. This hook is called once processing is
+  # complete and the response is ready to be returned.
+  cherrypy.tools.update_timestamp = cherrypy.Tool(
+      'on_end_resource', _GetUpdateTimestampHandler(options.static_dir))
+
   base_config = { 'global':
                   { 'server.log_request_headers': True,
                     'server.protocol_version': 'HTTP/1.1',
@@ -173,6 +201,7 @@
                   { 'tools.staticdir.dir': options.static_dir,
                     'tools.staticdir.on': True,
                     'response.timeout': 10000,
+                    'tools.update_timestamp.on': True,
                   },
                 }
   if options.production: