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

SimpleXMLRPCServer.py (12356B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\SimpleXMLRPCServer.py
      2 import xmlrpclib
      3 from xmlrpclib import Fault
      4 import SocketServer
      5 import BaseHTTPServer
      6 import sys
      7 import os
      8 import traceback
      9 import re
     10 try:
     11     import fcntl
     12 except ImportError:
     13     fcntl = None
     14 
     15 def resolve_dotted_attribute(obj, attr, allow_dotted_names = True):
     16     if allow_dotted_names:
     17         attrs = attr.split('.')
     18     else:
     19         attrs = [attr]
     20     for i in attrs:
     21         if i.startswith('_'):
     22             raise AttributeError('attempt to access private attribute "%s"' % i)
     23         else:
     24             obj = getattr(obj, i)
     25 
     26     return obj
     27 
     28 
     29 def list_public_methods(obj):
     30     return [ member for member in dir(obj) if not member.startswith('_') and hasattr(getattr(obj, member), '__call__') ]
     31 
     32 
     33 def remove_duplicates(lst):
     34     u = {}
     35     for x in lst:
     36         u[x] = 1
     37 
     38     return u.keys()
     39 
     40 
     41 class SimpleXMLRPCDispatcher():
     42 
     43     def __init__(self, allow_none = False, encoding = None):
     44         self.funcs = {}
     45         self.instance = None
     46         self.allow_none = allow_none
     47         self.encoding = encoding
     48 
     49     def register_instance(self, instance, allow_dotted_names = False):
     50         self.instance = instance
     51         self.allow_dotted_names = allow_dotted_names
     52 
     53     def register_function(self, function, name = None):
     54         if name is None:
     55             name = function.__name__
     56         self.funcs[name] = function
     57 
     58     def register_introspection_functions(self):
     59         self.funcs.update({'system.listMethods': self.system_listMethods,
     60          'system.methodSignature': self.system_methodSignature,
     61          'system.methodHelp': self.system_methodHelp})
     62 
     63     def register_multicall_functions(self):
     64         self.funcs.update({'system.multicall': self.system_multicall})
     65 
     66     def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
     67         try:
     68             params, method = xmlrpclib.loads(data)
     69             if dispatch_method is not None:
     70                 response = dispatch_method(method, params)
     71             else:
     72                 response = self._dispatch(method, params)
     73             response = (response,)
     74             response = xmlrpclib.dumps(response, methodresponse=1, allow_none=self.allow_none, encoding=self.encoding)
     75         except Fault as fault:
     76             response = xmlrpclib.dumps(fault, allow_none=self.allow_none, encoding=self.encoding)
     77         except:
     78             exc_type, exc_value = sys.exc_info()[:2]
     79             response = xmlrpclib.dumps(xmlrpclib.Fault(1, '%s:%s' % (exc_type, exc_value)), encoding=self.encoding, allow_none=self.allow_none)
     80 
     81         return response
     82 
     83     def system_listMethods(self):
     84         methods = self.funcs.keys()
     85         if self.instance is not None:
     86             if hasattr(self.instance, '_listMethods'):
     87                 methods = remove_duplicates(methods + self.instance._listMethods())
     88             elif not hasattr(self.instance, '_dispatch'):
     89                 methods = remove_duplicates(methods + list_public_methods(self.instance))
     90         methods.sort()
     91         return methods
     92 
     93     def system_methodSignature(self, method_name):
     94         return 'signatures not supported'
     95 
     96     def system_methodHelp(self, method_name):
     97         method = None
     98         if method_name in self.funcs:
     99             method = self.funcs[method_name]
    100         elif self.instance is not None:
    101             if hasattr(self.instance, '_methodHelp'):
    102                 return self.instance._methodHelp(method_name)
    103             if not hasattr(self.instance, '_dispatch'):
    104                 try:
    105                     method = resolve_dotted_attribute(self.instance, method_name, self.allow_dotted_names)
    106                 except AttributeError:
    107                     pass
    108 
    109         if method is None:
    110             return ''
    111         try:
    112             import pydoc
    113             return pydoc.getdoc(method)
    114         except ImportError:
    115             return method.__doc__
    116 
    117     def system_multicall(self, call_list):
    118         results = []
    119         for call in call_list:
    120             method_name = call['methodName']
    121             params = call['params']
    122             try:
    123                 results.append([self._dispatch(method_name, params)])
    124             except Fault as fault:
    125                 results.append({'faultCode': fault.faultCode,
    126                  'faultString': fault.faultString})
    127             except:
    128                 exc_type, exc_value, exc_tb = sys.exc_info()
    129                 results.append({'faultCode': 1,
    130                  'faultString': '%s:%s' % (exc_type, exc_value)})
    131 
    132         return results
    133 
    134     def _dispatch(self, method, params):
    135         func = None
    136         try:
    137             func = self.funcs[method]
    138         except KeyError:
    139             if self.instance is not None:
    140                 if hasattr(self.instance, '_dispatch'):
    141                     return self.instance._dispatch(method, params)
    142                 try:
    143                     func = resolve_dotted_attribute(self.instance, method, self.allow_dotted_names)
    144                 except AttributeError:
    145                     pass
    146 
    147         if func is not None:
    148             return func(*params)
    149         raise Exception('method "%s" is not supported' % method)
    150 
    151 
    152 class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    153     rpc_paths = ('/', '/RPC2')
    154     encode_threshold = 1400
    155     wbufsize = -1
    156     disable_nagle_algorithm = True
    157     aepattern = re.compile('\n                            \\s* ([^\\s;]+) \\s*            #content-coding\n                            (;\\s* q \\s*=\\s* ([0-9\\.]+))? #q\n                            ', re.VERBOSE | re.IGNORECASE)
    158 
    159     def accept_encodings(self):
    160         r = {}
    161         ae = self.headers.get('Accept-Encoding', '')
    162         for e in ae.split(','):
    163             match = self.aepattern.match(e)
    164             if match:
    165                 v = match.group(3)
    166                 v = float(v) if v else 1.0
    167                 r[match.group(1)] = v
    168 
    169         return r
    170 
    171     def is_rpc_path_valid(self):
    172         if self.rpc_paths:
    173             return self.path in self.rpc_paths
    174         else:
    175             return True
    176 
    177     def do_POST(self):
    178         if not self.is_rpc_path_valid():
    179             self.report_404()
    180             return
    181         try:
    182             max_chunk_size = 10485760
    183             size_remaining = int(self.headers['content-length'])
    184             L = []
    185             while size_remaining:
    186                 chunk_size = min(size_remaining, max_chunk_size)
    187                 L.append(self.rfile.read(chunk_size))
    188                 size_remaining -= len(L[-1])
    189 
    190             data = ''.join(L)
    191             data = self.decode_request_content(data)
    192             if data is None:
    193                 return
    194             response = self.server._marshaled_dispatch(data, getattr(self, '_dispatch', None), self.path)
    195         except Exception as e:
    196             self.send_response(500)
    197             if hasattr(self.server, '_send_traceback_header') and self.server._send_traceback_header:
    198                 self.send_header('X-exception', str(e))
    199                 self.send_header('X-traceback', traceback.format_exc())
    200             self.send_header('Content-length', '0')
    201             self.end_headers()
    202         else:
    203             self.send_response(200)
    204             self.send_header('Content-type', 'text/xml')
    205             if self.encode_threshold is not None:
    206                 if len(response) > self.encode_threshold:
    207                     q = self.accept_encodings().get('gzip', 0)
    208                     if q:
    209                         try:
    210                             response = xmlrpclib.gzip_encode(response)
    211                             self.send_header('Content-Encoding', 'gzip')
    212                         except NotImplementedError:
    213                             pass
    214 
    215             self.send_header('Content-length', str(len(response)))
    216             self.end_headers()
    217             self.wfile.write(response)
    218 
    219     def decode_request_content(self, data):
    220         encoding = self.headers.get('content-encoding', 'identity').lower()
    221         if encoding == 'identity':
    222             return data
    223         if encoding == 'gzip':
    224             try:
    225                 return xmlrpclib.gzip_decode(data)
    226             except NotImplementedError:
    227                 self.send_response(501, 'encoding %r not supported' % encoding)
    228             except ValueError:
    229                 self.send_response(400, 'error decoding gzip content')
    230 
    231         else:
    232             self.send_response(501, 'encoding %r not supported' % encoding)
    233         self.send_header('Content-length', '0')
    234         self.end_headers()
    235 
    236     def report_404(self):
    237         self.send_response(404)
    238         response = 'No such page'
    239         self.send_header('Content-type', 'text/plain')
    240         self.send_header('Content-length', str(len(response)))
    241         self.end_headers()
    242         self.wfile.write(response)
    243 
    244     def log_request(self, code = '-', size = '-'):
    245         if self.server.logRequests:
    246             BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
    247 
    248 
    249 class SimpleXMLRPCServer(SocketServer.TCPServer, SimpleXMLRPCDispatcher):
    250     allow_reuse_address = True
    251     _send_traceback_header = False
    252 
    253     def __init__(self, addr, requestHandler = SimpleXMLRPCRequestHandler, logRequests = True, allow_none = False, encoding = None, bind_and_activate = True):
    254         self.logRequests = logRequests
    255         SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
    256         SocketServer.TCPServer.__init__(self, addr, requestHandler, bind_and_activate)
    257         if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
    258             flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
    259             flags |= fcntl.FD_CLOEXEC
    260             fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
    261 
    262 
    263 class MultiPathXMLRPCServer(SimpleXMLRPCServer):
    264 
    265     def __init__(self, addr, requestHandler = SimpleXMLRPCRequestHandler, logRequests = True, allow_none = False, encoding = None, bind_and_activate = True):
    266         SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests, allow_none, encoding, bind_and_activate)
    267         self.dispatchers = {}
    268         self.allow_none = allow_none
    269         self.encoding = encoding
    270 
    271     def add_dispatcher(self, path, dispatcher):
    272         self.dispatchers[path] = dispatcher
    273         return dispatcher
    274 
    275     def get_dispatcher(self, path):
    276         return self.dispatchers[path]
    277 
    278     def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
    279         try:
    280             response = self.dispatchers[path]._marshaled_dispatch(data, dispatch_method, path)
    281         except:
    282             exc_type, exc_value = sys.exc_info()[:2]
    283             response = xmlrpclib.dumps(xmlrpclib.Fault(1, '%s:%s' % (exc_type, exc_value)), encoding=self.encoding, allow_none=self.allow_none)
    284 
    285         return response
    286 
    287 
    288 class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
    289 
    290     def __init__(self, allow_none = False, encoding = None):
    291         SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
    292 
    293     def handle_xmlrpc(self, request_text):
    294         response = self._marshaled_dispatch(request_text)
    295         print 'Content-Type: text/xml'
    296         print 'Content-Length: %d' % len(response)
    297         print
    298         sys.stdout.write(response)
    299 
    300     def handle_get(self):
    301         code = 400
    302         message, explain = BaseHTTPServer.BaseHTTPRequestHandler.responses[code]
    303         response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % {'code': code,
    304          'message': message,
    305          'explain': explain}
    306         print 'Status: %d %s' % (code, message)
    307         print 'Content-Type: %s' % BaseHTTPServer.DEFAULT_ERROR_CONTENT_TYPE
    308         print 'Content-Length: %d' % len(response)
    309         print
    310         sys.stdout.write(response)
    311 
    312     def handle_request(self, request_text = None):
    313         if request_text is None and os.environ.get('REQUEST_METHOD', None) == 'GET':
    314             self.handle_get()
    315         else:
    316             try:
    317                 length = int(os.environ.get('CONTENT_LENGTH', None))
    318             except (TypeError, ValueError):
    319                 length = -1
    320 
    321             if request_text is None:
    322                 request_text = sys.stdin.read(length)
    323             self.handle_xmlrpc(request_text)
    324 
    325 
    326 if __name__ == '__main__':
    327     print 'Running XML-RPC server on port 8000'
    328     server = SimpleXMLRPCServer(('localhost', 8000))
    329     server.register_function(pow)
    330     server.register_function(lambda x, y: x + y, 'add')
    331     server.serve_forever()