Ticket #376: modpython2_svn.py

File modpython2_svn.py, 6.7 KB (added by Sanel, 9 years ago)

Synced mod_python 2.x changes with latest svn code

Line 
1from django.core.handlers.base import BaseHandler
2from django.core import signals
3from django.dispatch import dispatcher
4from django.utils import datastructures
5from django import http
6from pprint import pformat
7import os
8
9# NOTE: do *not* import settings (or any module which eventually imports
10# settings) until after ModPythonHandler has been called; otherwise os.environ
11# won't be set up correctly (with respect to settings).
12
13class ModPythonRequest(http.HttpRequest):
14    def __init__(self, req):
15        self._req = req
16        self.path = req.uri
17
18    def __repr__(self):
19        # Since this is called as part of error handling, we need to be very
20        # robust against potentially malformed input.
21        try:
22            get = pformat(self.GET)
23        except:
24            get = '<could not parse>'
25        try:
26            post = pformat(self.POST)
27        except:
28            post = '<could not parse>'
29        try:
30            cookies = pformat(self.COOKIES)
31        except:
32            cookies = '<could not parse>'
33        try:
34            meta = pformat(self.META)
35        except:
36            meta = '<could not parse>'
37        return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \
38            (self.path, get, post, cookies, meta)
39
40    def get_full_path(self):
41        return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
42
43    def is_secure(self):
44        # Note: modpython 3.2.10+ has req.is_https(), but we need to support previous versions
45        return self._req.subprocess_env.has_key('HTTPS') and self._req.subprocess_env['HTTPS'] == 'on'
46
47    def _load_post_and_files(self):
48        "Populates self._post and self._files"
49        if self._req.headers_in.has_key('content-type') and self._req.headers_in['content-type'].startswith('multipart'):
50            self._post, self._files = http.parse_file_upload(self._req.headers_in, self.raw_post_data)
51        else:
52            self._post, self._files = http.QueryDict(self.raw_post_data), datastructures.MultiValueDict()
53
54    def _get_request(self):
55        if not hasattr(self, '_request'):
56            self._request = datastructures.MergeDict(self.POST, self.GET)
57        return self._request
58
59    def _get_get(self):
60        if not hasattr(self, '_get'):
61            self._get = http.QueryDict(self._req.args)
62        return self._get
63
64    def _set_get(self, get):
65        self._get = get
66
67    def _get_post(self):
68        if not hasattr(self, '_post'):
69            self._load_post_and_files()
70        return self._post
71
72    def _set_post(self, post):
73        self._post = post
74
75    def _get_cookies(self):
76        if not hasattr(self, '_cookies'):
77            if self._req.headers_in.has_key('cookie'):
78                self._cookies = http.parse_cookie(self._req.headers_in['cookie'])
79            else:
80                self._cookies = http.parse_cookie('')
81        return self._cookies
82
83    def _set_cookies(self, cookies):
84        self._cookies = cookies
85
86    def _get_files(self):
87        if not hasattr(self, '_files'):
88            self._load_post_and_files()
89        return self._files
90
91    def _get_meta(self):
92        "Lazy loader that returns self.META dictionary"
93        if not hasattr(self, '_meta'):
94            self._meta = {
95                'AUTH_TYPE':         self._req.connection.ap_auth_type,
96                'CONTENT_LENGTH':    self._req.clength, # This may be wrong
97                'CONTENT_TYPE':      self._req.content_type, # This may be wrong
98                'GATEWAY_INTERFACE': 'CGI/1.1',
99                'PATH_INFO':         self._req.path_info,
100                'PATH_TRANSLATED':   None, # Not supported
101                'QUERY_STRING':      self._req.args,
102                'REMOTE_ADDR':       self._req.connection.remote_ip,
103                'REMOTE_HOST':       None, # DNS lookups not supported
104                'REMOTE_IDENT':      self._req.connection.remote_logname,
105                'REMOTE_USER':       self._req.connection.user,
106                'REQUEST_METHOD':    self._req.method,
107                'SCRIPT_NAME':       None, # Not supported
108                'SERVER_NAME':       self._req.server.server_hostname,
109                'SERVER_PORT':       self._req.server.port,
110                'SERVER_PROTOCOL':   self._req.protocol,
111                'SERVER_SOFTWARE':   'mod_python'
112            }
113            for key in self._req.headers_in.keys():
114                nkey = 'HTTP_' + key.upper().replace('-', '_')
115                self._meta[nkey] = self._req.headers_in[key]
116        return self._meta
117
118    def _get_raw_post_data(self):
119        try:
120            return self._raw_post_data
121        except AttributeError:
122            self._raw_post_data = self._req.read()
123            return self._raw_post_data
124
125    def _get_method(self):
126        return self.META['REQUEST_METHOD'].upper()
127
128    GET = property(_get_get, _set_get)
129    POST = property(_get_post, _set_post)
130    COOKIES = property(_get_cookies, _set_cookies)
131    FILES = property(_get_files)
132    META = property(_get_meta)
133    REQUEST = property(_get_request)
134    raw_post_data = property(_get_raw_post_data)
135    method = property(_get_method)
136
137class ModPythonHandler(BaseHandler):
138    def __call__(self, req):
139        # mod_python fakes the environ, and thus doesn't process SetEnv.  This fixes that
140        os.environ.update(req.subprocess_env)
141
142        # now that the environ works we can see the correct settings, so imports
143        # that use settings now can work
144        from django.conf import settings
145
146        # if we need to set up middleware, now that settings works we can do it now.
147        if self._request_middleware is None:
148            self.load_middleware()
149
150        dispatcher.send(signal=signals.request_started)
151        try:
152            request = ModPythonRequest(req)
153            response = self.get_response(request)
154
155            # Apply response middleware
156            for middleware_method in self._response_middleware:
157                response = middleware_method(request, response)
158
159        finally:
160            dispatcher.send(signal=signals.request_finished)
161
162        # Convert our custom HttpResponse object back into the mod_python req.
163        req.content_type = response['Content-Type']
164        for key, value in response.headers.items():
165            if key != 'Content-Type':
166                req.headers_out[key] = value
167        for c in response.cookies.values():
168            req.headers_out.add('Set-Cookie', c.output(header=''))
169        req.status = response.status_code
170        try:
171            req.send_http_header()
172            for chunk in response:
173                req.write(chunk)
174        finally:
175            response.close()
176
177        return 0 # mod_python.apache.OK
178
179def handler(req):
180    # mod_python hooks into this function.
181    return ModPythonHandler()(req)
Back to Top