def send_file(self, path, mimetype=None): """Send a local file to the browser. This method includes the "Last-Modified", "Content-Type" and "Content-Length" headers in the response, corresponding to the file attributes. It also checks the last modification time of the local file against the "If-Modified-Since" provided by the user agent, and sends a "304 Not Modified" response if it matches. """ if not os.path.isfile(path): raise HTTPNotFound(_("File %(path)s not found", path=path)) stat = os.stat(path) mtime = datetime.fromtimestamp(stat.st_mtime, localtz) last_modified = http_date(mtime) if last_modified == self.get_header("If-Modified-Since"): self.send_response(304) self.send_header("Content-Length", 0) self.end_headers() raise RequestDone if not mimetype: mimetype = mimetypes.guess_type(path)[0] or "application/octet-stream" self.send_response(200) self.send_header("Content-Type", mimetype) self.send_header("Content-Length", stat.st_size) self.send_header("Last-Modified", last_modified) self.end_headers() if self.method != "HEAD": fileobj = file(path, "rb") file_wrapper = self.environ.get("wsgi.file_wrapper", _FileWrapper) self._response = file_wrapper(fileobj, 4096) raise RequestDone
def check_modified(self, datetime, extra=""): """Check the request "If-None-Match" header against an entity tag. The entity tag is generated from the specified last modified time (`datetime`), optionally appending an `extra` string to indicate variants of the requested resource. That `extra` parameter can also be a list, in which case the MD5 sum of the list content will be used. If the generated tag matches the "If-None-Match" header of the request, this method sends a "304 Not Modified" response to the client. Otherwise, it adds the entity tag as an "ETag" header to the response so that consecutive requests can be cached. """ if isinstance(extra, list): m = md5() for elt in extra: m.update(repr(elt)) extra = m.hexdigest() etag = 'W/"%s/%s/%s"' % (self.authname, http_date(datetime), extra) inm = self.get_header("If-None-Match") if not inm or inm != etag: self.send_header("ETag", etag) else: self.send_response(304) self.send_header("Content-Length", 0) self.end_headers() raise RequestDone