serving.py (13662B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\werkzeug\serving.py 2 import os 3 import socket 4 import sys 5 import time 6 import thread 7 import subprocess 8 from urllib import unquote 9 from itertools import chain 10 from SocketServer import ThreadingMixIn, ForkingMixIn 11 from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler 12 import werkzeug 13 from werkzeug._internal import _log 14 from werkzeug.exceptions import InternalServerError 15 16 class WSGIRequestHandler(BaseHTTPRequestHandler, object): 17 18 @property 19 def server_version(self): 20 return 'Werkzeug/' + werkzeug.__version__ 21 22 def make_environ(self): 23 if '?' in self.path: 24 path_info, query = self.path.split('?', 1) 25 else: 26 path_info = self.path 27 query = '' 28 url_scheme = self.server.ssl_context is None and 'http' or 'https' 29 environ = {'wsgi.version': (1, 0), 30 'wsgi.url_scheme': url_scheme, 31 'wsgi.input': self.rfile, 32 'wsgi.errors': sys.stderr, 33 'wsgi.multithread': self.server.multithread, 34 'wsgi.multiprocess': self.server.multiprocess, 35 'wsgi.run_once': False, 36 'SERVER_SOFTWARE': self.server_version, 37 'REQUEST_METHOD': self.command, 38 'SCRIPT_NAME': '', 39 'PATH_INFO': unquote(path_info), 40 'QUERY_STRING': query, 41 'CONTENT_TYPE': self.headers.get('Content-Type', ''), 42 'CONTENT_LENGTH': self.headers.get('Content-Length', ''), 43 'REMOTE_ADDR': self.client_address[0], 44 'REMOTE_PORT': self.client_address[1], 45 'SERVER_NAME': self.server.server_address[0], 46 'SERVER_PORT': str(self.server.server_address[1]), 47 'SERVER_PROTOCOL': self.request_version} 48 for key, value in self.headers.items(): 49 key = 'HTTP_' + key.upper().replace('-', '_') 50 if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): 51 environ[key] = value 52 53 return environ 54 55 def run_wsgi(self): 56 app = self.server.app 57 environ = self.make_environ() 58 headers_set = [] 59 headers_sent = [] 60 61 def write(data): 62 if not headers_sent: 63 status, response_headers = headers_sent[:] = headers_set 64 code, msg = status.split(None, 1) 65 self.send_response(int(code), msg) 66 header_keys = set() 67 for key, value in response_headers: 68 self.send_header(key, value) 69 key = key.lower() 70 header_keys.add(key) 71 72 if 'content-length' not in header_keys: 73 self.close_connection = True 74 self.send_header('Connection', 'close') 75 if 'server' not in header_keys: 76 self.send_header('Server', self.version_string()) 77 if 'date' not in header_keys: 78 self.send_header('Date', self.date_time_string()) 79 self.end_headers() 80 self.wfile.write(data) 81 self.wfile.flush() 82 83 def start_response(status, response_headers, exc_info = None): 84 if exc_info: 85 try: 86 if headers_sent: 87 raise exc_info[0], exc_info[1], exc_info[2] 88 finally: 89 exc_info = None 90 91 elif headers_set: 92 raise AssertionError('Headers already set') 93 headers_set[:] = [status, response_headers] 94 return write 95 96 def execute(app): 97 application_iter = app(environ, start_response) 98 try: 99 for data in application_iter: 100 write(data) 101 102 if not headers_sent: 103 write('') 104 finally: 105 if hasattr(application_iter, 'close'): 106 application_iter.close() 107 application_iter = None 108 109 try: 110 execute(app) 111 except (socket.error, socket.timeout) as e: 112 self.connection_dropped(e, environ) 113 except: 114 if self.server.passthrough_errors: 115 raise 116 from werkzeug.debug.tbtools import get_current_traceback 117 traceback = get_current_traceback(ignore_system_exceptions=True) 118 try: 119 if not headers_sent: 120 del headers_set[:] 121 execute(InternalServerError()) 122 except: 123 pass 124 125 self.server.log('error', 'Error on request:\n%s', traceback.plaintext) 126 127 def handle(self): 128 try: 129 return BaseHTTPRequestHandler.handle(self) 130 except (socket.error, socket.timeout) as e: 131 self.connection_dropped(e) 132 except: 133 if self.server.ssl_context is None or not is_ssl_error(): 134 raise 135 136 def connection_dropped(self, error, environ = None): 137 pass 138 139 def handle_one_request(self): 140 self.raw_requestline = self.rfile.readline() 141 if not self.raw_requestline: 142 self.close_connection = 1 143 elif self.parse_request(): 144 return self.run_wsgi() 145 146 def send_response(self, code, message = None): 147 self.log_request(code) 148 if message is None: 149 message = code in self.responses and self.responses[code][0] or '' 150 if self.request_version != 'HTTP/0.9': 151 self.wfile.write('%s %d %s\r\n' % (self.protocol_version, code, message)) 152 153 def version_string(self): 154 return BaseHTTPRequestHandler.version_string(self).strip() 155 156 def address_string(self): 157 return self.client_address[0] 158 159 def log_request(self, code = '-', size = '-'): 160 self.log('info', '"%s" %s %s', self.requestline, code, size) 161 162 def log_error(self, *args): 163 self.log('error', *args) 164 165 def log_message(self, format, *args): 166 self.log('info', format, *args) 167 168 def log(self, type, message, *args): 169 _log(type, '%s - - [%s] %s\n' % (self.address_string(), self.log_date_time_string(), message % args)) 170 171 172 BaseRequestHandler = WSGIRequestHandler 173 174 def generate_adhoc_ssl_context(): 175 from random import random 176 from OpenSSL import crypto, SSL 177 cert = crypto.X509() 178 cert.set_serial_number(int(random() * sys.maxint)) 179 cert.gmtime_adj_notBefore(0) 180 cert.gmtime_adj_notAfter(31536000) 181 subject = cert.get_subject() 182 subject.CN = '*' 183 subject.O = 'Dummy Certificate' 184 issuer = cert.get_issuer() 185 issuer.CN = 'Untrusted Authority' 186 issuer.O = 'Self-Signed' 187 pkey = crypto.PKey() 188 pkey.generate_key(crypto.TYPE_RSA, 768) 189 cert.set_pubkey(pkey) 190 cert.sign(pkey, 'md5') 191 ctx = SSL.Context(SSL.SSLv23_METHOD) 192 ctx.use_privatekey(pkey) 193 ctx.use_certificate(cert) 194 return ctx 195 196 197 def is_ssl_error(error = None): 198 if error is None: 199 error = sys.exc_info()[1] 200 from OpenSSL import SSL 201 return isinstance(error, SSL.Error) 202 203 204 class _SSLConnectionFix(object): 205 206 def __init__(self, con): 207 self._con = con 208 209 def makefile(self, mode, bufsize): 210 return socket._fileobject(self._con, mode, bufsize) 211 212 def __getattr__(self, attrib): 213 return getattr(self._con, attrib) 214 215 216 def select_ip_version(host, port): 217 try: 218 info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) 219 if info: 220 return info[0][0] 221 except socket.gaierror: 222 pass 223 224 if ':' in host and hasattr(socket, 'AF_INET6'): 225 return socket.AF_INET6 226 return socket.AF_INET 227 228 229 class BaseWSGIServer(HTTPServer, object): 230 multithread = False 231 multiprocess = False 232 233 def __init__(self, host, port, app, handler = None, passthrough_errors = False, ssl_context = None): 234 if handler is None: 235 handler = WSGIRequestHandler 236 self.address_family = select_ip_version(host, port) 237 HTTPServer.__init__(self, (host, int(port)), handler) 238 self.app = app 239 self.passthrough_errors = passthrough_errors 240 if ssl_context is not None: 241 try: 242 from OpenSSL import tsafe 243 except ImportError: 244 raise TypeError('SSL is not available if the OpenSSL library is not installed.') 245 246 if ssl_context == 'adhoc': 247 ssl_context = generate_adhoc_ssl_context() 248 self.socket = tsafe.Connection(ssl_context, self.socket) 249 self.ssl_context = ssl_context 250 else: 251 self.ssl_context = None 252 253 def log(self, type, message, *args): 254 _log(type, message, *args) 255 256 def serve_forever(self): 257 try: 258 HTTPServer.serve_forever(self) 259 except KeyboardInterrupt: 260 pass 261 262 def handle_error(self, request, client_address): 263 if self.passthrough_errors: 264 raise 265 else: 266 return HTTPServer.handle_error(self, request, client_address) 267 268 def get_request(self): 269 con, info = self.socket.accept() 270 if self.ssl_context is not None: 271 con = _SSLConnectionFix(con) 272 return (con, info) 273 274 275 class ThreadedWSGIServer(ThreadingMixIn, BaseWSGIServer): 276 multithread = True 277 278 279 class ForkingWSGIServer(ForkingMixIn, BaseWSGIServer): 280 multiprocess = True 281 282 def __init__(self, host, port, app, processes = 40, handler = None, passthrough_errors = False, ssl_context = None): 283 BaseWSGIServer.__init__(self, host, port, app, handler, passthrough_errors, ssl_context) 284 self.max_children = processes 285 286 287 def make_server(host, port, app = None, threaded = False, processes = 1, request_handler = None, passthrough_errors = False, ssl_context = None): 288 if threaded and processes > 1: 289 raise ValueError('cannot have a multithreaded and multi process server.') 290 else: 291 if threaded: 292 return ThreadedWSGIServer(host, port, app, request_handler, passthrough_errors, ssl_context) 293 if processes > 1: 294 return ForkingWSGIServer(host, port, app, processes, request_handler, passthrough_errors, ssl_context) 295 return BaseWSGIServer(host, port, app, request_handler, passthrough_errors, ssl_context) 296 297 298 def reloader_loop(extra_files = None, interval = 1): 299 300 def iter_module_files(): 301 for module in sys.modules.values(): 302 filename = getattr(module, '__file__', None) 303 if filename: 304 old = None 305 while not os.path.isfile(filename): 306 old = filename 307 filename = os.path.dirname(filename) 308 if filename == old: 309 break 310 else: 311 if filename[-4:] in ('.pyc', '.pyo'): 312 filename = filename[:-1] 313 yield filename 314 315 mtimes = {} 316 while 1: 317 for filename in chain(iter_module_files(), extra_files or ()): 318 try: 319 mtime = os.stat(filename).st_mtime 320 except OSError: 321 continue 322 323 old_time = mtimes.get(filename) 324 if old_time is None: 325 mtimes[filename] = mtime 326 continue 327 elif mtime > old_time: 328 _log('info', ' * Detected change in %r, reloading' % filename) 329 sys.exit(3) 330 331 time.sleep(interval) 332 333 334 def restart_with_reloader(): 335 while 1: 336 _log('info', ' * Restarting with reloader...') 337 args = [sys.executable] + sys.argv 338 new_environ = os.environ.copy() 339 new_environ['WERKZEUG_RUN_MAIN'] = 'true' 340 if os.name == 'nt': 341 for key, value in new_environ.iteritems(): 342 if isinstance(value, unicode): 343 new_environ[key] = value.encode('iso-8859-1') 344 345 exit_code = subprocess.call(args, env=new_environ) 346 if exit_code != 3: 347 return exit_code 348 349 350 def run_with_reloader(main_func, extra_files = None, interval = 1): 351 if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': 352 thread.start_new_thread(main_func, ()) 353 try: 354 reloader_loop(extra_files, interval) 355 except KeyboardInterrupt: 356 return 357 358 try: 359 sys.exit(restart_with_reloader()) 360 except KeyboardInterrupt: 361 pass 362 363 364 def run_simple(hostname, port, application, use_reloader = False, use_debugger = False, use_evalex = True, extra_files = None, reloader_interval = 1, threaded = False, processes = 1, request_handler = None, static_files = None, passthrough_errors = False, ssl_context = None): 365 if use_debugger: 366 from werkzeug.debug import DebuggedApplication 367 application = DebuggedApplication(application, use_evalex) 368 if static_files: 369 from werkzeug.wsgi import SharedDataMiddleware 370 application = SharedDataMiddleware(application, static_files) 371 372 def inner(): 373 make_server(hostname, port, application, threaded, processes, request_handler, passthrough_errors, ssl_context).serve_forever() 374 375 if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': 376 display_hostname = hostname != '*' and hostname or 'localhost' 377 if ':' in display_hostname: 378 display_hostname = '[%s]' % display_hostname 379 _log('info', ' * Running on %s://%s:%d/', ssl_context is None and 'http' or 'https', display_hostname, port) 380 if use_reloader: 381 test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 382 test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 383 test_socket.bind((hostname, port)) 384 test_socket.close() 385 run_with_reloader(inner, extra_files, reloader_interval) 386 else: 387 inner()