~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to services/serveservice

  • Committer: William Grant
  • Date: 2012-06-28 01:52:02 UTC
  • Revision ID: me@williamgrant.id.au-20120628015202-f6ru7o367gt6nvgz
Hah

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
# IVLE - Informatics Virtual Learning Environment
 
4
# Copyright (C) 2007-2008 The University of Melbourne
 
5
#
 
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.
 
10
#
 
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.
 
15
#
 
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
 
19
 
 
20
# Author: Thomas Conway, Will Grant
 
21
 
 
22
import mimetypes
 
23
import os
 
24
import sys
 
25
import StringIO
 
26
from optparse import OptionParser
 
27
 
 
28
try:
 
29
    import json
 
30
except ImportError:
 
31
    import simplejson as json
 
32
 
 
33
from ivle import zip as zipmod
 
34
import ivle.conf.app.server
 
35
import ivle.mimetypes
 
36
 
 
37
def determine_file_type(filename):
 
38
    filetype = mimetypes.guess_type(filename)[0]
 
39
    if filetype is None:
 
40
        filetype = ivle.mimetypes.DEFAULT_MIMETYPE
 
41
    return filetype
 
42
 
 
43
def throw_error(message, extra={}):
 
44
    error = {'error': message}
 
45
    error.update(extra)
 
46
    print json.dumps(error)
 
47
    sys.exit(0)
 
48
 
 
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()
 
53
 
 
54
# Detect download mode. Download mode zips any multiple selection,
 
55
# and does not execute CGI scripts.
 
56
if options.download:
 
57
    download = True
 
58
    # paths is filled later.
 
59
else:
 
60
    download = False
 
61
    assert len(args) == 1
 
62
 
 
63
default_mimetype = "application/octet-stream"
 
64
zip_mimetype = "application/zip"
 
65
 
 
66
zipmode = False
 
67
zipbasepath = None
 
68
zipfilename = None
 
69
 
 
70
# If multiple paths have been specified, zip them up.
 
71
if len(args) > 1:
 
72
    # Mangle the paths - we want the basename of their dirname in front.
 
73
    paths = []
 
74
    dir = os.path.dirname(args[0])
 
75
    for path in args:
 
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)
 
80
    zipmode = True
 
81
    zipbasepath = dir
 
82
    zipfilename = os.path.basename(zipbasepath)
 
83
else:
 
84
    paths = args
 
85
    filename = paths[0]
 
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)
 
91
 
 
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')
 
96
 
 
97
    # If it's a directory, serve as a zip file
 
98
    if os.path.isdir(filename):
 
99
        if not download:
 
100
            # Not giving a directory listing - this is visible to everyone.
 
101
            throw_error('is-directory')
 
102
        zipmode = True
 
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
 
105
        # file.
 
106
        if filename[-1] == os.sep: filename = filename[:-1]
 
107
        splitpath = filename.rsplit(os.sep, 1)
 
108
        if len(splitpath) == 1:
 
109
            zipbasepath = ''
 
110
            paths = [filename]
 
111
        else:
 
112
            zipbasepath = splitpath[0]
 
113
            paths = [splitpath[1]]
 
114
        zipfilename = filename
 
115
    else:
 
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')})
 
119
 
 
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')
 
128
 
 
129
if zipmode:
 
130
    # zipfilename is some filename. Strip trailing slash or extension,
 
131
    # and add ".zip".
 
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)
 
143
 
 
144
    print json.dumps({'type': zip_mimetype,
 
145
                      'name': zipfilename.decode('utf-8'),
 
146
                      'size': len(zipfile.getvalue()),
 
147
                      })
 
148
 
 
149
    stream = zipfile
 
150
    stream.seek(0)
 
151
else:
 
152
 
 
153
    print json.dumps({'type': determine_file_type(filename),
 
154
                      'name': os.path.basename(filename).decode('utf-8'),
 
155
                      'size': os.path.getsize(filename),
 
156
                      })
 
157
    stream = open(filename)
 
158
 
 
159
next = stream.read(1024)
 
160
while next:
 
161
    sys.stdout.write(next)
 
162
    next = stream.read(1024)