_cpwsgi.py (8124B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\_cpwsgi.py 2 import sys as _sys 3 import cherrypy as _cherrypy 4 from cherrypy._cpcompat import BytesIO 5 from cherrypy import _cperror 6 from cherrypy.lib import httputil 7 8 def downgrade_wsgi_ux_to_1x(environ): 9 env1x = {} 10 url_encoding = environ[u'wsgi.url_encoding'] 11 for k, v in environ.items(): 12 if k in (u'PATH_INFO', u'SCRIPT_NAME', u'QUERY_STRING'): 13 v = v.encode(url_encoding) 14 elif isinstance(v, unicode): 15 v = v.encode('ISO-8859-1') 16 env1x[k.encode('ISO-8859-1')] = v 17 18 return env1x 19 20 21 class VirtualHost(object): 22 default = None 23 use_x_forwarded_host = True 24 domains = {} 25 26 def __init__(self, default, domains = None, use_x_forwarded_host = True): 27 self.default = default 28 self.domains = domains or {} 29 self.use_x_forwarded_host = use_x_forwarded_host 30 31 def __call__(self, environ, start_response): 32 domain = environ.get('HTTP_HOST', '') 33 if self.use_x_forwarded_host: 34 domain = environ.get('HTTP_X_FORWARDED_HOST', domain) 35 nextapp = self.domains.get(domain) 36 if nextapp is None: 37 nextapp = self.default 38 return nextapp(environ, start_response) 39 40 41 class InternalRedirector(object): 42 43 def __init__(self, nextapp, recursive = False): 44 self.nextapp = nextapp 45 self.recursive = recursive 46 47 def __call__(self, environ, start_response): 48 redirections = [] 49 while True: 50 environ = environ.copy() 51 try: 52 return self.nextapp(environ, start_response) 53 except _cherrypy.InternalRedirect as ir: 54 sn = environ.get('SCRIPT_NAME', '') 55 path = environ.get('PATH_INFO', '') 56 qs = environ.get('QUERY_STRING', '') 57 old_uri = sn + path 58 if qs: 59 old_uri += '?' + qs 60 redirections.append(old_uri) 61 if not self.recursive: 62 new_uri = sn + ir.path 63 if ir.query_string: 64 new_uri += '?' + ir.query_string 65 if new_uri in redirections: 66 ir.request.close() 67 raise RuntimeError('InternalRedirector visited the same URL twice: %r' % new_uri) 68 environ['REQUEST_METHOD'] = 'GET' 69 environ['PATH_INFO'] = ir.path 70 environ['QUERY_STRING'] = ir.query_string 71 environ['wsgi.input'] = BytesIO() 72 environ['CONTENT_LENGTH'] = '0' 73 environ['cherrypy.previous_request'] = ir.request 74 75 76 class ExceptionTrapper(object): 77 78 def __init__(self, nextapp, throws = (KeyboardInterrupt, SystemExit)): 79 self.nextapp = nextapp 80 self.throws = throws 81 82 def __call__(self, environ, start_response): 83 return _TrappedResponse(self.nextapp, environ, start_response, self.throws) 84 85 86 class _TrappedResponse(object): 87 response = iter([]) 88 89 def __init__(self, nextapp, environ, start_response, throws): 90 self.nextapp = nextapp 91 self.environ = environ 92 self.start_response = start_response 93 self.throws = throws 94 self.started_response = False 95 self.response = self.trap(self.nextapp, self.environ, self.start_response) 96 self.iter_response = iter(self.response) 97 98 def __iter__(self): 99 self.started_response = True 100 return self 101 102 def next(self): 103 return self.trap(self.iter_response.next) 104 105 def close(self): 106 if hasattr(self.response, 'close'): 107 self.response.close() 108 109 def trap(self, func, *args, **kwargs): 110 try: 111 return func(*args, **kwargs) 112 except self.throws: 113 raise 114 except StopIteration: 115 raise 116 except: 117 tb = _cperror.format_exc() 118 _cherrypy.log(tb, severity=40) 119 if not _cherrypy.request.show_tracebacks: 120 tb = '' 121 s, h, b = _cperror.bare_error(tb) 122 if self.started_response: 123 self.iter_response = iter([]) 124 else: 125 self.iter_response = iter(b) 126 try: 127 self.start_response(s, h, _sys.exc_info()) 128 except: 129 _cherrypy.log(traceback=True, severity=40) 130 raise 131 132 if self.started_response: 133 return ''.join(b) 134 else: 135 return b 136 137 138 class AppResponse(object): 139 140 def __init__(self, environ, start_response, cpapp): 141 if environ.get(u'wsgi.version') == (u'u', 0): 142 environ = downgrade_wsgi_ux_to_1x(environ) 143 self.environ = environ 144 self.cpapp = cpapp 145 try: 146 self.run() 147 except: 148 self.close() 149 raise 150 151 r = _cherrypy.serving.response 152 self.iter_response = iter(r.body) 153 self.write = start_response(r.output_status, r.header_list) 154 155 def __iter__(self): 156 return self 157 158 def next(self): 159 return self.iter_response.next() 160 161 def close(self): 162 self.cpapp.release_serving() 163 164 def run(self): 165 env = self.environ.get 166 local = httputil.Host('', int(env('SERVER_PORT', 80)), env('SERVER_NAME', '')) 167 remote = httputil.Host(env('REMOTE_ADDR', ''), int(env('REMOTE_PORT', -1) or -1), env('REMOTE_HOST', '')) 168 scheme = env('wsgi.url_scheme') 169 sproto = env('ACTUAL_SERVER_PROTOCOL', 'HTTP/1.1') 170 request, resp = self.cpapp.get_serving(local, remote, scheme, sproto) 171 request.login = env('LOGON_USER') or env('REMOTE_USER') or None 172 request.multithread = self.environ['wsgi.multithread'] 173 request.multiprocess = self.environ['wsgi.multiprocess'] 174 request.wsgi_environ = self.environ 175 request.prev = env('cherrypy.previous_request', None) 176 meth = self.environ['REQUEST_METHOD'] 177 path = httputil.urljoin(self.environ.get('SCRIPT_NAME', ''), self.environ.get('PATH_INFO', '')) 178 qs = self.environ.get('QUERY_STRING', '') 179 rproto = self.environ.get('SERVER_PROTOCOL') 180 headers = self.translate_headers(self.environ) 181 rfile = self.environ['wsgi.input'] 182 request.run(meth, path, qs, rproto, headers, rfile) 183 184 headerNames = {'HTTP_CGI_AUTHORIZATION': 'Authorization', 185 'CONTENT_LENGTH': 'Content-Length', 186 'CONTENT_TYPE': 'Content-Type', 187 'REMOTE_HOST': 'Remote-Host', 188 'REMOTE_ADDR': 'Remote-Addr'} 189 190 def translate_headers(self, environ): 191 for cgiName in environ: 192 if cgiName in self.headerNames: 193 yield (self.headerNames[cgiName], environ[cgiName]) 194 elif cgiName[:5] == 'HTTP_': 195 translatedHeader = cgiName[5:].replace('_', '-') 196 yield (translatedHeader, environ[cgiName]) 197 198 199 class CPWSGIApp(object): 200 pipeline = [('ExceptionTrapper', ExceptionTrapper), ('InternalRedirector', InternalRedirector)] 201 head = None 202 config = {} 203 response_class = AppResponse 204 205 def __init__(self, cpapp, pipeline = None): 206 self.cpapp = cpapp 207 self.pipeline = self.pipeline[:] 208 if pipeline: 209 self.pipeline.extend(pipeline) 210 self.config = self.config.copy() 211 212 def tail(self, environ, start_response): 213 return self.response_class(environ, start_response, self.cpapp) 214 215 def __call__(self, environ, start_response): 216 head = self.head 217 if head is None: 218 head = self.tail 219 for name, callable in self.pipeline[::-1]: 220 conf = self.config.get(name, {}) 221 head = callable(head, **conf) 222 223 self.head = head 224 return head(environ, start_response) 225 226 def namespace_handler(self, k, v): 227 if k == 'pipeline': 228 self.pipeline.extend(v) 229 elif k == 'response_class': 230 self.response_class = v 231 else: 232 name, arg = k.split('.', 1) 233 bucket = self.config.setdefault(name, {}) 234 bucket[arg] = v