Code

Ticket #547: xmlrpc.patch

File xmlrpc.patch, 5.6 KB (added by upadhyay@…, 9 years ago)

Here is the patch.

  • contrib/xmlrpc.py

     
     1import xmlrpclib 
     2 
     3class SimpleXMLRPCView: 
     4    """ Simple XMLRPC View. 
     5 
     6        Simple XML-RPC server that allows functions and a single instance 
     7        to be installed to handle requests. 
     8    """ 
     9        def __init__(self, logRequests=1): 
     10        self.funcs = {} 
     11        self.logRequests = logRequests 
     12        self.instance = None 
     13 
     14    def register_instance(self, instance): 
     15        """Registers an instance to respond to XML-RPC requests. 
     16 
     17            Only one instance can be installed at a time. 
     18 
     19            If the registered instance has a _dispatch method then that 
     20            method will be called with the name of the XML-RPC method and 
     21            it's parameters as a tuple 
     22            e.g. instance._dispatch('add',(2,3)) 
     23 
     24            If the registered instance does not have a _dispatch method 
     25            then the instance will be searched to find a matching method 
     26            and, if found, will be called. 
     27 
     28            Methods beginning with an '_' are considered private and will 
     29            not be called by SimpleXMLRPCView. 
     30 
     31            If a registered function matches a XML-RPC request, then it 
     32            will be called instead of the registered instance. 
     33        """ 
     34 
     35        self.instance = instance 
     36 
     37    def register_function(self, function, name = None): 
     38        """Registers a function to respond to XML-RPC requests. 
     39 
     40            The optional name argument can be used to set a Unicode name 
     41            for the function. 
     42 
     43            If an instance is also registered then it will only be called 
     44            if a matching function is not found. 
     45        """ 
     46 
     47        if name is None: 
     48            name = function.__name__ 
     49        self.funcs[name] = function 
     50 
     51    def _dispatch(self, method, params): 
     52        """Dispatches the XML-RPC method. 
     53 
     54            XML-RPC calls are forwarded to a registered function that 
     55            matches the called XML-RPC method name. If no such function 
     56            exists then the call is forwarded to the registered instance, 
     57            if available. 
     58 
     59            If the registered instance has a _dispatch method then that 
     60            method will be called with the name of the XML-RPC method and 
     61            it's parameters as a tuple 
     62            e.g. instance._dispatch('add',(2,3)) 
     63 
     64            If the registered instance does not have a _dispatch method 
     65            then the instance will be searched to find a matching method 
     66            and, if found, will be called. 
     67 
     68            Methods beginning with an '_' are considered private and will 
     69            not be called by SimpleXMLRPCView. 
     70        """ 
     71 
     72        def resolve_dotted_attribute(obj, attr): 
     73            """resolve_dotted_attribute(math, 'cos.__doc__') => math.cos.__doc__ 
     74 
     75                Resolves a dotted attribute name to an object. Raises 
     76                an AttributeError if any attribute in the chain starts 
     77                with a '_'. 
     78            """ 
     79            for i in attr.split('.'): 
     80                if i.startswith('_'): 
     81                    raise AttributeError( 
     82                        'attempt to access private attribute "%s"' % i 
     83                        ) 
     84                else: 
     85                    obj = getattr(obj,i) 
     86            return obj 
     87 
     88        func = None 
     89        try: 
     90            # check to see if a matching function has been registered 
     91            func = self.funcs[method] 
     92        except KeyError: 
     93            if self.instance is not None: 
     94                # check for a _dispatch method 
     95                if hasattr(self.instance, '_dispatch'): 
     96                    return apply( 
     97                        getattr(self.instance,'_dispatch'), 
     98                        (method, params) 
     99                        ) 
     100                else: 
     101                    # call instance method directly 
     102                    try: 
     103                        func = resolve_dotted_attribute( 
     104                            self.instance, 
     105                            method 
     106                            ) 
     107                    except AttributeError: 
     108                        pass 
     109 
     110        if func is not None: 
     111            return apply(func, params) 
     112        else: 
     113            raise Exception('method "%s" is not supported' % method) 
     114 
     115    def __call__(request): 
     116        """ SimpleXMLRPCView is callable so it can be installed as a view. 
     117 
     118            Django calls it with 'request', which is a HttpRequest             
     119        """ 
     120 
     121        if request.META['REQUEST_METHOD'] != 'POST': 
     122            return HttpResponseServerError('Non POST methods not allowed.') 
     123         
     124        try: 
     125            # get arguments 
     126            data = request.raw_post_data 
     127            params, method = xmlrpclib.loads(data) 
     128 
     129            # generate response 
     130            try: 
     131                response = self._dispatch(method, params) 
     132                # wrap response in a singleton tuple 
     133                response = (response,) 
     134            except: 
     135                # report exception back to server 
     136                response = xmlrpclib.dumps( 
     137                    xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)) 
     138                    ) 
     139            else: 
     140                response = xmlrpclib.dumps(response, methodresponse=1) 
     141        except: 
     142            # internal error, report as HTTP server error 
     143            return HttpResponseServerError('internal error') 
     144        else: 
     145            # got a valid XML RPC response 
     146            return HttpResponse(response, mimetype="text/xml") 
     147