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       
Back to Top