_cprequest.py (15107B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\_cprequest.py 2 import os 3 import sys 4 import time 5 import warnings 6 import cherrypy 7 from cherrypy._cpcompat import basestring, copykeys, ntob, unicodestr 8 from cherrypy._cpcompat import SimpleCookie, CookieError 9 from cherrypy import _cpreqbody, _cpconfig 10 from cherrypy._cperror import format_exc, bare_error 11 from cherrypy.lib import httputil, file_generator 12 13 class Hook(object): 14 callback = None 15 failsafe = False 16 priority = 50 17 kwargs = {} 18 19 def __init__(self, callback, failsafe = None, priority = None, **kwargs): 20 self.callback = callback 21 if failsafe is None: 22 failsafe = getattr(callback, 'failsafe', False) 23 self.failsafe = failsafe 24 if priority is None: 25 priority = getattr(callback, 'priority', 50) 26 self.priority = priority 27 self.kwargs = kwargs 28 29 def __cmp__(self, other): 30 return cmp(self.priority, other.priority) 31 32 def __call__(self): 33 return self.callback(**self.kwargs) 34 35 def __repr__(self): 36 cls = self.__class__ 37 return '%s.%s(callback=%r, failsafe=%r, priority=%r, %s)' % (cls.__module__, 38 cls.__name__, 39 self.callback, 40 self.failsafe, 41 self.priority, 42 ', '.join([ '%s=%r' % (k, v) for k, v in self.kwargs.items() ])) 43 44 45 class HookMap(dict): 46 47 def __new__(cls, points = None): 48 d = dict.__new__(cls) 49 for p in points or []: 50 d[p] = [] 51 52 return d 53 54 def __init__(self, *a, **kw): 55 pass 56 57 def attach(self, point, callback, failsafe = None, priority = None, **kwargs): 58 self[point].append(Hook(callback, failsafe, priority, **kwargs)) 59 60 def run(self, point): 61 exc = None 62 hooks = self[point] 63 hooks.sort() 64 for hook in hooks: 65 if exc is None or hook.failsafe: 66 try: 67 hook() 68 except (KeyboardInterrupt, SystemExit): 69 raise 70 except (cherrypy.HTTPError, cherrypy.HTTPRedirect, cherrypy.InternalRedirect): 71 exc = sys.exc_info()[1] 72 except: 73 exc = sys.exc_info()[1] 74 cherrypy.log(traceback=True, severity=40) 75 76 if exc: 77 raise 78 79 def __copy__(self): 80 newmap = self.__class__() 81 for k, v in self.items(): 82 newmap[k] = v[:] 83 84 return newmap 85 86 copy = __copy__ 87 88 def __repr__(self): 89 cls = self.__class__ 90 return '%s.%s(points=%r)' % (cls.__module__, cls.__name__, copykeys(self)) 91 92 93 def hooks_namespace(k, v): 94 hookpoint = k.split('.', 1)[0] 95 if isinstance(v, basestring): 96 v = cherrypy.lib.attributes(v) 97 if not isinstance(v, Hook): 98 v = Hook(v) 99 cherrypy.serving.request.hooks[hookpoint].append(v) 100 101 102 def request_namespace(k, v): 103 if k[:5] == 'body.': 104 setattr(cherrypy.serving.request.body, k[5:], v) 105 else: 106 setattr(cherrypy.serving.request, k, v) 107 108 109 def response_namespace(k, v): 110 if k[:8] == 'headers.': 111 cherrypy.serving.response.headers[k.split('.', 1)[1]] = v 112 else: 113 setattr(cherrypy.serving.response, k, v) 114 115 116 def error_page_namespace(k, v): 117 if k != 'default': 118 k = int(k) 119 cherrypy.serving.request.error_page[k] = v 120 121 122 hookpoints = ['on_start_resource', 123 'before_request_body', 124 'before_handler', 125 'before_finalize', 126 'on_end_resource', 127 'on_end_request', 128 'before_error_response', 129 'after_error_response'] 130 131 class Request(object): 132 prev = None 133 local = httputil.Host('127.0.0.1', 80) 134 remote = httputil.Host('127.0.0.1', 1111) 135 scheme = 'http' 136 server_protocol = 'HTTP/1.1' 137 base = '' 138 request_line = '' 139 method = 'GET' 140 query_string = '' 141 query_string_encoding = 'utf8' 142 protocol = (1, 1) 143 params = {} 144 header_list = [] 145 headers = httputil.HeaderMap() 146 cookie = SimpleCookie() 147 rfile = None 148 process_request_body = True 149 methods_with_bodies = ('POST', 'PUT') 150 body = None 151 dispatch = cherrypy.dispatch.Dispatcher() 152 script_name = '' 153 path_info = '/' 154 login = None 155 app = None 156 handler = None 157 toolmaps = {} 158 config = None 159 is_index = None 160 hooks = HookMap(hookpoints) 161 error_response = cherrypy.HTTPError(500).set_response 162 error_page = {} 163 show_tracebacks = True 164 show_mismatched_params = True 165 throws = (KeyboardInterrupt, SystemExit, cherrypy.InternalRedirect) 166 throw_errors = False 167 closed = False 168 stage = None 169 namespaces = _cpconfig.NamespaceSet(**{'hooks': hooks_namespace, 170 'request': request_namespace, 171 'response': response_namespace, 172 'error_page': error_page_namespace, 173 'tools': cherrypy.tools}) 174 175 def __init__(self, local_host, remote_host, scheme = 'http', server_protocol = 'HTTP/1.1'): 176 self.local = local_host 177 self.remote = remote_host 178 self.scheme = scheme 179 self.server_protocol = server_protocol 180 self.closed = False 181 self.error_page = self.error_page.copy() 182 self.namespaces = self.namespaces.copy() 183 self.stage = None 184 185 def close(self): 186 if not self.closed: 187 self.closed = True 188 self.stage = 'on_end_request' 189 self.hooks.run('on_end_request') 190 self.stage = 'close' 191 192 def run(self, method, path, query_string, req_protocol, headers, rfile): 193 response = cherrypy.serving.response 194 self.stage = 'run' 195 try: 196 self.error_response = cherrypy.HTTPError(500).set_response 197 self.method = method 198 path = path or '/' 199 self.query_string = query_string or '' 200 self.params = {} 201 rp = (int(req_protocol[5]), int(req_protocol[7])) 202 sp = (int(self.server_protocol[5]), int(self.server_protocol[7])) 203 self.protocol = min(rp, sp) 204 response.headers.protocol = self.protocol 205 url = path 206 if query_string: 207 url += '?' + query_string 208 self.request_line = '%s %s %s' % (method, url, req_protocol) 209 self.header_list = list(headers) 210 self.headers = httputil.HeaderMap() 211 self.rfile = rfile 212 self.body = None 213 self.cookie = SimpleCookie() 214 self.handler = None 215 self.script_name = self.app.script_name 216 self.path_info = pi = path[len(self.script_name):] 217 self.stage = 'respond' 218 self.respond(pi) 219 except self.throws: 220 raise 221 except: 222 if self.throw_errors: 223 raise 224 else: 225 cherrypy.log(traceback=True, severity=40) 226 if self.show_tracebacks: 227 body = format_exc() 228 else: 229 body = '' 230 r = bare_error(body) 231 response.output_status, response.header_list, response.body = r 232 233 if self.method == 'HEAD': 234 response.body = [] 235 try: 236 cherrypy.log.access() 237 except: 238 cherrypy.log.error(traceback=True) 239 240 if response.timed_out: 241 raise cherrypy.TimeoutError() 242 return response 243 244 def respond(self, path_info): 245 response = cherrypy.serving.response 246 try: 247 try: 248 if self.app is None: 249 raise cherrypy.NotFound() 250 self.stage = 'process_headers' 251 self.process_headers() 252 self.hooks = self.__class__.hooks.copy() 253 self.toolmaps = {} 254 self.stage = 'get_resource' 255 self.get_resource(path_info) 256 self.body = _cpreqbody.RequestBody(self.rfile, self.headers, request_params=self.params) 257 self.namespaces(self.config) 258 self.stage = 'on_start_resource' 259 self.hooks.run('on_start_resource') 260 self.stage = 'process_query_string' 261 self.process_query_string() 262 if self.process_request_body: 263 if self.method not in self.methods_with_bodies: 264 self.process_request_body = False 265 self.stage = 'before_request_body' 266 self.hooks.run('before_request_body') 267 if self.process_request_body: 268 self.body.process() 269 self.stage = 'before_handler' 270 self.hooks.run('before_handler') 271 if self.handler: 272 self.stage = 'handler' 273 response.body = self.handler() 274 self.stage = 'before_finalize' 275 self.hooks.run('before_finalize') 276 response.finalize() 277 except (cherrypy.HTTPRedirect, cherrypy.HTTPError): 278 inst = sys.exc_info()[1] 279 inst.set_response() 280 self.stage = 'before_finalize (HTTPError)' 281 self.hooks.run('before_finalize') 282 response.finalize() 283 finally: 284 self.stage = 'on_end_resource' 285 self.hooks.run('on_end_resource') 286 287 except self.throws: 288 raise 289 except: 290 if self.throw_errors: 291 raise 292 self.handle_error() 293 294 def process_query_string(self): 295 try: 296 p = httputil.parse_query_string(self.query_string, encoding=self.query_string_encoding) 297 except UnicodeDecodeError: 298 raise cherrypy.HTTPError(404, 'The given query string could not be processed. Query strings for this resource must be encoded with %r.' % self.query_string_encoding) 299 300 for key, value in p.items(): 301 if isinstance(key, unicode): 302 del p[key] 303 p[key.encode(self.query_string_encoding)] = value 304 305 self.params.update(p) 306 307 def process_headers(self): 308 headers = self.headers 309 for name, value in self.header_list: 310 name = name.title() 311 value = value.strip() 312 if '=?' in value: 313 dict.__setitem__(headers, name, httputil.decode_TEXT(value)) 314 else: 315 dict.__setitem__(headers, name, value) 316 if name == 'Cookie': 317 try: 318 self.cookie.load(value) 319 except CookieError: 320 msg = 'Illegal cookie name %s' % value.split('=')[0] 321 raise cherrypy.HTTPError(400, msg) 322 323 if not dict.__contains__(headers, 'Host'): 324 if self.protocol >= (1, 1): 325 msg = "HTTP/1.1 requires a 'Host' request header." 326 raise cherrypy.HTTPError(400, msg) 327 host = dict.get(headers, 'Host') 328 if not host: 329 host = self.local.name or self.local.ip 330 self.base = '%s://%s' % (self.scheme, host) 331 332 def get_resource(self, path): 333 dispatch = self.app.find_config(path, 'request.dispatch', self.dispatch) 334 dispatch(path) 335 336 def handle_error(self): 337 try: 338 self.hooks.run('before_error_response') 339 if self.error_response: 340 self.error_response() 341 self.hooks.run('after_error_response') 342 cherrypy.serving.response.finalize() 343 except cherrypy.HTTPRedirect: 344 inst = sys.exc_info()[1] 345 inst.set_response() 346 cherrypy.serving.response.finalize() 347 348 def _get_body_params(self): 349 warnings.warn('body_params is deprecated in CherryPy 3.2, will be removed in CherryPy 3.3.', DeprecationWarning) 350 return self.body.params 351 352 body_params = property(_get_body_params, doc='\n If the request Content-Type is \'application/x-www-form-urlencoded\' or\n multipart, this will be a dict of the params pulled from the entity\n body; that is, it will be the portion of request.params that come\n from the message body (sometimes called "POST params", although they\n can be sent with various HTTP method verbs). This value is set between\n the \'before_request_body\' and \'before_handler\' hooks (assuming that\n process_request_body is True).\n \n Deprecated in 3.2, will be removed for 3.3 in favor of\n :attr:`request.body.params<cherrypy._cprequest.RequestBody.params>`.') 353 354 355 class ResponseBody(object): 356 357 def __get__(self, obj, objclass = None): 358 if obj is None: 359 return self 360 else: 361 return obj._body 362 363 def __set__(self, obj, value): 364 if isinstance(value, basestring): 365 if value: 366 value = [value] 367 else: 368 value = [] 369 elif hasattr(value, 'read'): 370 value = file_generator(value) 371 elif value is None: 372 value = [] 373 obj._body = value 374 375 376 class Response(object): 377 status = '' 378 header_list = [] 379 headers = httputil.HeaderMap() 380 cookie = SimpleCookie() 381 body = ResponseBody() 382 time = None 383 timeout = 300 384 timed_out = False 385 stream = False 386 387 def __init__(self): 388 self.status = None 389 self.header_list = None 390 self._body = [] 391 self.time = time.time() 392 self.headers = httputil.HeaderMap() 393 dict.update(self.headers, {'Content-Type': 'text/html', 394 'Server': 'CherryPy/' + cherrypy.__version__, 395 'Date': httputil.HTTPDate(self.time)}) 396 self.cookie = SimpleCookie() 397 398 def collapse_body(self): 399 if isinstance(self.body, basestring): 400 return self.body 401 newbody = ''.join([ chunk for chunk in self.body ]) 402 self.body = newbody 403 return newbody 404 405 def finalize(self): 406 try: 407 code, reason, _ = httputil.valid_status(self.status) 408 except ValueError: 409 raise cherrypy.HTTPError(500, sys.exc_info()[1].args[0]) 410 411 headers = self.headers 412 self.output_status = ntob(str(code), 'ascii') + ntob(' ') + headers.encode(reason) 413 if self.stream: 414 if dict.get(headers, 'Content-Length') is None: 415 dict.pop(headers, 'Content-Length', None) 416 elif code < 200 or code in (204, 205, 304): 417 dict.pop(headers, 'Content-Length', None) 418 self.body = ntob('') 419 elif dict.get(headers, 'Content-Length') is None: 420 content = self.collapse_body() 421 dict.__setitem__(headers, 'Content-Length', len(content)) 422 self.header_list = h = headers.output() 423 cookie = self.cookie.output() 424 if cookie: 425 for line in cookie.split('\n'): 426 if line.endswith('\r'): 427 line = line[:-1] 428 name, value = line.split(': ', 1) 429 if isinstance(name, unicodestr): 430 name = name.encode('ISO-8859-1') 431 if isinstance(value, unicodestr): 432 value = headers.encode(value) 433 h.append((name, value)) 434 435 def check_timeout(self): 436 if time.time() > self.time + self.timeout: 437 self.timed_out = True