1 """Native adapter for serving CherryPy via mod_python
2
3 Basic usage:
4
5 ##########################################
6 # Application in a module called myapp.py
7 ##########################################
8
9 import cherrypy
10
11 class Root:
12 @cherrypy.expose
13 def index(self):
14 return 'Hi there, Ho there, Hey there'
15
16
17 # We will use this method from the mod_python configuration
18 # as the entyr point to our application
19 def setup_server():
20 cherrypy.tree.mount(Root())
21 cherrypy.config.update({'environment': 'production',
22 'log.screen': False,
23 'show_tracebacks': False})
24 # You must start the engine in a non-blocking fashion
25 # so that mod_python can proceed
26 cherrypy.engine.start(blocking=False)
27
28 ##########################################
29 # mod_python settings for apache2
30 # This should reside in your httpd.conf
31 # or a file that will be loaded at
32 # apache startup
33 ##########################################
34
35 # Start
36 DocumentRoot "/"
37 Listen 8080
38 LoadModule python_module /usr/lib/apache2/modules/mod_python.so
39
40 <Location "/">
41 PythonPath "sys.path+['/path/to/my/application']"
42 SetHandler python-program
43 PythonHandler cherrypy._cpmodpy::handler
44 PythonOption cherrypy.setup myapp::setup_server
45 PythonDebug On
46 </Location>
47 # End
48
49 The actual path to your mod_python.so is dependant of your
50 environment. In this case we suppose a global mod_python
51 installation on a Linux distribution such as Ubuntu.
52
53 We do set the PythonPath configuration setting so that
54 your application can be found by from the user running
55 the apache2 instance. Of course if your application
56 resides in the global site-package this won't be needed.
57
58 Then restart apache2 and access http://localhost:8080
59 """
60
61 import StringIO
62
63 import cherrypy
64 from cherrypy._cperror import format_exc, bare_error
65 from cherrypy.lib import http
66
67
68
69
70
71
93 try:
94 from mod_python import apache
95
96 apache.register_cleanup(cherrypy_cleanup)
97 except AttributeError:
98 req.server.register_cleanup(req, cherrypy_cleanup)
99
100
102 expose = ('read', 'readline', 'readlines')
106
107
108 recursive = False
109
110 _isSetUp = False
112 from mod_python import apache
113 try:
114 global _isSetUp
115 if not _isSetUp:
116 setup(req)
117 _isSetUp = True
118
119
120 local = req.connection.local_addr
121 local = http.Host(local[0], local[1], req.connection.local_host or "")
122 remote = req.connection.remote_addr
123 remote = http.Host(remote[0], remote[1], req.connection.remote_host or "")
124
125 scheme = req.parsed_uri[0] or 'http'
126 req.get_basic_auth_pw()
127
128 try:
129
130 q = apache.mpm_query
131 threaded = q(apache.AP_MPMQ_IS_THREADED)
132 forked = q(apache.AP_MPMQ_IS_FORKED)
133 except AttributeError:
134 bad_value = ("You must provide a PythonOption '%s', "
135 "either 'on' or 'off', when running a version "
136 "of mod_python < 3.1")
137
138 threaded = options.get('multithread', '').lower()
139 if threaded == 'on':
140 threaded = True
141 elif threaded == 'off':
142 threaded = False
143 else:
144 raise ValueError(bad_value % "multithread")
145
146 forked = options.get('multiprocess', '').lower()
147 if forked == 'on':
148 forked = True
149 elif forked == 'off':
150 forked = False
151 else:
152 raise ValueError(bad_value % "multiprocess")
153
154 sn = cherrypy.tree.script_name(req.uri or "/")
155 if sn is None:
156 send_response(req, '404 Not Found', [], '')
157 else:
158 app = cherrypy.tree.apps[sn]
159 method = req.method
160 path = req.uri
161 qs = req.args or ""
162 sproto = req.protocol
163 headers = req.headers_in.items()
164 rfile = _ReadOnlyRequest(req)
165 prev = None
166
167 redirections = []
168 while True:
169 request = cherrypy.engine.request(local, remote, scheme)
170 request.login = req.user
171 request.multithread = bool(threaded)
172 request.multiprocess = bool(forked)
173 request.app = app
174 request.prev = prev
175
176
177 try:
178 response = request.run(method, path, qs, sproto, headers, rfile)
179 break
180 except cherrypy.InternalRedirect, ir:
181 cherrypy.engine.release()
182 prev = request
183
184 if not recursive:
185 if ir.path in redirections:
186 raise RuntimeError("InternalRedirector visited the "
187 "same URL twice: %r" % ir.path)
188 else:
189
190 if qs:
191 qs = "?" + qs
192 redirections.append(sn + path + qs)
193
194
195 method = "GET"
196 path = ir.path
197 qs = ir.query_string
198 rfile = StringIO.StringIO()
199
200 send_response(req, response.status, response.header_list, response.body)
201 cherrypy.engine.release()
202 except:
203 tb = format_exc()
204 cherrypy.log(tb)
205 s, h, b = bare_error()
206 send_response(req, s, h, b)
207 return apache.OK
208
210
211 req.status = int(status[:3])
212
213
214 req.content_type = "text/plain"
215 for header, value in headers:
216 if header.lower() == 'content-type':
217 req.content_type = value
218 continue
219 req.headers_out.add(header, value)
220
221
222 if isinstance(body, basestring):
223 req.write(body)
224 else:
225 for seg in body:
226 req.write(seg)
227
228
229
230
231
232
233 import os
234 import re
235
236
238 pipein, pipeout = os.popen4("%s %s" % (cmd, args))
239 try:
240 firstline = pipeout.readline()
241 if (re.search(r"(not recognized|No such file|not found)", firstline,
242 re.IGNORECASE)):
243 raise IOError('%s must be on your system path.' % cmd)
244 output = firstline + pipeout.read()
245 finally:
246 pipeout.close()
247 return output
248
249
251
252 template = """
253 # Apache2 server configuration file for running CherryPy with mod_python.
254
255 DocumentRoot "/"
256 Listen %(port)s
257 LoadModule python_module modules/mod_python.so
258
259 <Location %(loc)s>
260 SetHandler python-program
261 PythonHandler %(handler)s
262 PythonDebug On
263 %(opts)s
264 </Location>
265 """
266
267 - def __init__(self, loc="/", port=80, opts=None, apache_path="apache",
268 handler="cherrypy._cpmodpy::handler"):
269 self.loc = loc
270 self.port = port
271 self.opts = opts
272 self.apache_path = apache_path
273 self.handler = handler
274
276 opts = "".join([" PythonOption %s %s\n" % (k, v)
277 for k, v in self.opts])
278 conf_data = self.template % {"port": self.port,
279 "loc": self.loc,
280 "opts": opts,
281 "handler": self.handler,
282 }
283
284 mpconf = os.path.join(os.path.dirname(__file__), "cpmodpy.conf")
285 f = open(mpconf, 'wb')
286 try:
287 f.write(conf_data)
288 finally:
289 f.close()
290
291 response = read_process(self.apache_path, "-k start -f %s" % mpconf)
292 self.ready = True
293 return response
294
296 os.popen("apache -k stop")
297 self.ready = False
298