NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

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()