Ticket #547: xmlrpc.2.patch

File xmlrpc.2.patch, 6.0 KB (added by upadhyay@…, 19 years ago)

Oops, attached older patch, use this one.

  • contrib/xmlrpc.py

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