_cpmodpy.py (7671B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\_cpmodpy.py 2 import logging 3 import sys 4 import cherrypy 5 from cherrypy._cpcompat import BytesIO, copyitems, ntob 6 from cherrypy._cperror import format_exc, bare_error 7 from cherrypy.lib import httputil 8 9 def setup(req): 10 from mod_python import apache 11 options = req.get_options() 12 if 'cherrypy.setup' in options: 13 for function in options['cherrypy.setup'].split(): 14 atoms = function.split('::', 1) 15 if len(atoms) == 1: 16 mod = __import__(atoms[0], globals(), locals()) 17 else: 18 modname, fname = atoms 19 mod = __import__(modname, globals(), locals(), [fname]) 20 func = getattr(mod, fname) 21 func() 22 23 cherrypy.config.update({'log.screen': False, 24 'tools.ignore_headers.on': True, 25 'tools.ignore_headers.headers': ['Range']}) 26 engine = cherrypy.engine 27 if hasattr(engine, 'signal_handler'): 28 engine.signal_handler.unsubscribe() 29 if hasattr(engine, 'console_control_handler'): 30 engine.console_control_handler.unsubscribe() 31 engine.autoreload.unsubscribe() 32 cherrypy.server.unsubscribe() 33 34 def _log(msg, level): 35 newlevel = apache.APLOG_ERR 36 if logging.DEBUG >= level: 37 newlevel = apache.APLOG_DEBUG 38 elif logging.INFO >= level: 39 newlevel = apache.APLOG_INFO 40 elif logging.WARNING >= level: 41 newlevel = apache.APLOG_WARNING 42 apache.log_error(msg, newlevel, req.server) 43 44 engine.subscribe('log', _log) 45 engine.start() 46 47 def cherrypy_cleanup(data): 48 engine.exit() 49 50 try: 51 apache.register_cleanup(cherrypy_cleanup) 52 except AttributeError: 53 req.server.register_cleanup(req, cherrypy_cleanup) 54 55 56 class _ReadOnlyRequest: 57 expose = ('read', 'readline', 'readlines') 58 59 def __init__(self, req): 60 for method in self.expose: 61 self.__dict__[method] = getattr(req, method) 62 63 64 recursive = False 65 _isSetUp = False 66 67 def handler(req): 68 global _isSetUp 69 from mod_python import apache 70 try: 71 if not _isSetUp: 72 setup(req) 73 _isSetUp = True 74 local = req.connection.local_addr 75 local = httputil.Host(local[0], local[1], req.connection.local_host or '') 76 remote = req.connection.remote_addr 77 remote = httputil.Host(remote[0], remote[1], req.connection.remote_host or '') 78 scheme = req.parsed_uri[0] or 'http' 79 req.get_basic_auth_pw() 80 try: 81 q = apache.mpm_query 82 threaded = q(apache.AP_MPMQ_IS_THREADED) 83 forked = q(apache.AP_MPMQ_IS_FORKED) 84 except AttributeError: 85 bad_value = "You must provide a PythonOption '%s', either 'on' or 'off', when running a version of mod_python < 3.1" 86 threaded = options.get('multithread', '').lower() 87 if threaded == 'on': 88 threaded = True 89 elif threaded == 'off': 90 threaded = False 91 else: 92 raise ValueError(bad_value % 'multithread') 93 forked = options.get('multiprocess', '').lower() 94 if forked == 'on': 95 forked = True 96 elif forked == 'off': 97 forked = False 98 else: 99 raise ValueError(bad_value % 'multiprocess') 100 101 sn = cherrypy.tree.script_name(req.uri or '/') 102 if sn is None: 103 send_response(req, '404 Not Found', [], '') 104 else: 105 app = cherrypy.tree.apps[sn] 106 method = req.method 107 path = req.uri 108 qs = req.args or '' 109 reqproto = req.protocol 110 headers = copyitems(req.headers_in) 111 rfile = _ReadOnlyRequest(req) 112 prev = None 113 try: 114 redirections = [] 115 while True: 116 request, response = app.get_serving(local, remote, scheme, 'HTTP/1.1') 117 request.login = req.user 118 request.multithread = bool(threaded) 119 request.multiprocess = bool(forked) 120 request.app = app 121 request.prev = prev 122 try: 123 request.run(method, path, qs, reqproto, headers, rfile) 124 break 125 except cherrypy.InternalRedirect: 126 ir = sys.exc_info()[1] 127 app.release_serving() 128 prev = request 129 if not recursive: 130 if ir.path in redirections: 131 raise RuntimeError('InternalRedirector visited the same URL twice: %r' % ir.path) 132 else: 133 if qs: 134 qs = '?' + qs 135 redirections.append(sn + path + qs) 136 method = 'GET' 137 path = ir.path 138 qs = ir.query_string 139 rfile = BytesIO() 140 141 send_response(req, response.status, response.header_list, response.body, response.stream) 142 finally: 143 app.release_serving() 144 145 except: 146 tb = format_exc() 147 cherrypy.log(tb, 'MOD_PYTHON', severity=logging.ERROR) 148 s, h, b = bare_error() 149 send_response(req, s, h, b) 150 151 return apache.OK 152 153 154 def send_response(req, status, headers, body, stream = False): 155 req.status = int(status[:3]) 156 req.content_type = 'text/plain' 157 for header, value in headers: 158 if header.lower() == 'content-type': 159 req.content_type = value 160 continue 161 req.headers_out.add(header, value) 162 163 if stream: 164 req.flush() 165 if isinstance(body, basestring): 166 req.write(body) 167 else: 168 for seg in body: 169 req.write(seg) 170 171 172 import os 173 import re 174 175 def read_process(cmd, args = ''): 176 fullcmd = '%s %s' % (cmd, args) 177 pipein, pipeout = os.popen4(fullcmd) 178 try: 179 firstline = pipeout.readline() 180 if re.search(ntob('(not recognized|No such file|not found)'), firstline, re.IGNORECASE): 181 raise IOError('%s must be on your system path.' % cmd) 182 output = firstline + pipeout.read() 183 finally: 184 pipeout.close() 185 186 return output 187 188 189 class ModPythonServer(object): 190 template = '\n# Apache2 server configuration file for running CherryPy with mod_python.\n\nDocumentRoot "/"\nListen %(port)s\nLoadModule python_module modules/mod_python.so\n\n<Location %(loc)s>\n SetHandler python-program\n PythonHandler %(handler)s\n PythonDebug On\n%(opts)s\n</Location>\n' 191 192 def __init__(self, loc = '/', port = 80, opts = None, apache_path = 'apache', handler = 'cherrypy._cpmodpy::handler'): 193 self.loc = loc 194 self.port = port 195 self.opts = opts 196 self.apache_path = apache_path 197 self.handler = handler 198 199 def start(self): 200 opts = ''.join([ ' PythonOption %s %s\n' % (k, v) for k, v in self.opts ]) 201 conf_data = self.template % {'port': self.port, 202 'loc': self.loc, 203 'opts': opts, 204 'handler': self.handler} 205 mpconf = os.path.join(os.path.dirname(__file__), 'cpmodpy.conf') 206 f = open(mpconf, 'wb') 207 try: 208 f.write(conf_data) 209 finally: 210 f.close() 211 212 response = read_process(self.apache_path, '-k start -f %s' % mpconf) 213 self.ready = True 214 return response 215 216 def stop(self): 217 os.popen('apache -k stop') 218 self.ready = False