3
# IVLE - Informatics Virtual Learning Environment
4
# Copyright (C) 2007-2008 The University of Melbourne
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
# Author: Thomas Conway, Will Grant
26
from optparse import OptionParser
31
import simplejson as json
33
from ivle import zip as zipmod
34
import ivle.conf.app.server
37
def determine_file_type(filename):
38
filetype = mimetypes.guess_type(filename)[0]
40
filetype = ivle.mimetypes.DEFAULT_MIMETYPE
43
def throw_error(message, extra={}):
44
error = {'error': message}
46
print json.dumps(error)
49
parser = OptionParser()
50
parser.add_option('-d', '--download', dest='download', action='store_true',
51
help='force download, not execution, of the paths')
52
(options, args) = parser.parse_args()
54
# Detect download mode. Download mode zips any multiple selection,
55
# and does not execute CGI scripts.
58
# paths is filled later.
63
default_mimetype = "application/octet-stream"
64
zip_mimetype = "application/zip"
70
# If multiple paths have been specified, zip them up.
72
# Mangle the paths - we want the basename of their dirname in front.
74
dir = os.path.dirname(args[0])
76
assert os.path.dirname(path) == dir
77
paths.append(os.path.join(os.path.basename(dir),
78
os.path.basename(path)))
79
dir = os.path.dirname(dir)
82
zipfilename = os.path.basename(zipbasepath)
86
if not os.access(filename, os.F_OK):
87
# The given path doesn't exist. CGI lets us backtrack and put the path
88
# elements through which we pass into PATH_INFO, so we try that.
89
while not os.access(filename, os.F_OK):
90
filename, path_info_frag = os.path.split(filename)
92
# We now have a file that exists, but is it something that we're allowed
93
# to execute? If not, we should 404 anyway.
94
if determine_file_type(filename) not in ivle.conf.app.server.interpreters:
95
throw_error('not-found')
97
# If it's a directory, serve as a zip file
98
if os.path.isdir(filename):
100
# Not giving a directory listing - this is visible to everyone.
101
throw_error('is-directory')
103
# Zip it from the perspective of its own parent.
104
# That way it will be a directory in the top level of the zip
106
if filename[-1] == os.sep: filename = filename[:-1]
107
splitpath = filename.rsplit(os.sep, 1)
108
if len(splitpath) == 1:
112
zipbasepath = splitpath[0]
113
paths = [splitpath[1]]
114
zipfilename = filename
116
if not download and \
117
determine_file_type(filename) in ivle.conf.app.server.interpreters:
118
throw_error('is-executable', {'path': filename.decode('utf-8')})
120
if not download and (
121
(ivle.conf.app.server.blacklist_served_filetypes and \
122
determine_file_type(filename) in \
123
ivle.conf.app.server.served_filetypes_blacklist) or \
124
(ivle.conf.app.server.served_filetypes_whitelist and \
125
determine_file_type(filename) not in \
126
ivle.conf.app.server.served_filetypes_whitelist)):
127
throw_error('forbidden')
130
# zipfilename is some filename. Strip trailing slash or extension,
132
if zipfilename == '':
133
zipfilename = "files"
134
elif zipfilename[-1] == '/':
135
zipfilename = zipfilename[:-1]
136
elif '.' in zipfilename:
137
zipfilename = zipfilename[:zipfilename.rindex('.')]
138
zipfilename += ".zip"
139
#req.headers_out["Content-Disposition"] = ("attachment; filename=" +
140
# zipfilename) # TODO
141
zipfile = StringIO.StringIO()
142
zipmod.make_zip(zipbasepath, paths, zipfile)
144
print json.dumps({'type': zip_mimetype,
145
'name': zipfilename.decode('utf-8'),
146
'size': len(zipfile.getvalue()),
153
print json.dumps({'type': determine_file_type(filename),
154
'name': os.path.basename(filename).decode('utf-8'),
155
'size': os.path.getsize(filename),
157
stream = open(filename)
159
next = stream.read(1024)
161
sys.stdout.write(next)
162
next = stream.read(1024)