Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/tags/cherrypy-3.0.0/cherrypy/_cpmodpy.py

Revision 1433 (checked in by fumanchu, 3 years ago)

InternalRedirect? changes:

  1. Moved InternalRedirect? out of the Request object, so that an IR creates a separate Request object per redirect. This makes the design of hooks and tools (both builtin and user-defined) much simpler and safer.
  2. New _cpwsgi.InternalRedirector? for the WSGI implementation. Users who do not use InternalRedirects? at all can remove this from the wsgi pipeline if they wish.
  3. InternalRedirect? trap implemented in _cpmodpy.py
  4. Custom servers/gateways will have to write their own handling for InternalRedirect? being thrown from request.run.
  5. Request.redirections (a list of URL's) removed in favor of request.prev, which points to the previous Request object in a redirection chain. Defaults to None.
  6. Replace "request.recursive" (per request) with "wsgi.iredir.recursive" (per app).
  7. Removed Request.body_read and .headers_read.
  8. New Request.throws tuple of exceptions which should not be trapped.
  • Property svn:eol-style set to native
Line 
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 # ------------------------------ Request-handling
70
71
72 def setup(req):
73     # Run any setup function defined by a "PythonOption cherrypy.setup" directive.
74     options = req.get_options()
75     if 'cherrypy.setup' in options:
76         modname, fname = options['cherrypy.setup'].split('::')
77         mod = __import__(modname, globals(), locals(), [fname])
78         func = getattr(mod, fname)
79         func()
80    
81     cherrypy.config.update({'log.screen': False,
82                             "tools.ignore_headers.on": True,
83                             "tools.ignore_headers.headers": ['Range'],
84                             })
85    
86     if cherrypy.engine.state == cherrypy._cpengine.STOPPED:
87         cherrypy.engine.start(blocking=False)
88     elif cherrypy.engine.state == cherrypy._cpengine.STARTING:
89         cherrypy.engine.wait()
90    
91     def cherrypy_cleanup(data):
92         cherrypy.engine.stop()
93     try:
94         from mod_python import apache
95         # apache.register_cleanup wasn't available until 3.1.4.
96         apache.register_cleanup(cherrypy_cleanup)
97     except AttributeError:
98         req.server.register_cleanup(req, cherrypy_cleanup)
99
100
101 class _ReadOnlyRequest:
102     expose = ('read', 'readline', 'readlines')
103     def __init__(self, req):
104         for method in self.expose:
105             self.__dict__[method] = getattr(req, method)
106
107
108 recursive = False
109
110 _isSetUp = False
111 def handler(req):
112     from mod_python import apache
113     try:
114         global _isSetUp
115         if not _isSetUp:
116             setup(req)
117             _isSetUp = True
118        
119         # Obtain a Request object from CherryPy
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             # apache.mpm_query only became available in mod_python 3.1
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                 # Run the CherryPy Request object and obtain the response
177                 try:
178                     response = request.run(method, path, qs, sproto, headers, rfile)
179                     break
180                 except cherrypy.InternalRedirect, ir:
181                     request.close()
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                             # Add the *previous* path_info + qs to redirections.
190                             if qs:
191                                 qs = "?" + qs
192                             redirections.append(sn + path + qs)
193                    
194                     # Munge environment and try again.
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             request.close()
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
209 def send_response(req, status, headers, body):
210     # Set response status
211     req.status = int(status[:3])
212    
213     # Set response headers
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     # Set response body
222     if isinstance(body, basestring):
223         req.write(body)
224     else:
225         for seg in body:
226             req.write(seg)
227
228
229
230 # --------------- Startup tools for CherryPy + mod_python --------------- #
231
232
233 import os
234 import re
235
236
237 def read_process(cmd, args=""):
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
250 class ModPythonServer(object):
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    
275     def start(self):
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    
295     def stop(self):
296         os.popen("apache -k stop")
297         self.ready = False
298
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets