19
19
# Author: Matt Giuca
22
22
# Serves content to the user (acting as a web server for students files).
23
23
# Unlike "serve", all content is served as a static file, and with the
24
24
# application/octet-stream mime type.
25
25
# Also can serve directories or multiple files, automatically zipping them up.
27
from common import (util, studpath)
27
from common import (util, studpath, zip)
34
# TODO: Make it work on multiple files, zipping them up.
35
# TODO: Make it work on directories, zipping them up.
37
35
# Serve all files as application/octet-stream so the browser presents them as
39
37
default_mimetype = "application/octet-stream"
38
zip_mimetype = "application/zip"
42
41
"""Handler for the Download application which serves files for
45
48
req.write_html_head_foot = False
47
# Get the username of the student whose work we are browsing, and the path
48
# on the local machine where the file is stored.
49
(user, path) = studpath.url_to_local(req.path)
52
# TODO: Nicer 404 message?
53
req.throw_error(req.HTTP_NOT_FOUND)
55
if not os.access(path, os.R_OK):
56
req.throw_error(req.HTTP_NOT_FOUND)
57
req.content_type = default_mimetype
50
# If any "path=" variables have been supplied, bring these into a list and
51
# make a zip file instead.
52
fields = req.get_fieldstorage()
53
paths = fields.getlist("path")
56
zipbasepath = req.path
57
zipfilename = os.path.basename(zipbasepath)
58
for i in range(0, len(paths)):
59
paths[i] = paths[i].value
61
# Otherwise, just serve directly (unless it's a directory)
62
(_, path) = studpath.url_to_local(req.path)
64
# TODO: Nicer 404 message?
65
req.throw_error(req.HTTP_NOT_FOUND)
66
elif not os.access(path, os.R_OK):
67
req.throw_error(req.HTTP_NOT_FOUND)
68
# If it's a directory, serve as a zip file
69
if os.path.isdir(path):
71
# Zip it from the perspective of its own parent.
72
# That way it will be a directory in the top level of the zip
75
if path[-1] == os.sep: path = path[:-1]
76
splitpath = path.rsplit(os.sep, 1)
77
if len(splitpath) == 1:
81
zipbasepath = splitpath[0]
82
paths = [splitpath[1]]
83
zipfilename = paths[0]
86
req.content_type = zip_mimetype
87
# zipfilename is some filename. Strip trailing slash or extension,
91
elif zipfilename[-1] == '/':
92
zipfilename = zipfilename[:-1]
93
elif '.' in zipfilename:
94
zipfilename = zipfilename[:zipfilename.rindex('.')]
96
req.headers_out["Content-Disposition"] = ("attachment; filename=" +
98
zipfile = StringIO.StringIO()
99
zip.make_zip(zipbasepath, paths, zipfile,req)
100
req.write(zipfile.getvalue())
102
req.content_type = default_mimetype