]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Merge master
authorDavid Wolever <david@wolever.net>
Tue, 21 May 2013 04:37:35 +0000 (00:37 -0400)
committerDavid Wolever <david@wolever.net>
Tue, 21 May 2013 04:37:35 +0000 (00:37 -0400)
1  2 
tornado/test/web_test.py
tornado/web.py

Simple merge
diff --cc tornado/web.py
index 0ffd9e164fadacc6a25018de20223904fe0a5ab9,8d90f027f600f50f40f0a45539666f3f83f6d38d..51c652c3e86af89ab9c9702b1fffdecc284c9ea1
@@@ -1729,36 -1777,81 +1778,82 @@@ class StaticFileHandler(RequestHandler)
          self.get(path, include_body=False)
  
      def get(self, path, include_body=True):
-         path = self.parse_url_path(path)
-         abspath = os.path.abspath(os.path.join(self.root, path))
-         # os.path.abspath strips a trailing /
-         # it needs to be temporarily added back for requests to root/
-         if not (abspath + os.path.sep).startswith(self.root):
-             raise HTTPError(403, "%s is not in root static directory", path)
-         if os.path.isdir(abspath) and self.default_filename is not None:
-             # need to look at the request.path here for when path is empty
-             # but there is some prefix to the path that was already
-             # trimmed by the routing
-             if not self.request.path.endswith("/"):
-                 self.redirect(self.request.path + "/")
+         # Set up our path instance variables.
+         self.path = self.parse_url_path(path)
+         del path  # make sure we don't refer to path instead of self.path again
+         absolute_path = self.get_absolute_path(self.settings, self.path)
+         self.absolute_path = self.validate_absolute_path(absolute_path)
+         if self.absolute_path is None:
+             return
+         self.modified = self.get_modified_time()
+         self.set_headers()
+         if self.should_return_304():
+             self.set_status(304)
+             return
+         request_range = None
+         range_header = self.request.headers.get("Range")
+         if range_header:
+             request_range = httputil._parse_request_range(range_header)
+             if not request_range:
+                 self.set_status(416)  # Range Not Satisfiable
+                 self.set_header("Content-Type", "text/plain")
+                 self.write("The provided Range header is not valid: %r\n"
+                            "Note: multiple ranges are not supported."
+                            % range_header)
                  return
-             abspath = os.path.join(abspath, self.default_filename)
-         if not os.path.exists(abspath):
-             raise HTTPError(404)
-         if not os.path.isfile(abspath):
-             raise HTTPError(403, "%s is not a file", path)
  
-         stat_result = os.stat(abspath)
-         modified = datetime.datetime.utcfromtimestamp(stat_result[stat.ST_MTIME])
+         if request_range:
+             start, end = request_range
+             size = self.get_content_size()
+             if start < 0:
+                 start += size
 -            self.set_status(206)  # Partial Content
++            if size != (end or size) - (start or 0):
++                self.set_status(206)  # Partial Content
+             self.set_header("Content-Range",
+                             httputil._get_content_range(start, end, size))
+         else:
+             start = end = None
+         content = self.get_content(self.absolute_path, start, end)
+         if isinstance(content, bytes_type):
+             content = [content]
+         content_length = 0
+         for chunk in content:
+             if include_body:
+                 self.write(chunk)
+             else:
+                 content_length += len(chunk)
+         if not include_body:
+             assert self.request.method == "HEAD"
+             self.set_header("Content-Length", content_length)
+     def compute_etag(self):
+         """Sets the ``Etag`` header based on static url version.
+         This allows efficient ``If-None-Match`` checks against cached
+         versions, and sends the correct ``Etag`` for a partial response
+         (i.e. the same ``Etag`` as the full file).
+         """
+         version_hash = self._get_cached_version(self.absolute_path)
+         if not version_hash:
+             return None
+         return '"%s"' %(version_hash, )
  
-         self.set_header("Last-Modified", modified)
+     def set_headers(self):
+         """Sets the content and caching headers on the response."""
+         self.set_header("Accept-Ranges", "bytes")
+         self.set_etag_header()
  
-         mime_type, encoding = mimetypes.guess_type(abspath)
-         if mime_type:
-             self.set_header("Content-Type", mime_type)
+         if self.modified is not None:
+             self.set_header("Last-Modified", self.modified)
  
-         cache_time = self.get_cache_time(path, modified, mime_type)
+         content_type = self.get_content_type()
+         if content_type:
+             self.set_header("Content-Type", content_type)
  
+         cache_time = self.get_cache_time(self.path, self.modified, content_type)
          if cache_time > 0:
              self.set_header("Expires", datetime.datetime.utcnow() +
                              datetime.timedelta(seconds=cache_time))