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

« back to all changes in this revision

Viewing changes to ivle/dispatch/request.py

  • Committer: David Coles
  • Date: 2010-07-17 11:32:50 UTC
  • Revision ID: coles.david@gmail.com-20100717113250-vi18n50bcjmfmzrt
Show warning for CGI header field-names which contain restricted characters.

Forbidden characters are the separators defined by RFC3875. This is mainly to 
fix an issue where printing a dictionary (with no CGI headers) could be 
assumed to be a CGI header with no warnings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
    import mod_python.Session
30
30
    import mod_python.Cookie
31
31
    import mod_python.util
 
32
    import mod_python.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
32
47
except ImportError:
33
48
    # This needs to be importable from outside Apache.
34
49
    pass
35
50
 
 
51
import os.path
 
52
 
36
53
import ivle.util
37
54
import ivle.database
38
55
from ivle.webapp.base.plugins import CookiePlugin
 
56
import ivle.webapp.security
 
57
 
39
58
 
40
59
class Request:
41
60
    """An IVLE request object. This is presented to the IVLE apps as a way of
46
65
            String. The request method (eg. 'GET', 'POST', etc)
47
66
        uri (read)
48
67
            String. The path portion of the URI.
 
68
        unparsed_uri (read)
 
69
            String. The path portion of the URI, unparsed with query string.
49
70
        app (read)
50
71
            String. Name of the application specified in the URL, or None.
51
72
        path (read)
77
98
        location (write)
78
99
            String. Response "Location" header value. Used with HTTP redirect
79
100
            responses.
80
 
        styles (write)
81
 
            List of strings. Write a list of URLs to CSS files here, and they
82
 
            will be incorporated as <link rel="stylesheet" type="text/css">
83
 
            elements in the head, if write_html_head_foot is True.
84
 
            URLs should be relative to the IVLE root; they will be fixed up
85
 
            to be site-relative.
86
 
        scripts (write)
87
 
            List of strings. Write a list of URLs to JS files here, and they
88
 
            will be incorporated as <script type="text/javascript"> elements
89
 
            in the head, if write_html_head_foot is True.
90
 
            URLs should be relative to the IVLE root; they will be fixed up
91
 
            to be site-relative.
92
 
        scripts_init (write)
93
 
            List of strings. Write a list of JS function names, and they
94
 
            will be added as window.addListener('load', ..., false); calls
95
 
            in the head, if write_html_head_foot is True.
96
 
            This is the propper way to specify functions that need to run at 
97
 
            page load time.
98
101
    """
99
102
 
100
103
    # Special code for an OK response.
104
107
 
105
108
    # HTTP status codes
106
109
 
107
 
    HTTP_CONTINUE                     = 100
108
 
    HTTP_SWITCHING_PROTOCOLS          = 101
109
 
    HTTP_PROCESSING                   = 102
110
110
    HTTP_OK                           = 200
111
 
    HTTP_CREATED                      = 201
112
 
    HTTP_ACCEPTED                     = 202
113
 
    HTTP_NON_AUTHORITATIVE            = 203
114
 
    HTTP_NO_CONTENT                   = 204
115
 
    HTTP_RESET_CONTENT                = 205
116
 
    HTTP_PARTIAL_CONTENT              = 206
117
 
    HTTP_MULTI_STATUS                 = 207
118
 
    HTTP_MULTIPLE_CHOICES             = 300
119
 
    HTTP_MOVED_PERMANENTLY            = 301
120
111
    HTTP_MOVED_TEMPORARILY            = 302
121
 
    HTTP_SEE_OTHER                    = 303
122
 
    HTTP_NOT_MODIFIED                 = 304
123
 
    HTTP_USE_PROXY                    = 305
124
 
    HTTP_TEMPORARY_REDIRECT           = 307
125
 
    HTTP_BAD_REQUEST                  = 400
126
 
    HTTP_UNAUTHORIZED                 = 401
127
 
    HTTP_PAYMENT_REQUIRED             = 402
128
112
    HTTP_FORBIDDEN                    = 403
129
113
    HTTP_NOT_FOUND                    = 404
130
 
    HTTP_METHOD_NOT_ALLOWED           = 405
131
 
    HTTP_NOT_ACCEPTABLE               = 406
132
 
    HTTP_PROXY_AUTHENTICATION_REQUIRED= 407
133
 
    HTTP_REQUEST_TIME_OUT             = 408
134
 
    HTTP_CONFLICT                     = 409
135
 
    HTTP_GONE                         = 410
136
 
    HTTP_LENGTH_REQUIRED              = 411
137
 
    HTTP_PRECONDITION_FAILED          = 412
138
 
    HTTP_REQUEST_ENTITY_TOO_LARGE     = 413
139
 
    HTTP_REQUEST_URI_TOO_LARGE        = 414
140
 
    HTTP_UNSUPPORTED_MEDIA_TYPE       = 415
141
 
    HTTP_RANGE_NOT_SATISFIABLE        = 416
142
 
    HTTP_EXPECTATION_FAILED           = 417
143
 
    HTTP_UNPROCESSABLE_ENTITY         = 422
144
 
    HTTP_LOCKED                       = 423
145
 
    HTTP_FAILED_DEPENDENCY            = 424
146
114
    HTTP_INTERNAL_SERVER_ERROR        = 500
147
 
    HTTP_NOT_IMPLEMENTED              = 501
148
 
    HTTP_BAD_GATEWAY                  = 502
149
 
    HTTP_SERVICE_UNAVAILABLE          = 503
150
 
    HTTP_GATEWAY_TIME_OUT             = 504
151
 
    HTTP_VERSION_NOT_SUPPORTED        = 505
152
 
    HTTP_VARIANT_ALSO_VARIES          = 506
153
 
    HTTP_INSUFFICIENT_STORAGE         = 507
154
 
    HTTP_NOT_EXTENDED                 = 510
 
115
 
 
116
    _store = None
155
117
 
156
118
    def __init__(self, req, config):
157
119
        """Create an IVLE request from a mod_python one.
175
137
        # Inherit values for the input members
176
138
        self.method = req.method
177
139
        self.uri = req.uri
 
140
        self.unparsed_uri = req.unparsed_uri
178
141
        # Split the given path into the app (top-level dir) and sub-path
179
142
        # (after first stripping away the root directory)
180
 
        path = ivle.util.unmake_path(req.uri)
181
 
        (self.app, self.path) = (ivle.util.split_path(path))
182
 
        self.user = None
 
143
        (self.app, self.path) = (ivle.util.split_path(req.uri))
183
144
        self.hostname = req.hostname
184
145
        self.headers_in = req.headers_in
185
146
        self.headers_out = req.headers_out
186
147
 
187
 
        # Open a database connection and transaction, keep it around for users
188
 
        # of the Request object to use
189
 
        self.store = ivle.database.get_store(config)
190
 
 
191
148
        # Default values for the output members
192
149
        self.status = Request.HTTP_OK
193
150
        self.content_type = None        # Use Apache's default
194
151
        self.location = None
195
 
        self.styles = []
196
 
        self.scripts = []
197
 
        self.scripts_init = []
198
152
        # In some cases we don't want the template JS (such as the username
199
153
        # and public FQDN) in the output HTML. In that case, set this to 0.
200
154
        self.write_javascript_settings = True
201
155
        self.got_common_vars = False
202
156
 
203
157
    def __del__(self):
204
 
        """Cleanup."""
205
 
        self.store.close()
 
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()
206
170
 
207
171
    def __writeheaders(self):
208
172
        """Writes out the HTTP and HTML headers before any real data is
251
215
                for cookie in plugin.cookies:
252
216
                    self.add_cookie(mod_python.Cookie.Cookie(cookie, '',
253
217
                                                    expires=1, path='/'))
254
 
        self.throw_redirect(ivle.util.make_path('')) 
 
218
        self.throw_redirect(self.make_path(''))
255
219
 
256
220
 
257
221
    def flush(self):
291
255
        else:
292
256
            mod_python.Cookie.add_cookie(self.apache_req, cookie, value, **attributes)
293
257
 
 
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
 
294
267
    def get_session(self):
295
268
        """Returns a mod_python Session object for this request.
296
269
        Note that this is dependent on mod_python and may need to change
301
274
        """
302
275
        # Cache the session object and set the timeout to 24 hours.
303
276
        if not hasattr(self, 'session'):
304
 
            self.session = mod_python.Session.FileSession(self.apache_req,
305
 
                                               timeout = 60 * 60 * 24)
 
277
            self.session = PotentiallySecureFileSession(
 
278
                self.apache_req, timeout = 60 * 60 * 24)
306
279
        return self.session
307
280
 
308
281
    def get_fieldstorage(self):
323
296
            self.got_common_vars = True
324
297
        return self.apache_req.subprocess_env
325
298
 
326
 
    @staticmethod
327
 
    def get_http_codename(code):
328
 
        """Given a HTTP error code int, returns a (name, description)
329
 
        pair, suitable for displaying to the user.
330
 
        May return (None,None) if code is unknown.
331
 
        Only lists common 4xx and 5xx codes (since this is just used
332
 
        to display throw_error error messages).
333
 
        """
 
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.
334
312
        try:
335
 
            return http_codenames[code]
336
 
        except KeyError:
337
 
            return None, None
 
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
338
324
 
339
 
# Human strings for HTTP response codes
340
 
http_codenames = {
341
 
    Request.HTTP_BAD_REQUEST:
342
 
        ("Bad Request",
343
 
        "Your browser sent a request IVLE did not understand."),
344
 
    Request.HTTP_UNAUTHORIZED:
345
 
        ("Unauthorized",
346
 
        "You are not allowed to view this part of IVLE."),
347
 
    Request.HTTP_FORBIDDEN:
348
 
        ("Forbidden",
349
 
        "You are not allowed to view this part of IVLE."),
350
 
    Request.HTTP_NOT_FOUND:
351
 
        ("Not Found",
352
 
        "The application or file you requested does not exist."),
353
 
    Request.HTTP_METHOD_NOT_ALLOWED:
354
 
        ("Method Not Allowed",
355
 
        "Your browser is interacting with IVLE in the wrong way."
356
 
        "This is probably a bug in IVLE. "
357
 
        "Please report it to the administrators."),
358
 
    Request.HTTP_INTERNAL_SERVER_ERROR:
359
 
        ("Internal Server Error",
360
 
        "An unknown error occured in IVLE."),
361
 
    Request.HTTP_NOT_IMPLEMENTED:
362
 
        ("Not Implemented",
363
 
        "The application or file you requested has not been implemented "
364
 
        "in IVLE."),
365
 
    Request.HTTP_SERVICE_UNAVAILABLE:
366
 
        ("Service Unavailable",
367
 
        "IVLE is currently experiencing technical difficulties. "
368
 
        "Please try again later."),
369
 
}