17
17
# along with this program; if not, write to the Free Software
18
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
# Author: Thomas Conway, Will Grant
20
# Script: serveservice
21
# Author: Thomas Conway
24
# A CGI script for serving files.
26
from optparse import OptionParser
30
from ivle import zip as zipmod
31
import ivle.conf.app.server
33
def determine_file_type(filename):
34
filetype = mimetypes.guess_type(filename)[0]
36
filetype = ivle.conf.mimetypes.default_mimetype
39
def throw_error(message, extra={}):
40
error = {'error': message}
42
print cjson.encode(error)
45
parser = OptionParser()
46
parser.add_option('-d', '--download', dest='download', action='store_true',
47
help='force download, not execution, of the paths')
48
(options, args) = parser.parse_args()
50
# Detect download mode. Download mode zips any multiple selection,
51
# and does not execute CGI scripts.
54
# paths is filled later.
32
from common import (cgirequest, studpath)
33
from common import zip as zipmod
35
req = cgirequest.CGIRequest()
36
req.install_error_handler()
38
# Work out the parts of the URL
39
url = urlparse.urlparse(req.path)
42
filename = studpath.url_to_jailpaths(urlpath)[2]
59
44
default_mimetype = "application/octet-stream"
60
45
zip_mimetype = "application/zip"
66
# If multiple paths have been specified, zip them up.
68
# Mangle the paths - we want the basename of their dirname in front.
70
dir = os.path.dirname(args[0])
72
assert os.path.dirname(path) == dir
73
paths.append(os.path.join(os.path.basename(dir),
74
os.path.basename(path)))
75
dir = os.path.dirname(dir)
52
# If any "path=" variables have been supplied, bring these into a list and
53
# make a zip file instead.
54
fields = req.get_fieldstorage()
55
paths = fields.getlist("path")
58
zipbasepath = filename
78
59
zipfilename = os.path.basename(zipbasepath)
60
#for i in range(0, len(paths)):
61
#paths[i] = paths[i].value
82
if not os.access(filename, os.F_OK):
83
# The given path doesn't exist. CGI lets us backtrack and put the path
84
# elements through which we pass into PATH_INFO, so we try that.
85
while not os.access(filename, os.F_OK):
86
filename, path_info_frag = os.path.split(filename)
88
# We now have a file that exists, but is it something that we're allowed
89
# to execute? If not, we should 404 anyway.
90
if determine_file_type(filename) not in ivle.conf.app.server.interpreters:
91
throw_error('not-found')
93
# If it's a directory, serve as a zip file
64
req.throw_error(req.HTTP_NOT_FOUND,
65
"The path specified is invalid.")
66
elif not os.access(filename, os.R_OK):
67
req.throw_error(req.HTTP_NOT_FOUND,
68
"The specified file (%s) does not exist." % urlpath)
69
# If it's a directory, serve as a zip file
94
70
if os.path.isdir(filename):
96
# Not giving a directory listing - this is visible to everyone.
97
throw_error('is-directory')
99
72
# Zip it from the perspective of its own parent.
100
73
# That way it will be a directory in the top level of the zip
108
81
zipbasepath = splitpath[0]
109
82
paths = [splitpath[1]]
110
zipfilename = filename
112
if not download and \
113
determine_file_type(filename) in ivle.conf.app.server.interpreters:
114
throw_error('is-executable', {'path': filename})
116
if (ivle.conf.app.server.blacklist_served_filetypes and \
117
determine_file_type(filename) in \
118
ivle.conf.app.server.served_filetypes_blacklist) or \
119
(ivle.conf.app.server.served_filetypes_whitelist and \
120
determine_file_type(filename) not in \
121
ivle.conf.app.server.served_filetypes_whitelist):
122
throw_error('forbidden')
83
zipfilename = paths[0]
86
req.content_type = zip_mimetype
125
87
# zipfilename is some filename. Strip trailing slash or extension,
127
89
if zipfilename == '':
131
93
elif '.' in zipfilename:
132
94
zipfilename = zipfilename[:zipfilename.rindex('.')]
133
95
zipfilename += ".zip"
134
#req.headers_out["Content-Disposition"] = ("attachment; filename=" +
135
# zipfilename) # TODO
96
req.headers_out["Content-Disposition"] = ("attachment; filename=" +
136
98
zipfile = StringIO.StringIO()
137
99
zipmod.make_zip(zipbasepath, paths, zipfile)
139
print cjson.encode({'type': zip_mimetype,
140
'name': zipfilename})
141
print zipfile.getvalue()
101
req.write(zipfile.getvalue())
143
print cjson.encode({'type': determine_file_type(filename),
144
'name': os.path.basename(filename)})
145
print open(filename).read()
103
#req.content_type = default_mimetype
104
req.sendfile(filename)