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

1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
1
# IVLE - Informatics Virtual Learning Environment
1080.1.2 by matt.giuca
New module: ivle.database. Classes and utilities for Storm ORM.
2
# Copyright (C) 2007-2009 The University of Melbourne
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18
# Author: Matt Giuca
1080.1.2 by matt.giuca
New module: ivle.database. Classes and utilities for Storm ORM.
19
20
"""
21
IVLE Request Object
22
23
Builds an IVLE request object from a mod_python request object.
24
See design notes/apps/dispatch.txt for a full specification of this request
25
object.
26
"""
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
27
1099.1.5 by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can
28
try:
29
    import mod_python.Session
30
    import mod_python.Cookie
31
    import mod_python.util
1750 by William Grant
Set 'secure' flag on cookies if served over a direct or proxied HTTPS connection.
32
    import mod_python.apache
1754 by William Grant
Move PotentiallySecureFileSession into the try/export import block, so ivle.dispatch.request can be imported from outside Apache.
33
34
    class PotentiallySecureFileSession(mod_python.Session.FileSession):
35
        """A mod_python FileSession that sets secure cookie when appropriate.
36
37
        A secure cookie will be set if the request itself is over HTTPS, or if
38
        a proxy in front has set X-Forwarded-Proto: https. Otherwise the cookie
39
        will be insecure.
40
        """
41
        def make_cookie(self):
42
            cookie = super(PotentiallySecureFileSession, self).make_cookie()
43
            if (self._req.is_https() or
44
                self._req.headers_in.get('X-Forwarded-Proto') == 'https'):
45
                cookie.secure = True
46
            return cookie
1099.1.5 by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can
47
except ImportError:
48
    # This needs to be importable from outside Apache.
49
    pass
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
50
1208 by William Grant
Replace ivle.util.unmake_path with specialisations in Request and CGIRequest.
51
import os.path
52
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
53
import ivle.util
1080.1.2 by matt.giuca
New module: ivle.database. Classes and utilities for Storm ORM.
54
import ivle.database
1099.1.80 by William Grant
Port the forum app to the new framework. With it also comes new cookie
55
from ivle.webapp.base.plugins import CookiePlugin
1712 by William Grant
Shuffle things around so that req.user and req.store only construct when actually retrieved, and ensure they're not retrieved for media files. Saves 50ms of DB connection time per request.
56
import ivle.webapp.security
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
57
1750 by William Grant
Set 'secure' flag on cookies if served over a direct or proxied HTTPS connection.
58
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
59
class Request:
60
    """An IVLE request object. This is presented to the IVLE apps as a way of
61
    interacting with the web server and the dispatcher.
62
63
    Request object attributes:
64
        method (read)
65
            String. The request method (eg. 'GET', 'POST', etc)
66
        uri (read)
67
            String. The path portion of the URI.
1796.1.3 by William Grant
Use req.unparsed_uri instead of req.uri -- req.uri doesn't contain the query string.
68
        unparsed_uri (read)
69
            String. The path portion of the URI, unparsed with query string.
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
70
        app (read)
71
            String. Name of the application specified in the URL, or None.
72
        path (read)
73
            String. The path specified in the URL *not including* the
74
            application or the IVLE location prefix. eg. a URL of
75
            "/ivle/files/joe/myfiles" has a path of "joe/myfiles".
76
        user (read)
77
            User object. Details of the user who is currently logged in, or
78
            None.
1080.1.2 by matt.giuca
New module: ivle.database. Classes and utilities for Storm ORM.
79
        store (read)
80
            storm.store.Store instance. Holds a database transaction open,
81
            which is available for the entire lifetime of the request.
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
82
        hostname (read)
83
            String. Hostname the server is running on.
84
        headers_in (read)
85
            Table object representing headers sent by the client.
86
        headers_out (read, can be written to)
87
            Table object representing headers to be sent to the client.
88
        publicmode (read)
89
            Bool. True if the request came for the "public host" as
90
            configured in conf.py. Note that public mode requests do not
91
            have an app (app is set to None).
92
93
        status (write)
94
            Int. Response status number. Use one of the status codes defined
95
            in class Request.
96
        content_type (write)
97
            String. The Content-Type (mime type) header value.
98
        location (write)
99
            String. Response "Location" header value. Used with HTTP redirect
100
            responses.
101
    """
102
103
    # Special code for an OK response.
104
    # Do not use HTTP_OK; for some reason Apache produces an "OK" error
105
    # message if you do that.
106
    OK  = 0
107
108
    # HTTP status codes
109
110
    HTTP_OK                           = 200
111
    HTTP_MOVED_TEMPORARILY            = 302
112
    HTTP_FORBIDDEN                    = 403
113
    HTTP_NOT_FOUND                    = 404
114
    HTTP_INTERNAL_SERVER_ERROR        = 500
115
1712 by William Grant
Shuffle things around so that req.user and req.store only construct when actually retrieved, and ensure they're not retrieved for media files. Saves 50ms of DB connection time per request.
116
    _store = None
117
1199 by William Grant
Populate req.config in a cleaner manner.
118
    def __init__(self, req, config):
119
        """Create an IVLE request from a mod_python one.
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
120
1199 by William Grant
Populate req.config in a cleaner manner.
121
        @param req: A mod_python request.
122
        @param config: An IVLE configuration.
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
123
        """
124
125
        # Methods are mostly wrappers around the Apache request object
126
        self.apache_req = req
1199 by William Grant
Populate req.config in a cleaner manner.
127
        self.config = config
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
128
        self.headers_written = False
129
130
        # Determine if the browser used the public host name to make the
131
        # request (in which case we are in "public mode")
1199 by William Grant
Populate req.config in a cleaner manner.
132
        if req.hostname == config['urls']['public_host']:
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
133
            self.publicmode = True
134
        else:
135
            self.publicmode = False
136
137
        # Inherit values for the input members
138
        self.method = req.method
139
        self.uri = req.uri
1796.1.3 by William Grant
Use req.unparsed_uri instead of req.uri -- req.uri doesn't contain the query string.
140
        self.unparsed_uri = req.unparsed_uri
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
141
        # Split the given path into the app (top-level dir) and sub-path
142
        # (after first stripping away the root directory)
1288 by William Grant
Kill Request.unmake_path.
143
        (self.app, self.path) = (ivle.util.split_path(req.uri))
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
144
        self.hostname = req.hostname
145
        self.headers_in = req.headers_in
146
        self.headers_out = req.headers_out
147
148
        # Default values for the output members
149
        self.status = Request.HTTP_OK
150
        self.content_type = None        # Use Apache's default
151
        self.location = None
152
        # In some cases we don't want the template JS (such as the username
153
        # and public FQDN) in the output HTML. In that case, set this to 0.
154
        self.write_javascript_settings = True
155
        self.got_common_vars = False
156
1080.1.2 by matt.giuca
New module: ivle.database. Classes and utilities for Storm ORM.
157
    def __del__(self):
1712 by William Grant
Shuffle things around so that req.user and req.store only construct when actually retrieved, and ensure they're not retrieved for media files. Saves 50ms of DB connection time per request.
158
        self.cleanup()
159
160
    def cleanup(self):
161
        """Cleanup."""
162
        if self._store is not None:
163
            self._store.close()
164
            self._store = None
165
166
    def commit(self):
167
        """Cleanup."""
168
        if self._store is not None:
169
            self._store.commit()
1080.1.2 by matt.giuca
New module: ivle.database. Classes and utilities for Storm ORM.
170
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
171
    def __writeheaders(self):
172
        """Writes out the HTTP and HTML headers before any real data is
173
        written."""
174
        self.headers_written = True
175
176
        # Prepare the HTTP and HTML headers before the first write is made
177
        if self.content_type != None:
178
            self.apache_req.content_type = self.content_type
179
        self.apache_req.status = self.status
180
        if self.location != None:
181
            self.apache_req.headers_out['Location'] = self.location
182
183
    def ensure_headers_written(self):
184
        """Writes out the HTTP and HTML headers if they haven't already been
185
        written."""
186
        if not self.headers_written:
187
            self.__writeheaders()
188
189
    def write(self, string, flush=1):
190
        """Writes string directly to the client, then flushes the buffer,
191
        unless flush is 0."""
192
193
        if not self.headers_written:
194
            self.__writeheaders()
195
        if isinstance(string, unicode):
196
            # Encode unicode strings as UTF-8
197
            # (Otherwise cannot handle being written to a bytestream)
198
            self.apache_req.write(string.encode('utf8'), flush)
199
        else:
200
            # 8-bit clean strings just get written directly.
201
            # This includes binary strings.
202
            self.apache_req.write(string, flush)
203
1081 by me at id
ivle.conf, ivle.dispatch: Redo some of Nick's changes made between the
204
    def logout(self):
205
        """Log out the current user by destroying the session state.
206
        Then redirect to the top-level IVLE page."""
207
        if hasattr(self, 'session'):
208
            self.session.invalidate()
209
            self.session.delete()
210
            # Invalidates all IVLE cookies
1099.1.5 by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can
211
            all_cookies = mod_python.Cookie.get_cookies(self)
1099.1.80 by William Grant
Port the forum app to the new framework. With it also comes new cookie
212
213
            # Create cookies for plugins that might request them.
1092.1.61 by William Grant
Fix cookie deletion.
214
            for plugin in self.config.plugin_index[CookiePlugin]:
1099.1.80 by William Grant
Port the forum app to the new framework. With it also comes new cookie
215
                for cookie in plugin.cookies:
216
                    self.add_cookie(mod_python.Cookie.Cookie(cookie, '',
217
                                                    expires=1, path='/'))
1210 by William Grant
Use Request.make_path everywhere.
218
        self.throw_redirect(self.make_path(''))
1081 by me at id
ivle.conf, ivle.dispatch: Redo some of Nick's changes made between the
219
220
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
221
    def flush(self):
222
        """Flushes the output buffer."""
223
        self.apache_req.flush()
224
225
    def sendfile(self, filename):
226
        """Sends the named file directly to the client."""
227
        if not self.headers_written:
228
            self.__writeheaders()
229
        self.apache_req.sendfile(filename)
230
231
    def read(self, len=None):
232
        """Reads at most len bytes directly from the client. (See mod_python
233
        Request.read)."""
234
        if len is None:
235
            return self.apache_req.read()
236
        else:
237
            return self.apache_req.read(len)
238
239
    def throw_redirect(self, location):
240
        """Writes out an HTTP redirect to the specified URL. Raises an
241
        exception which is caught by the dispatch or web server, so any
242
        code following this call will not be executed.
243
244
        httpcode: An HTTP response status code. Pass a constant from the
245
        Request class.
246
        """
1080.1.7 by matt.giuca
The new ivle.database.User class is now used in Request and usrmgt, which
247
        # Note: location may be a unicode, but it MUST only have ASCII
248
        # characters (non-ascii characters should be URL-encoded).
249
        mod_python.util.redirect(self.apache_req, location.encode("ascii"))
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
250
251
    def add_cookie(self, cookie, value=None, **attributes):
252
        """Inserts a cookie into this request object's headers."""
253
        if value is None:
1099.1.5 by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can
254
            mod_python.Cookie.add_cookie(self.apache_req, cookie)
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
255
        else:
1099.1.5 by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can
256
            mod_python.Cookie.add_cookie(self.apache_req, cookie, value, **attributes)
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
257
1209 by William Grant
Add Request.make_path, to replace ivle.util.make_path.
258
    def make_path(self, path):
259
        """Prepend the IVLE URL prefix to the given path.
260
261
        This is used when generating URLs to send to the client.
262
263
        This method is DEPRECATED. We no longer support use of a prefix.
264
        """
265
        return os.path.join(self.config['urls']['root'], path)
266
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
267
    def get_session(self):
268
        """Returns a mod_python Session object for this request.
269
        Note that this is dependent on mod_python and may need to change
1130 by William Grant
Unlock the session everywhere as soon as we are done with it, and add a warning
270
        interface if porting away from mod_python.
271
272
        IMPORTANT: Call unlock() on the session as soon as you are done with
273
                   it! If you don't, all other requests will block!
274
        """
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
275
        # Cache the session object and set the timeout to 24 hours.
276
        if not hasattr(self, 'session'):
1750 by William Grant
Set 'secure' flag on cookies if served over a direct or proxied HTTPS connection.
277
            self.session = PotentiallySecureFileSession(
278
                self.apache_req, timeout = 60 * 60 * 24)
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
279
        return self.session
280
281
    def get_fieldstorage(self):
282
        """Returns a mod_python FieldStorage object for this request.
283
        Note that this is dependent on mod_python and may need to change
284
        interface if porting away from mod_python."""
285
        # Cache the fieldstorage object
286
        if not hasattr(self, 'fields'):
1099.1.5 by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can
287
            self.fields = mod_python.util.FieldStorage(self.apache_req)
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
288
        return self.fields
289
290
    def get_cgi_environ(self):
291
        """Returns the CGI environment emulation for this request. (Calls
292
        add_common_vars). The environment is returned as a mapping
293
        compatible with os.environ."""
294
        if not self.got_common_vars:
295
            self.apache_req.add_common_vars()
296
            self.got_common_vars = True
297
        return self.apache_req.subprocess_env
298
1712 by William Grant
Shuffle things around so that req.user and req.store only construct when actually retrieved, and ensure they're not retrieved for media files. Saves 50ms of DB connection time per request.
299
    @property
300
    def store(self):
301
        # Open a database connection and transaction, keep it around for users
302
        # of the Request object to use.
303
        if self._store is None:
304
            self._store = ivle.database.get_store(self.config)
305
        return self._store
306
307
    @property
308
    def user(self):
309
        # Get and cache the request user, or None if it's not valid.
310
        # This is a property so that we don't create a store unless
311
        # some code actually requests the user.
312
        try:
313
            return self._user
314
        except AttributeError:
315
            if self.publicmode:
316
                self._user = None
317
            else:
318
                temp_user = ivle.webapp.security.get_user_details(self)
319
                if temp_user and temp_user.valid:
320
                    self._user = temp_user
321
                else:
322
                    self._user = None
323
            return self._user
324