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

« back to all changes in this revision

Viewing changes to lib/common/interpret.py

  • Committer: drtomc
  • Date: 2008-02-25 02:23:18 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:561
app: improve the error message when an app fails to load.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
# This can be resolved but needs careful sanitisation. See fixup_environ.
29
29
 
30
30
from common import studpath
31
 
from common import db
32
 
from common.util import IVLEError, IVLEJailError
33
31
import conf
34
32
import functools
35
33
 
44
42
 
45
43
CGI_BLOCK_SIZE = 65535
46
44
 
47
 
uids = {}
48
 
 
49
 
def get_uid(login):
50
 
    """Get the unix uid corresponding to the given login name.
51
 
       If it is not in the dictionary of uids, then consult the
52
 
       database and retrieve an update of the user table."""
53
 
    global uids
54
 
    if login in uids:
55
 
        return uids[login]
56
 
 
57
 
    conn = db.DB()
58
 
    res = conn.get_all('login', ['login', 'unixid'])
59
 
    def repack(flds):
60
 
        return (flds['login'], flds['unixid'])
61
 
    uids = dict(map(repack,res))
62
 
 
63
 
    return uids[login]
64
 
 
65
 
def interpret_file(req, owner, jail_dir, filename, interpreter, gentle=True):
 
45
def interpret_file(req, owner, jail_dir, filename, interpreter):
66
46
    """Serves a file by interpreting it using one of IVLE's builtin
67
47
    interpreters. All interpreters are intended to run in the user's jail. The
68
48
    jail location is provided as an argument to the interpreter but it is up
74
54
    filename: Absolute filename within the user's jail.
75
55
    interpreter: A function object to call.
76
56
    """
77
 
    # We can't test here whether or not the target file actually exists,
78
 
    # because the apache user may not have permission. Instead we have to
79
 
    # rely on the interpreter generating an error.
 
57
    # Make sure the file exists (otherwise some interpreters may not actually
 
58
    # complain).
 
59
    # Don't test for execute permission, that will only be required for
 
60
    # certain interpreters.
80
61
    if filename.startswith(os.sep):
81
62
        filename_abs = filename
82
63
        filename_rel = filename[1:]
84
65
        filename_abs = os.path.join(os.sep, filename)
85
66
        filename_rel = filename
86
67
 
 
68
    if not os.access(os.path.join(jail_dir, filename_rel), os.R_OK):
 
69
        req.throw_error(req.HTTP_NOT_FOUND)
 
70
 
87
71
    # Get the UID of the owner of the file
88
72
    # (Note: files are executed by their owners, not the logged in user.
89
73
    # This ensures users are responsible for their own programs and also
90
74
    # allows them to be executed by the public).
91
 
    uid = get_uid(owner)
 
75
    uid = req.user.unixid
92
76
 
93
77
    # Split up req.path again, this time with respect to the jail
94
78
    (working_dir, _) = os.path.split(filename_abs)
99
83
    # (Note that paths "relative" to the jail actually begin with a '/' as
100
84
    # they are absolute in the jailspace)
101
85
 
102
 
    return interpreter(uid, jail_dir, working_dir, filename_abs, req,
103
 
                       gentle)
 
86
    return interpreter(uid, jail_dir, working_dir, filename_abs, req)
104
87
 
105
88
class CGIFlags:
106
 
    """Stores flags regarding the state of reading CGI output.
107
 
       If this is to be gentle, detection of invalid headers will result in an
108
 
       HTML warning."""
109
 
    def __init__(self, begentle=True):
110
 
        self.gentle = begentle
 
89
    """Stores flags regarding the state of reading CGI output."""
 
90
    def __init__(self):
111
91
        self.started_cgi_body = False
112
92
        self.got_cgi_headers = False
113
93
        self.wrote_html_warning = False
115
95
        self.headers = {}       # Header names : values
116
96
 
117
97
def execute_cgi(interpreter, trampoline, uid, jail_dir, working_dir,
118
 
                script_path, req, gentle):
 
98
                script_path, req):
119
99
    """
120
100
    trampoline: Full path on the local system to the CGI wrapper program
121
101
        being executed.
170
150
    # process_cgi_line: Reads a single line of CGI output and processes it.
171
151
    # Prints to req, and also does fancy HTML warnings if Content-Type
172
152
    # omitted.
173
 
    cgiflags = CGIFlags(gentle)
 
153
    cgiflags = CGIFlags()
174
154
 
175
155
    # Read from the process's stdout into req
176
156
    data = pid.stdout.read(CGI_BLOCK_SIZE)
202
182
        # Break data into lines of CGI header data. 
203
183
        linebuf = cgiflags.linebuf + data
204
184
        # First see if we can split all header data
205
 
        # We need to get the double CRLF- or LF-terminated headers, whichever
206
 
        # is smaller, as either sequence may appear somewhere in the body.
207
 
        usplit = linebuf.split('\n\n', 1)
208
 
        wsplit = linebuf.split('\r\n\r\n', 1)
209
 
        split = len(usplit[0]) > len(wsplit[0]) and wsplit or usplit
 
185
        split = linebuf.split('\r\n\r\n', 1)
 
186
        if len(split) == 1:
 
187
            # Allow UNIX newlines instead
 
188
            split = linebuf.split('\n\n', 1)
210
189
        if len(split) == 1:
211
190
            # Haven't seen all headers yet. Buffer and come back later.
212
191
            cgiflags.linebuf = linebuf
232
211
            if len(split) == 1:
233
212
                split = headers.split('\n', 1)
234
213
 
235
 
        # Is this an internal IVLE error condition?
236
 
        hs = cgiflags.headers
237
 
        if 'X-IVLE-Error-Type' in hs:
238
 
            t = hs['X-IVLE-Error-Type']
239
 
            if t == IVLEError.__name__:
240
 
                raise IVLEError(int(hs['X-IVLE-Error-Code']),
241
 
                                hs['X-IVLE-Error-Message'])
242
 
            else:
243
 
                try:
244
 
                    raise IVLEJailError(hs['X-IVLE-Error-Type'],
245
 
                                        hs['X-IVLE-Error-Message'],
246
 
                                        hs['X-IVLE-Error-Info'])
247
 
                except KeyError:
248
 
                    raise IVLEError(500, 'bad error headers written by CGI')
249
 
 
250
214
        # Check to make sure the required headers were written
251
 
        if cgiflags.wrote_html_warning or not cgiflags.gentle:
 
215
        if cgiflags.wrote_html_warning:
252
216
            # We already reported an error, that's enough
253
217
            pass
254
218
        elif "Content-Type" in cgiflags.headers:
281
245
    try:
282
246
        name, value = line.split(':', 1)
283
247
    except ValueError:
284
 
        # If we are being gentle, we want to help the user understand what
285
 
        # went wrong. Otherwise, we bail out.
286
 
        if not cgiflags.gentle:
287
 
            raise
288
248
        # No colon. The user did not write valid headers.
289
249
        if len(cgiflags.headers) == 0:
290
250
            # First line was not a header line. We can assume this is not
316
276
        try:
317
277
            req.status = int(value.split(' ', 1)[0])
318
278
        except ValueError:
319
 
            if not cgiflags.gentle:
320
 
                # This isn't user code, so it should be good.
321
 
                # Get us out of here!
322
 
                raise
323
279
            message = """The "Status" CGI header was invalid. You need to
324
280
print a number followed by a message, such as "302 Found"."""
325
281
            write_html_warning(req, message)