Ticket #376: modpython2_svn.py

File modpython2_svn.py, 6.7 KB (added by Sanel, 17 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