r"""XML-RPC Servers.This module can be used to create simple XML-RPC serversby creating a server and either installing functions, aclass instance, or by extending the SimpleXMLRPCServerclass.It can also be used to handle XML-RPC requests in a CGIenvironment using CGIXMLRPCRequestHandler.The Doc* classes can be used to create XML-RPC servers thatserve pydoc-style documentation in response to HTTPGET requests. This documentation is dynamically generatedbased on the functions and methods registered with theserver.A list of possible usage patterns follows:1. Install functions:server = SimpleXMLRPCServer(("localhost", 8000))server.register_function(pow)server.register_function(lambda x,y: x+y, 'add')server.serve_forever()2. Install an instance:class MyFuncs:def __init__(self):# make all of the sys functions available through sys.func_nameimport sysself.sys = sysdef _listMethods(self):# implement this method so that system.listMethods# knows to advertise the sys methodsreturn list_public_methods(self) + \['sys.' + method for method in list_public_methods(self.sys)]def pow(self, x, y): return pow(x, y)def add(self, x, y) : return x + yserver = SimpleXMLRPCServer(("localhost", 8000))server.register_introspection_functions()server.register_instance(MyFuncs())server.serve_forever()3. Install an instance with custom dispatch method:class Math:def _listMethods(self):# this method must be present for system.listMethods# to workreturn ['add', 'pow']def _methodHelp(self, method):# this method must be present for system.methodHelp# to workif method == 'add':return "add(2,3) => 5"elif method == 'pow':return "pow(x, y[, z]) => number"else:# By convention, return empty# string if no help is availablereturn ""def _dispatch(self, method, params):if method == 'pow':return pow(*params)elif method == 'add':return params[0] + params[1]else:raise ValueError('bad method')server = SimpleXMLRPCServer(("localhost", 8000))server.register_introspection_functions()server.register_instance(Math())server.serve_forever()4. Subclass SimpleXMLRPCServer:class MathServer(SimpleXMLRPCServer):def _dispatch(self, method, params):try:# We are forcing the 'export_' prefix on methods that are# callable through XML-RPC to prevent potential security# problemsfunc = getattr(self, 'export_' + method)except AttributeError:raise Exception('method "%s" is not supported' % method)else:return func(*params)def export_add(self, x, y):return x + yserver = MathServer(("localhost", 8000))server.serve_forever()5. CGI script:server = CGIXMLRPCRequestHandler()server.register_function(pow)server.handle_request()"""# Written by Brian Quinlan (brian@sweetapp.com).# Based on code written by Fredrik Lundh.from xmlrpc.client import Fault, dumps, loads, gzip_encode, gzip_decodefrom http.server import BaseHTTPRequestHandlerfrom functools import partialfrom inspect import signatureimport htmlimport http.serverimport socketserverimport sysimport osimport reimport pydocimport tracebacktry:import fcntlexcept ImportError:fcntl = Nonedef resolve_dotted_attribute(obj, attr, allow_dotted_names=True):"""resolve_dotted_attribute(a, 'b.c.d') => a.b.c.dResolves a dotted attribute name to an object. Raisesan AttributeError if any attribute in the chain starts with a '_'.If the optional allow_dotted_names argument is false, dots are notsupported and this function operates similar to getattr(obj, attr)."""if allow_dotted_names:attrs = attr.split('.')else:attrs = [attr]for i in attrs:if i.startswith('_'):raise AttributeError('attempt to access private attribute "%s"' % i)else:obj = getattr(obj,i)return objdef list_public_methods(obj):"""Returns a list of attribute strings, found in the specifiedobject, which represent callable attributes"""return [member for member in dir(obj)if not member.startswith('_') andcallable(getattr(obj, member))]class SimpleXMLRPCDispatcher:"""Mix-in class that dispatches XML-RPC requests.This class is used to register XML-RPC method handlersand then to dispatch them. This class doesn't need to beinstanced directly when used by SimpleXMLRPCServer but itcan be instanced when used by the MultiPathXMLRPCServer"""def __init__(self, allow_none=False, encoding=None,use_builtin_types=False):self.funcs = {}self.instance = Noneself.allow_none = allow_noneself.encoding = encoding or 'utf-8'self.use_builtin_types = use_builtin_typesdef register_instance(self, instance, allow_dotted_names=False):"""Registers an instance to respond to XML-RPC requests.Only one instance can be installed at a time.If the registered instance has a _dispatch method then thatmethod will be called with the name of the XML-RPC method andits parameters as a tuplee.g. instance._dispatch('add',(2,3))If the registered instance does not have a _dispatch methodthen the instance will be searched to find a matching methodand, if found, will be called. Methods beginning with an '_'are considered private and will not be called bySimpleXMLRPCServer.If a registered function matches an XML-RPC request, then itwill be called instead of the registered instance.If the optional allow_dotted_names argument is true and theinstance does not have a _dispatch method, method namescontaining dots are supported and resolved, as long as none ofthe name segments start with an '_'.*** SECURITY WARNING: ***Enabling the allow_dotted_names options allows intrudersto access your module's global variables and may allowintruders to execute arbitrary code on your machine. Onlyuse this option on a secure, closed network."""self.instance = instanceself.allow_dotted_names = allow_dotted_namesdef register_function(self, function=None, name=None):"""Registers a function to respond to XML-RPC requests.The optional name argument can be used to set a Unicode namefor the function."""# decorator factoryif function is None:return partial(self.register_function, name=name)if name is None:name = function.__name__self.funcs[name] = functionreturn functiondef register_introspection_functions(self):"""Registers the XML-RPC introspection methods in the systemnamespace.see http://xmlrpc.usefulinc.com/doc/reserved.html"""self.funcs.update({'system.listMethods' : self.system_listMethods,'system.methodSignature' : self.system_methodSignature,'system.methodHelp' : self.system_methodHelp})def register_multicall_functions(self):"""Registers the XML-RPC multicall method in the systemnamespace.see http://www.xmlrpc.com/discuss/msgReader1208ドル"""self.funcs.update({'system.multicall' : self.system_multicall})def _marshaled_dispatch(self, data, dispatch_method = None, path = None):"""Dispatches an XML-RPC method from marshalled (XML) data.XML-RPC methods are dispatched from the marshalled (XML) datausing the _dispatch method and the result is returned asmarshalled data. For backwards compatibility, a dispatchfunction can be provided as an argument (see comment inSimpleXMLRPCRequestHandler.do_POST) but overriding theexisting method through subclassing is the preferred meansof changing method dispatch behavior."""try:params, method = loads(data, use_builtin_types=self.use_builtin_types)# generate responseif dispatch_method is not None:response = dispatch_method(method, params)else:response = self._dispatch(method, params)# wrap response in a singleton tupleresponse = (response,)response = dumps(response, methodresponse=1,allow_none=self.allow_none, encoding=self.encoding)except Fault as fault:response = dumps(fault, allow_none=self.allow_none,encoding=self.encoding)except:# report exception back to serverexc_type, exc_value, exc_tb = sys.exc_info()try:response = dumps(Fault(1, "%s:%s" % (exc_type, exc_value)),encoding=self.encoding, allow_none=self.allow_none,)finally:# Break reference cycleexc_type = exc_value = exc_tb = Nonereturn response.encode(self.encoding, 'xmlcharrefreplace')def system_listMethods(self):"""system.listMethods() => ['add', 'subtract', 'multiple']Returns a list of the methods supported by the server."""methods = set(self.funcs.keys())if self.instance is not None:# Instance can implement _listMethod to return a list of# methodsif hasattr(self.instance, '_listMethods'):methods |= set(self.instance._listMethods())# if the instance has a _dispatch method then we# don't have enough information to provide a list# of methodselif not hasattr(self.instance, '_dispatch'):methods |= set(list_public_methods(self.instance))return sorted(methods)def system_methodSignature(self, method_name):"""system.methodSignature('add') => [double, int, int]Returns a list describing the signature of the method. In theabove example, the add method takes two integers as argumentsand returns a double result.This server does NOT support system.methodSignature."""# See http://xmlrpc.usefulinc.com/doc/sysmethodsig.htmlreturn 'signatures not supported'def system_methodHelp(self, method_name):"""system.methodHelp('add') => "Adds two integers together"Returns a string containing documentation for the specified method."""method = Noneif method_name in self.funcs:method = self.funcs[method_name]elif self.instance is not None:# Instance can implement _methodHelp to return help for a methodif hasattr(self.instance, '_methodHelp'):return self.instance._methodHelp(method_name)# if the instance has a _dispatch method then we# don't have enough information to provide helpelif not hasattr(self.instance, '_dispatch'):try:method = resolve_dotted_attribute(self.instance,method_name,self.allow_dotted_names)except AttributeError:pass# Note that we aren't checking that the method actually# be a callable object of some kindif method is None:return ""else:return pydoc.getdoc(method)def system_multicall(self, call_list):"""system.multicall([{'methodName': 'add', 'params': [2, 2]}, ...]) => \[[4], ...]Allows the caller to package multiple XML-RPC calls into a singlerequest.See http://www.xmlrpc.com/discuss/msgReader1208ドル"""results = []for call in call_list:method_name = call['methodName']params = call['params']try:# XXX A marshalling error in any response will fail the entire# multicall. If someone cares they should fix this.results.append([self._dispatch(method_name, params)])except Fault as fault:results.append({'faultCode' : fault.faultCode,'faultString' : fault.faultString})except:exc_type, exc_value, exc_tb = sys.exc_info()try:results.append({'faultCode' : 1,'faultString' : "%s:%s" % (exc_type, exc_value)})finally:# Break reference cycleexc_type = exc_value = exc_tb = Nonereturn resultsdef _dispatch(self, method, params):"""Dispatches the XML-RPC method.XML-RPC calls are forwarded to a registered function thatmatches the called XML-RPC method name. If no such functionexists then the call is forwarded to the registered instance,if available.If the registered instance has a _dispatch method then thatmethod will be called with the name of the XML-RPC method andits parameters as a tuplee.g. instance._dispatch('add',(2,3))If the registered instance does not have a _dispatch methodthen the instance will be searched to find a matching methodand, if found, will be called.Methods beginning with an '_' are considered private and willnot be called."""try:# call the matching registered functionfunc = self.funcs[method]except KeyError:passelse:if func is not None:return func(*params)raise Exception('method "%s" is not supported' % method)if self.instance is not None:if hasattr(self.instance, '_dispatch'):# call the `_dispatch` method on the instancereturn self.instance._dispatch(method, params)# call the instance's method directlytry:func = resolve_dotted_attribute(self.instance,method,self.allow_dotted_names)except AttributeError:passelse:if func is not None:return func(*params)raise Exception('method "%s" is not supported' % method)class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):"""Simple XML-RPC request handler class.Handles all HTTP POST requests and attempts to decode them asXML-RPC requests."""# Class attribute listing the accessible path components;# paths not on this list will result in a 404 error.rpc_paths = ('/', '/RPC2')#if not None, encode responses larger than this, if possibleencode_threshold = 1400 #a common MTU#Override form StreamRequestHandler: full buffering of output#and no Nagle.wbufsize = -1disable_nagle_algorithm = True# a re to match a gzip Accept-Encodingaepattern = re.compile(r"""\s* ([^\s;]+) \s* #content-coding(;\s* q \s*=\s* ([0-9\.]+))? #q""", re.VERBOSE | re.IGNORECASE)def accept_encodings(self):r = {}ae = self.headers.get("Accept-Encoding", "")for e in ae.split(","):match = self.aepattern.match(e)if match:v = match.group(3)v = float(v) if v else 1.0r[match.group(1)] = vreturn rdef is_rpc_path_valid(self):if self.rpc_paths:return self.path in self.rpc_pathselse:# If .rpc_paths is empty, just assume all paths are legalreturn Truedef do_POST(self):"""Handles the HTTP POST request.Attempts to interpret all HTTP POST requests as XML-RPC calls,which are forwarded to the server's _dispatch method for handling."""# Check that the path is legalif not self.is_rpc_path_valid():self.report_404()returntry:# Get arguments by reading body of request.# We read this in chunks to avoid straining# socket.read(); around the 10 or 15Mb mark, some platforms# begin to have problems (bug #792570).max_chunk_size = 10*1024*1024size_remaining = int(self.headers["content-length"])L = []while size_remaining:chunk_size = min(size_remaining, max_chunk_size)chunk = self.rfile.read(chunk_size)if not chunk:breakL.append(chunk)size_remaining -= len(L[-1])data = b''.join(L)data = self.decode_request_content(data)if data is None:return #response has been sent# In previous versions of SimpleXMLRPCServer, _dispatch# could be overridden in this class, instead of in# SimpleXMLRPCDispatcher. To maintain backwards compatibility,# check to see if a subclass implements _dispatch and dispatch# using that method if present.response = self.server._marshaled_dispatch(data, getattr(self, '_dispatch', None), self.path)except Exception as e: # This should only happen if the module is buggy# internal error, report as HTTP server errorself.send_response(500)# Send information about the exception if requestedif hasattr(self.server, '_send_traceback_header') and \self.server._send_traceback_header:self.send_header("X-exception", str(e))trace = traceback.format_exc()trace = str(trace.encode('ASCII', 'backslashreplace'), 'ASCII')self.send_header("X-traceback", trace)self.send_header("Content-length", "0")self.end_headers()else:self.send_response(200)self.send_header("Content-type", "text/xml")if self.encode_threshold is not None:if len(response) > self.encode_threshold:q = self.accept_encodings().get("gzip", 0)if q:try:response = gzip_encode(response)self.send_header("Content-Encoding", "gzip")except NotImplementedError:passself.send_header("Content-length", str(len(response)))self.end_headers()self.wfile.write(response)def decode_request_content(self, data):#support gzip encoding of requestencoding = self.headers.get("content-encoding", "identity").lower()if encoding == "identity":return dataif encoding == "gzip":try:return gzip_decode(data)except NotImplementedError:self.send_response(501, "encoding %r not supported" % encoding)except ValueError:self.send_response(400, "error decoding gzip content")else:self.send_response(501, "encoding %r not supported" % encoding)self.send_header("Content-length", "0")self.end_headers()def report_404 (self):# Report a 404 errorself.send_response(404)response = b'No such page'self.send_header("Content-type", "text/plain")self.send_header("Content-length", str(len(response)))self.end_headers()self.wfile.write(response)def log_request(self, code='-', size='-'):"""Selectively log an accepted request."""if self.server.logRequests:BaseHTTPRequestHandler.log_request(self, code, size)class SimpleXMLRPCServer(socketserver.TCPServer,SimpleXMLRPCDispatcher):"""Simple XML-RPC server.Simple XML-RPC server that allows functions and a single instanceto be installed to handle requests. The default implementationattempts to dispatch XML-RPC calls to the functions or instanceinstalled in the server. Override the _dispatch method inheritedfrom SimpleXMLRPCDispatcher to change this behavior."""allow_reuse_address = True# Warning: this is for debugging purposes only! Never set this to True in# production code, as will be sending out sensitive information (exception# and stack trace details) when exceptions are raised inside# SimpleXMLRPCRequestHandler.do_POST_send_traceback_header = Falsedef __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,logRequests=True, allow_none=False, encoding=None,bind_and_activate=True, use_builtin_types=False):self.logRequests = logRequestsSimpleXMLRPCDispatcher.__init__(self, allow_none, encoding, use_builtin_types)socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate)class MultiPathXMLRPCServer(SimpleXMLRPCServer):"""Multipath XML-RPC ServerThis specialization of SimpleXMLRPCServer allows the user to createmultiple Dispatcher instances and assign them to differentHTTP request paths. This makes it possible to run two or more'virtual XML-RPC servers' at the same port.Make sure that the requestHandler accepts the paths in question."""def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,logRequests=True, allow_none=False, encoding=None,bind_and_activate=True, use_builtin_types=False):SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests, allow_none,encoding, bind_and_activate, use_builtin_types)self.dispatchers = {}self.allow_none = allow_noneself.encoding = encoding or 'utf-8'def add_dispatcher(self, path, dispatcher):self.dispatchers[path] = dispatcherreturn dispatcherdef get_dispatcher(self, path):return self.dispatchers[path]def _marshaled_dispatch(self, data, dispatch_method = None, path = None):try:response = self.dispatchers[path]._marshaled_dispatch(data, dispatch_method, path)except:# report low level exception back to server# (each dispatcher should have handled their own# exceptions)exc_type, exc_value = sys.exc_info()[:2]try:response = dumps(Fault(1, "%s:%s" % (exc_type, exc_value)),encoding=self.encoding, allow_none=self.allow_none)response = response.encode(self.encoding, 'xmlcharrefreplace')finally:# Break reference cycleexc_type = exc_value = Nonereturn responseclass CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):"""Simple handler for XML-RPC data passed through CGI."""def __init__(self, allow_none=False, encoding=None, use_builtin_types=False):SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding, use_builtin_types)def handle_xmlrpc(self, request_text):"""Handle a single XML-RPC request"""response = self._marshaled_dispatch(request_text)print('Content-Type: text/xml')print('Content-Length: %d' % len(response))print()sys.stdout.flush()sys.stdout.buffer.write(response)sys.stdout.buffer.flush()def handle_get(self):"""Handle a single HTTP GET request.Default implementation indicates an error becauseXML-RPC uses the POST method."""code = 400message, explain = BaseHTTPRequestHandler.responses[code]response = http.server.DEFAULT_ERROR_MESSAGE % \{'code' : code,'message' : message,'explain' : explain}response = response.encode('utf-8')print('Status: %d %s' % (code, message))print('Content-Type: %s' % http.server.DEFAULT_ERROR_CONTENT_TYPE)print('Content-Length: %d' % len(response))print()sys.stdout.flush()sys.stdout.buffer.write(response)sys.stdout.buffer.flush()def handle_request(self, request_text=None):"""Handle a single XML-RPC request passed through a CGI post method.If no XML data is given then it is read from stdin. The resultingXML-RPC response is printed to stdout along with the correct HTTPheaders."""if request_text is None and \os.environ.get('REQUEST_METHOD', None) == 'GET':self.handle_get()else:# POST data is normally available through stdintry:length = int(os.environ.get('CONTENT_LENGTH', None))except (ValueError, TypeError):length = -1if request_text is None:request_text = sys.stdin.read(length)self.handle_xmlrpc(request_text)# -----------------------------------------------------------------------------# Self documenting XML-RPC Server.class ServerHTMLDoc(pydoc.HTMLDoc):"""Class used to generate pydoc HTML document for a server"""def markup(self, text, escape=None, funcs={}, classes={}, methods={}):"""Mark up some plain text, given a context of symbols to look for.Each context dictionary maps object names to anchor names."""escape = escape or self.escaperesults = []here = 0# XXX Note that this regular expression does not allow for the# hyperlinking of arbitrary strings being used as method# names. Only methods with names consisting of word characters# and '.'s are hyperlinked.pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'r'RFC[- ]?(\d+)|'r'PEP[- ]?(\d+)|'r'(self\.)?((?:\w|\.)+))\b')while 1:match = pattern.search(text, here)if not match: breakstart, end = match.span()results.append(escape(text[here:start]))all, scheme, rfc, pep, selfdot, name = match.groups()if scheme:url = escape(all).replace('"', '"')results.append('<a href="%s">%s</a>' % (url, url))elif rfc:url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)results.append('<a href="%s">%s</a>' % (url, escape(all)))elif pep:url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)results.append('<a href="%s">%s</a>' % (url, escape(all)))elif text[end:end+1] == '(':results.append(self.namelink(name, methods, funcs, classes))elif selfdot:results.append('self.<strong>%s</strong>' % name)else:results.append(self.namelink(name, classes))here = endresults.append(escape(text[here:]))return ''.join(results)def docroutine(self, object, name, mod=None,funcs={}, classes={}, methods={}, cl=None):"""Produce HTML documentation for a function or method object."""anchor = (cl and cl.__name__ or '') + '-' + namenote = ''title = '<a name="%s"><strong>%s</strong></a>' % (self.escape(anchor), self.escape(name))if callable(object):argspec = str(signature(object))else:argspec = '(...)'if isinstance(object, tuple):argspec = object[0] or argspecdocstring = object[1] or ""else:docstring = pydoc.getdoc(object)decl = title + argspec + (note and self.grey('<font face="helvetica, arial">%s</font>' % note))doc = self.markup(docstring, self.preformat, funcs, classes, methods)doc = doc and '<dd><tt>%s</tt></dd>' % docreturn '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)def docserver(self, server_name, package_documentation, methods):"""Produce HTML documentation for an XML-RPC server."""fdict = {}for key, value in methods.items():fdict[key] = '#-' + keyfdict[value] = fdict[key]server_name = self.escape(server_name)head = '<big><big><strong>%s</strong></big></big>' % server_nameresult = self.heading(head, '#ffffff', '#7799ee')doc = self.markup(package_documentation, self.preformat, fdict)doc = doc and '<tt>%s</tt>' % docresult = result + '<p>%s</p>\n' % doccontents = []method_items = sorted(methods.items())for key, value in method_items:contents.append(self.docroutine(value, key, funcs=fdict))result = result + self.bigsection('Methods', '#ffffff', '#eeaa77', ''.join(contents))return resultclass XMLRPCDocGenerator:"""Generates documentation for an XML-RPC server.This class is designed as mix-in and should notbe constructed directly."""def __init__(self):# setup variables used for HTML documentationself.server_name = 'XML-RPC Server Documentation'self.server_documentation = \"This server exports the following methods through the XML-RPC "\"protocol."self.server_title = 'XML-RPC Server Documentation'def set_server_title(self, server_title):"""Set the HTML title of the generated server documentation"""self.server_title = server_titledef set_server_name(self, server_name):"""Set the name of the generated HTML server documentation"""self.server_name = server_namedef set_server_documentation(self, server_documentation):"""Set the documentation string for the entire server."""self.server_documentation = server_documentationdef generate_html_documentation(self):"""generate_html_documentation() => html documentation for the serverGenerates HTML documentation for the server using introspection forinstalled functions and instances that do not implement the_dispatch method. Alternatively, instances can choose to implementthe _get_method_argstring(method_name) method to provide theargument string used in the documentation and the_methodHelp(method_name) method to provide the help text usedin the documentation."""methods = {}for method_name in self.system_listMethods():if method_name in self.funcs:method = self.funcs[method_name]elif self.instance is not None:method_info = [None, None] # argspec, documentationif hasattr(self.instance, '_get_method_argstring'):method_info[0] = self.instance._get_method_argstring(method_name)if hasattr(self.instance, '_methodHelp'):method_info[1] = self.instance._methodHelp(method_name)method_info = tuple(method_info)if method_info != (None, None):method = method_infoelif not hasattr(self.instance, '_dispatch'):try:method = resolve_dotted_attribute(self.instance,method_name)except AttributeError:method = method_infoelse:method = method_infoelse:assert 0, "Could not find method in self.functions and no "\"instance installed"methods[method_name] = methoddocumenter = ServerHTMLDoc()documentation = documenter.docserver(self.server_name,self.server_documentation,methods)return documenter.page(html.escape(self.server_title), documentation)class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):"""XML-RPC and documentation request handler class.Handles all HTTP POST requests and attempts to decode them asXML-RPC requests.Handles all HTTP GET requests and interprets them as requestsfor documentation."""def do_GET(self):"""Handles the HTTP GET request.Interpret all HTTP GET requests as requests for serverdocumentation."""# Check that the path is legalif not self.is_rpc_path_valid():self.report_404()returnresponse = self.server.generate_html_documentation().encode('utf-8')self.send_response(200)self.send_header("Content-type", "text/html")self.send_header("Content-length", str(len(response)))self.end_headers()self.wfile.write(response)class DocXMLRPCServer( SimpleXMLRPCServer,XMLRPCDocGenerator):"""XML-RPC and HTML documentation server.Adds the ability to serve server documentation to the capabilitiesof SimpleXMLRPCServer."""def __init__(self, addr, requestHandler=DocXMLRPCRequestHandler,logRequests=True, allow_none=False, encoding=None,bind_and_activate=True, use_builtin_types=False):SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests,allow_none, encoding, bind_and_activate,use_builtin_types)XMLRPCDocGenerator.__init__(self)class DocCGIXMLRPCRequestHandler( CGIXMLRPCRequestHandler,XMLRPCDocGenerator):"""Handler for XML-RPC data and documentation requests passed throughCGI"""def handle_get(self):"""Handles the HTTP GET request.Interpret all HTTP GET requests as requests for serverdocumentation."""response = self.generate_html_documentation().encode('utf-8')print('Content-Type: text/html')print('Content-Length: %d' % len(response))print()sys.stdout.flush()sys.stdout.buffer.write(response)sys.stdout.buffer.flush()def __init__(self):CGIXMLRPCRequestHandler.__init__(self)XMLRPCDocGenerator.__init__(self)if __name__ == '__main__':import datetimeclass ExampleService:def getData(self):return '42'class currentTime:@staticmethoddef getCurrentTime():return datetime.datetime.now()with SimpleXMLRPCServer(("localhost", 8000)) as server:server.register_function(pow)server.register_function(lambda x,y: x+y, 'add')server.register_instance(ExampleService(), allow_dotted_names=True)server.register_multicall_functions()print('Serving XML-RPC on localhost port 8000')print('It is advisable to run this example server within a secure, closed network.')try:server.serve_forever()except KeyboardInterrupt:print("\nKeyboard interrupt received, exiting.")sys.exit(0)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。