shalabh / quixote_extras
User contributed add-ons and for Quixote. See http://mems-exchange.org/software/quixote/. This repository used to be hosted at http://www.cafepy.com/quixote_extras/. All links from old location are now redirected here.
Clone this repository (size: 917.6 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/shalabh/quixote_extras
| commit 149: | 5b7911ccd017 |
| parent 148: | fbb05270db35 |
| branch: | default |
| tags: | tip |
Updated readme to reflect move to bitbucket.org
10 months ago
quixote_extras /
rex
/
StaticFile.py
| r149:5b7911ccd017 | 105 loc | 3.9 KB | embed / history / annotate / raw / |
|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | """StaticFile.py
Wrap a static file or directory so it can be served as a Quixote callable.
CHANGELOG:
2005-06-01: Copied from quixote.util module. Removed functions and imports
not needed by StaticFile or StaticDirectory. The only material difference in
our Static File is the "Last-Modified" header is not generated; this is what
causes the mod_scgi Refresh bug. THIS VERSION DISABLES BROWSER CACHING;
that's the tradeoff.
The official download location for this module is:
http://cafepy.com/quixote_extras/rex/StaticFile.py
Derived from quixote.util module at
http://www.mems-exchange.org/software/quixote/
and carries the same license.
"""
import sys
import os
import mimetypes
import urllib
from rfc822 import formatdate
import quixote
from quixote import errors
from quixote.directory import Directory
from quixote.html import htmltext, TemplateIO
from quixote.util import FileStream
from quixote.util import StaticDirectory as BaseStaticDirectory
class StaticFile:
"""
Wrapper for a static file on the filesystem.
"""
def __init__(self, path, follow_symlinks=False,
mime_type=None, encoding=None, cache_time=None):
"""StaticFile(path:string, follow_symlinks:bool)
Initialize instance with the absolute path to the file. If
'follow_symlinks' is true, symbolic links will be followed.
'mime_type' specifies the MIME type, and 'encoding' the
encoding; if omitted, the MIME type will be guessed,
defaulting to text/plain.
Optional cache_time parameter indicates the number of
seconds a response is considered to be valid, and will
be used to set the Expires header in the response when
quixote gets to that part. If the value is None then
the Expires header will not be set.
"""
# Check that the supplied path is absolute and (if a symbolic link) may
# be followed
self.path = path
if not os.path.isabs(path):
raise ValueError, "Path %r is not absolute" % path
# Decide the Content-Type of the file
guess_mime, guess_enc = mimetypes.guess_type(os.path.basename(path),
strict=False)
self.mime_type = mime_type or guess_mime or 'text/plain'
self.encoding = encoding or guess_enc or None
self.cache_time = cache_time
self.follow_symlinks = follow_symlinks
def __call__(self):
if not self.follow_symlinks and os.path.islink(self.path):
raise errors.TraversalError(private_msg="Path %r is a symlink"
% self.path)
request = quixote.get_request()
response = quixote.get_response()
if self.cache_time is None:
response.set_expires(None) # don't set the Expires header
else:
# explicitly allow client to cache page by setting the Expires
# header, this is even more efficient than the using
# Last-Modified/If-Modified-Since since the browser does not need
# to contact the server
response.set_expires(seconds=self.cache_time)
stat = os.stat(self.path)
last_modified = formatdate(stat.st_mtime)
# XXX Commented to test the following code.
#if last_modified == request.get_header('If-Modified-Since'):
# # handle exact match of If-Modified-Since header
# response.set_status(304)
# return ''
# Set the Content-Type for the response and return the file's contents.
response.set_content_type(self.mime_type)
if self.encoding:
response.set_header("Content-Encoding", self.encoding)
# @@MO: This line causes the SCGI Refresh bug.
#response.set_header('Last-Modified', last_modified)
return FileStream(open(self.path, 'rb'), stat.st_size)
class StaticDirectory(BaseStaticDirectory):
FILE_CLASS = StaticFile
|
