def post(self, request): dispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None) dispatcher.register_function(partial(self.ping, request), 'pingback:ping') response = HttpResponse(mimetype="application/xml") response.write(dispatcher._marshaled_dispatch(request.raw_post_data)) return response
class WSGIXMLRPCApplication(object): """Application to handle requests to the XMLRPC service""" def __init__(self, instance=None, methods=[]): """Create windmill xmlrpc dispatcher""" self.dispatcher = SimpleXMLRPCDispatcher(allow_none=True, encoding=None) if instance is not None: self.dispatcher.register_instance(instance) for method in methods: self.dispatcher.register_function(method) self.dispatcher.register_introspection_functions() def handler(self, environ, start_response): """XMLRPC service for windmill browser core to communicate with""" if environ['REQUEST_METHOD'] == 'POST': return self.handle_POST(environ, start_response) else: start_response("400 Bad request", [('Content-Type', 'text/plain')]) return [''] def handle_POST(self, environ, start_response): """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. Most code taken from SimpleXMLRPCServer with modifications for wsgi and my custom dispatcher. """ try: # Get arguments by reading body of request. # We read this in chunks to avoid straining length = int(environ['CONTENT_LENGTH']) data = environ['wsgi.input'].read(length) # 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 # using that method if present. response = self.dispatcher._marshaled_dispatch( data, getattr(self.dispatcher, '_dispatch', None) ) response += '\n' except: # This should only happen if the module is buggy # internal error, report as HTTP server error start_response("500 Server error", [('Content-Type', 'text/plain')]) return [] else: # got a valid XML RPC response start_response("200 OK", [('Content-Type', 'text/xml'), ('Content-Length', str(len(response)),)]) return [response] def __call__(self, environ, start_response): return self.handler(environ, start_response)
class WSGIXMLRPCApplication(object): """Application to handle requests to the XMLRPC service""" def __init__(self, instance=None, methods=()): """Create windmill xmlrpc dispatcher""" try: self.dispatcher = SimpleXMLRPCDispatcher(allow_none=True, encoding=None) except TypeError: # python 2.4 self.dispatcher = SimpleXMLRPCDispatcher() if instance is not None: self.dispatcher.register_instance(instance) for method in methods: self.dispatcher.register_function(method) self.dispatcher.register_introspection_functions() @Request.application def handler(self, request): if request.method == 'POST': return self.handle_POST(request) else: return BadRequest() def handle_POST(self, request): """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. Most code taken from SimpleXMLRPCServer with modifications for wsgi and my custom dispatcher. """ try: # Read the data from the request data = request.get_data() # 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 # using that method if present. response = self.dispatcher._marshaled_dispatch( data, getattr(self.dispatcher, '_dispatch', None)) response += '\n' except: # This should only happen if the module is buggy # internal error, report as HTTP server error return InternalServerError() else: # got a valid XML RPC response return Response(response, mimetype='text/xml') def __call__(self, environ, start_response): return self.handler(environ, start_response)
def handler(request, response, methods): response.session_id = None # no sessions for xmlrpc dispatcher = SimpleXMLRPCDispatcher(allow_none=True, encoding=None) for method in methods: dispatcher.register_function(method) dispatcher.register_introspection_functions() response.headers['Content-Type'] = 'text/xml' dispatch = getattr(dispatcher, '_dispatch', None) return dispatcher._marshaled_dispatch(request.body.read(), dispatch)
def rpc_handler(request): """ the actual handler: if you setup your urls.py properly, all calls to the xml-rpc service should be routed through here. If post data is defined, it assumes it's XML-RPC and tries to process as such Empty post assumes you're viewing from a browser and tells you about the service. """ #moving this here to see if it will fix the thread leaks dispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None) # Python 2.5 if len(request.POST): dispatcher.register_function(_updateStatus, 'updateStatus') dispatcher.register_function(_setSceneError, 'setSceneError') dispatcher.register_function(_set_scene_unavailable, 'setSceneUnavailable') dispatcher.register_function(_markSceneComplete, 'markSceneComplete') dispatcher.register_function(_getConfiguration, 'getConfiguration') dispatcher.register_function(_getScenesToProcess, 'getScenesToProcess') dispatcher.register_function(_getScenesToPurge, 'getScenesToPurge') dispatcher.register_function(_getSceneInputPath, 'getSceneInputPath') dispatcher.register_function(_getDataSourceCredentials, 'getDataSourceCredentials') #if our leak isn't fixed, try checking to see if we need to close the response here. response = HttpResponse(mimetype="application/xml") response.write(dispatcher._marshaled_dispatch(request.raw_post_data)) else: response = HttpResponse() response.write("<b>This is an XML-RPC Service.</b><br>") response.write("You need to invoke it using an XML-RPC Client!<br>") response.write("The following methods are available:<ul>") methods = dispatcher.system_listMethods() for method in methods: # right now, my version of SimpleXMLRPCDispatcher always # returns "signatures not supported"... :( # but, in an ideal world it will tell users what args are expected sig = dispatcher.system_methodSignature(method) # this just reads your docblock, so fill it in! help = dispatcher.system_methodHelp(method) response.write("<li><b>%s</b>: [%s] %s" % (method, sig, help)) response.write("</ul>") response.write('<a href="http://www.djangoproject.com/"> <img src="http://media.djangoproject.com/img/badges/djangomade124x25_grey.gif" border="0" alt="Made with Django." title="Made with Django."></a>') response['Content-length'] = str(len(response.content)) return response
def handle_request(app, request): '''Wrap an invocation of the XML-RPC dispatcher. ''' dispatcher = SimpleXMLRPCDispatcher() dispatcher.register_instance(Interface(app, request)) # read in the XML-RPC request data, limiting to a sensible size if int(request.headers['Content-Length']) > 10 * 1024 * 1024: raise BadRequest('request data too large') xml_request = request.get_data(cache=False, as_text=True) # errors here are handled by _marshaled_dispatch response = dispatcher._marshaled_dispatch(xml_request) # legacy; remove non-printable ASCII control codes from the response response = re.sub('([\x00-\x08]|[\x0b-\x0c]|[\x0e-\x1f])+', '', response) return Response(response, mimetype="text/xml")
class ServerGateway(object): def __init__(self, prefix): self.prefix = prefix try: # Python 2.4 self.dispatcher = SimpleXMLRPCDispatcher() except TypeError: # Python 2.5 self.dispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None) def add_function(self, name, func): self.dispatcher.register_function(func, ".".join([self.prefix, name])) def connect( self, func=None, name=None): def _connector(func): self.add_function(not name and func.__name__ or name, func) return func if not func: return _connector else: _connector(func) return func def __call__(self, request, *args, **kwargs): if kwargs: raise RuntimeError("Xmlrpc server gateway cannot handle key variable argumets") def custom_dispatch(method, params): return self.dispatcher._dispatch(method, params + tuple(args)) response = HttpResponse() if len(request.POST): response.write(self.dispatcher._marshaled_dispatch(request.raw_post_data, custom_dispatch)) else: methods = self.dispatcher.system_listMethods() response['Content-Type'] = 'text/plain' for method in methods: # __doc__ help = self.dispatcher.system_methodHelp(method) response.write("%s:\n %s\n\n" % (method, help)) response['Content-Length'] = str(len(response.content)) return response
def rpc_handler(request): """ the actual handler: if you setup your urls.py properly, all calls to the xml-rpc service should be routed through here. If post data is defined, it assumes it's XML-RPC and tries to process as such. Empty post assumes you're viewing from a browser and tells you about the service. """ d = SimpleXMLRPCDispatcher(allow_none=True, encoding=None) if len(request.body): d.register_function(_update_status, 'update_status') d.register_function(_set_product_error, 'set_scene_error') d.register_function(_set_product_unavailable, 'set_scene_unavailable') d.register_function(_mark_product_complete, 'mark_scene_complete') d.register_function(_handle_orders, 'handle_orders') d.register_function(_queue_products, 'queue_products') d.register_function(_get_configuration, 'get_configuration') d.register_function(_get_products_to_process, 'get_scenes_to_process') d.register_function(_get_data_points, 'get_data_points') response = HttpResponse(mimetype="application/xml") response.write(d._marshaled_dispatch(request.body)) else: response = HttpResponse() response.write("<b>This is an XML-RPC Service.</b><br>") response.write("You need to invoke it using an XML-RPC Client!<br>") response.write("The following methods are available:<ul>") methods = d.system_listMethods() for method in methods: sig = d.system_methodSignature(method) # this just reads your docblock, so fill it in! help_msg = d.system_methodHelp(method) response.write("<li><b>%s</b>: [%s] %s" % (method, sig, help_msg)) response.write("</ul>") response['Content-length'] = str(len(response.content)) return response
class XMLRPCApplication(RestApplication): """Application to handle requests to the XMLRPC service""" def __init__(self, instance=None, methods=[]): """Create windmill xmlrpc dispatcher""" try: self.dispatcher = SimpleXMLRPCDispatcher(allow_none=True, encoding=None) except TypeError: # python 2.4 self.dispatcher = SimpleXMLRPCDispatcher() if instance is not None: self.dispatcher.register_instance(instance) for method in methods: self.dispatcher.register_function(method) self.dispatcher.register_introspection_functions() def POST(self, request, *path): """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. Most code taken from SimpleXMLRPCServer with modifications for wsgi and my custom dispatcher. """ try: data = str(request.body) # 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 # using that method if present. response = self.dispatcher._marshaled_dispatch( data, getattr(self.dispatcher, '_dispatch', None) ) response += '\n' except: # This should only happen if the module is buggy # internal error, report as HTTP server error return Response500() else: # got a valid XML RPC response return XMLResponse(response)
class RpcHandler: def __init__(self): self.__dispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None) def dispatcher(self): return self.__dispatcher def rpc_handler(self,request): """ the actual handler: if you setup your urls.py properly, all calls to the xml-rpc service should be routed through here. If post data is defined, it assumes it's XML-RPC and tries to process as such Empty post assumes you're viewing from a browser and tells you about the service. """ if len(request.POST): response = HttpResponse(mimetype="application/xml") response.write(self.__dispatcher._marshaled_dispatch(request.raw_post_data)) else: response = HttpResponse() response.write("<b>This is an XML-RPC Service.</b><br>") response.write("You need to invoke it using an XML-RPC Client!<br>") response.write("The following methods are available:<ul>") methods = self.__dispatcher.system_listMethods() for method in methods: # right now, my version of SimpleXMLRPCDispatcher always # returns "signatures not supported"... :( # but, in an ideal world it will tell users what args are expected sig = self.__dispatcher.system_methodSignature(method) # this just reads your docblock, so fill it in! help = self.__dispatcher.system_methodHelp(method) response.write("<li><b>%s</b>: [%s] %s" % (method, sig, help)) response.write("</ul>") # response['Content-length'] = str(len(response.content)) return response
def handle_request(app, request): '''Wrap an invocation of the XML-RPC dispatcher. ''' # unicode strings will be encoded in utf-8 by xmlrpclib dispatcher = SimpleXMLRPCDispatcher() dispatcher.register_instance(Interface(app, request)) # read in the XML-RPC request data, limiting to a sensible size if int(request.headers['Content-Length']) > 10 * 1024 * 1024: raise BadRequest('request data too large') xml_request = request.get_data(cache=False, as_text=True) # errors here are handled by _marshaled_dispatch response = dispatcher._marshaled_dispatch(xml_request) # legacy; remove non-printable ASCII control codes from the response # RJ: disabled this as it's a giant, unreliable hack that doesn't work and # I can't even remember why it's in here to start with # response = re.sub('([\x00-\x08]|[\x0b-\x0c]|[\x0e-\x1f])+', '', response) return Response(response, mimetype="text/xml; charset=utf-8")
class WSGIXMLRPCApplication: def __init__(self,instance=None,methods=[]): self.dispatcher = SimpleXMLRPCDispatcher(allow_none=True,encoding=None) if instance is not None: self.dispatcher.register_instance(instance) for method in methods: self.dispatcher.register_function(method) self.dispatcher.register_introspection_functions() def __call__(self,environ,start_response): if environ["REQUEST_METHOD"] == "POST": return self.handle_post(environ,start_response) else: start_response("400 Bad request",[("Content-Type","text/plain")]) return [''] def handle_post(self,environ,start_response): try: max_chunk_size = 10*1024*1024 size_remaining = int(environ["CONTENT_LENGTH"]) L = [] rfile = environ['wsgi.input'] while size_remaining: chunk_size = min(size_remaining, max_chunk_size) chunk = rfile.read(chunk_size) if not chunk: break L.append(chunk) size_remaining -= len(L[-1]) data = ''.join(L) data = self.decode_request_content(data,environ,start_response) if isinstance(data, list): return data response = self.dispatcher._marshaled_dispatch(data) except Exception, e: start_response("%d %s" % (500,_RESPONSE_STATUSES[500]),[ ("Content-length", '') ]) return [] else:
class XMLRPCDispatcher(Resource): '''A Resource that knows how to host an XMLRPCObject and serve it''' def __init__(self, application, request, response, session, instance=None, methods=[], allow_none=True, encoding=None): '''initializes this dispatcher which can handle XMLRPC requests.''' if not instance: raise ValueError("You must pass in a non-null object which we will serve") super(XMLRPCDispatcher, self).__init__(application, request, response, session) self.dispatcher = SimpleXMLRPCDispatcher(allow_none=allow_none, encoding=encoding) self.dispatcher.register_instance(instance) for method in methods: self.dispatcher.register_function(method) self.dispatcher.register_introspection_functions() self.dispatcher.register_multicall_functions() @POST @Route("/{path:.*}") def post(self, path): ''' Attempts to process all posts as XMLRPC Requests which are then dispatched to the XMLRPCObject. Most of the code was taken from SimpleXMLRPCServer with modifications to make it compatible with Gates ''' try: data = self.request.body response = self.dispatcher._marshaled_dispatch( data, getattr(self.dispatcher, '_dispatch', None) ) except Exception as e: # This should only happen if the module is buggy # internal error, report as Internal HTTP Server error traceback.print_exc(e) abort(500, "XMLRPC Application Error! You shouldn't be seeing this. We're sorry.") else: # We got a valid XML RPC response self.response.type = "text/xml" self.response.write(response)
class WSGIXMLRPCApplication(object): """WSGI application to handle requests to the XMLRPC service. This WSGI application acts like the Python standard `SimpleXMLRPCServer` but processes WSGI requests instead and does not fiddle around with raw HTTP. The passed in `cache_dir` is used only if set. """ def __init__(self, cache_dir=None): # set up a dispatcher self.dispatcher = SimpleXMLRPCDispatcher( allow_none=True, encoding=None) self.dispatcher.register_function( self.convert_locally, 'convert_locally') self.dispatcher.register_function( self.get_cached, 'get_cached') self.dispatcher.register_introspection_functions() self.cache_dir = cache_dir def convert_locally(self, src_path, options): """Convert document in `path`. Expects a local path to the document to convert. The `options` are a dictionary of options as accepted by all converter components in this package. The cache (if set) will be updated. Returns path of converted document, a cache key and a dictionary of metadata. The cache key is ``None`` if no cache was used. """ result_path, cache_key, metadata = convert_doc( src_path, options, self.cache_dir) return result_path, cache_key, metadata def get_cached(self, cache_key): """Get a cached document. Retrieve the document representation stored under `cache_key` in cache if it exists. Returns `None` otherwise. """ client = Client(cache_dir=self.cache_dir) return client.get_cached(cache_key) @wsgify def __call__(self, req): """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. Most code taken from SimpleXMLRPCServer with modifications for wsgi and my custom dispatcher. """ if req.method != 'POST': return exc.HTTPBadRequest() try: data = req.environ['wsgi.input'].read(req.content_length) response = self.dispatcher._marshaled_dispatch( data, self.dispatcher._dispatch ) + '\n' except: # pragma: no cover # This should only happen if the module is buggy # internal error, report as HTTP server error return exc.HTTPServerError() else: # got a valid XML RPC response response = Response(response) response.content_type = 'text/xml' return response
class RPCDispatcher: """ Dispatches method calls to either the xmlrpc or jsonrpc dispatcher """ def __init__(self, url="", apps=[], restrict_introspection=False): version = platform.python_version_tuple() self.url = url self.rpcmethods = [] # a list of RPCMethod objects self.jsonrpcdispatcher = JSONRPCDispatcher() if int(version[0]) < 3 and int(version[1]) < 5: # this is for python 2.4 and below self.xmlrpcdispatcher = SimpleXMLRPCDispatcher() else: # python 2.5+ requires different parameters self.xmlrpcdispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None) if not restrict_introspection: self.register_method(self.system_listmethods) self.register_method(self.system_methodhelp) self.register_method(self.system_methodsignature) self.register_method(self.system_describe) self.register_rpcmethods(apps) @rpcmethod(name="system.describe", signature=["struct"]) def system_describe(self): """ Returns a simple method description of the methods supported """ description = {} description["serviceType"] = "RPC4Django JSONRPC+XMLRPC" description["serviceURL"] = (self.url,) description["methods"] = [ { "name": method.name, "summary": method.help, "params": method.get_params(), "return": method.get_returnvalue(), } for method in self.rpcmethods ] return description @rpcmethod(name="system.listMethods", signature=["array"]) def system_listmethods(self): """ Returns a list of supported methods """ methods = [method.name for method in self.rpcmethods] methods.sort() return methods @rpcmethod(name="system.methodHelp", signature=["string", "string"]) def system_methodhelp(self, method_name): """ Returns documentation for a specified method """ for method in self.rpcmethods: if method.name == method_name: return method.help # this differs from what implementation in SimpleXMLRPCServer does # this will report via a fault or error while SimpleXMLRPCServer # just returns an empty string raise Fault(APPLICATION_ERROR, "No method found with name: " + str(method_name)) @rpcmethod(name="system.methodSignature", signature=["array", "string"]) def system_methodsignature(self, method_name): """ Returns the signature for a specified method """ for method in self.rpcmethods: if method.name == method_name: return method.signature raise Fault(APPLICATION_ERROR, "No method found with name: " + str(method_name)) def register_rpcmethods(self, apps): """ Scans the installed apps for methods with the rpcmethod decorator Adds these methods to the list of methods callable via RPC """ for appname in apps: # check each app for any rpcmethods app = __import__(appname, globals(), locals(), ["*"]) for obj in dir(app): method = getattr(app, obj) if callable(method) and getattr(method, "is_rpcmethod", False): # if this method is callable and it has the rpcmethod # decorator, add it to the dispatcher self.register_method(method, method.external_name) def jsondispatch(self, raw_post_data): """ Sends the post data to a jsonrpc processor """ return self.jsonrpcdispatcher.dispatch(raw_post_data) def xmldispatch(self, raw_post_data): """ Sends the post data to an xmlrpc processor """ return self.xmlrpcdispatcher._marshaled_dispatch(raw_post_data) def get_method_name(self, raw_post_data, request_format="xml"): """ Gets the name of the method to be called given the post data and the format of the data """ if request_format == "xml": # xmlrpclib.loads could throw an exception, but this is fine # since _marshaled_dispatch would throw the same thing try: params, method = xmlrpclib.loads(raw_post_data) return method except Fault: return None else: try: # attempt to do a json decode on the data jsondict = json.loads(raw_post_data) if not isinstance(jsondict, dict) or "method" not in jsondict: return None else: return jsondict["method"] except ValueError: return None def list_methods(self): """ Returns a list of RPCMethod objects supported by the server """ return self.rpcmethods def register_method(self, method, name=None, signature=None, helpmsg=None): """ Registers a method with the rpc server """ meth = RPCMethod(method, name, signature, helpmsg) self.xmlrpcdispatcher.register_function(method, meth.name) self.jsonrpcdispatcher.register_function(method, meth.name) self.rpcmethods.append(meth)
class WSGIXMLRPCApplication(object): """WSGI application to handle requests to the XMLRPC service. This WSGI application acts like the Python standard `SimpleXMLRPCServer` but processes WSGI requests instead and does not fiddle around with raw HTTP. The passed in `cache_dir` is used only if set. """ def __init__(self, cache_dir=None): # set up a dispatcher self.dispatcher = SimpleXMLRPCDispatcher(allow_none=True, encoding=None) self.dispatcher.register_function(self.convert_locally, 'convert_locally') self.dispatcher.register_function(self.get_cached, 'get_cached') self.dispatcher.register_introspection_functions() self.cache_dir = cache_dir def convert_locally(self, src_path, options): """Convert document in `path`. Expects a local path to the document to convert. The `options` are a dictionary of options as accepted by all converter components in this package. The cache (if set) will be updated. Returns path of converted document, a cache key and a dictionary of metadata. The cache key is ``None`` if no cache was used. """ result_path, cache_key, metadata = convert_doc(src_path, options, self.cache_dir) return result_path, cache_key, metadata def get_cached(self, cache_key): """Get a cached document. Retrieve the document representation stored under `cache_key` in cache if it exists. Returns `None` otherwise. """ client = Client(cache_dir=self.cache_dir) return client.get_cached(cache_key) @wsgify def __call__(self, req): """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. Most code taken from SimpleXMLRPCServer with modifications for wsgi and my custom dispatcher. """ if req.method != 'POST': return exc.HTTPBadRequest() try: data = req.environ['wsgi.input'].read(req.content_length) response = self.dispatcher._marshaled_dispatch( data, self.dispatcher._dispatch) + b'\n' except: # pragma: no cover # This should only happen if the module is buggy # internal error, report as HTTP server error return exc.HTTPServerError() else: # got a valid XML RPC response response = Response(response) response.content_type = 'text/xml' return response
def _marshaled_dispatch(self, data, dispatch_method = None, path = None): self._path = path return SimpleXMLRPCDispatcher._marshaled_dispatch(self, data, dispatch_method, path)