| 1 | from SimpleXMLRPCServer import SimpleXMLRPCDispatcher, resolve_dotted_attribute |
| 2 | from django.utils.httpwrappers import HttpResponseServerError, HttpResponse |
| 3 | |
| 4 | |
| 5 | class SimpleXMLRPCView(SimpleXMLRPCDispatcher): |
| 6 | def __call__(self, request): |
| 7 | """ SimpleXMLRPCView is callable so it can be installed as a view. |
| 8 | |
| 9 | Django calls it with 'request', which is a HttpRequest |
| 10 | """ |
| 11 | |
| 12 | if request.META['REQUEST_METHOD'] != 'POST': |
| 13 | return HttpResponseServerError('Non POST methods not allowed.') |
| 14 | |
| 15 | try: |
| 16 | # get arguments |
| 17 | data = request.raw_post_data |
| 18 | response = self._marshaled_dispatch( |
| 19 | data, getattr(self, '_dispatch', None) |
| 20 | ) |
| 21 | except: |
| 22 | # internal error, report as HTTP server error |
| 23 | return HttpResponseServerError('internal error') |
| 24 | else: |
| 25 | # got a valid XML RPC response |
| 26 | return HttpResponse(response, mimetype="text/xml") |
| 27 | |
| 28 | class SafeXMLRPCView(SimpleXMLRPCView): |
| 29 | """ class SafeXMLRPCView |
| 30 | |
| 31 | Checks for "public" attribute on callables before calling them. |
| 32 | """ |
| 33 | def system_listMethods(self): |
| 34 | return SimpleXMLRPCView.system_listMethods(self) |
| 35 | system_listMethods.public = True |
| 36 | |
| 37 | def system_methodSignature(self, method_name): |
| 38 | return SimpleXMLRPCView.system_methodSignature(self, method_name) |
| 39 | system_methodSignature.public = True |
| 40 | |
| 41 | def system_methodHelp(self, method_name): |
| 42 | return SimpleXMLRPCView.system_methodHelp(self, method_name) |
| 43 | system_methodHelp.public = True |
| 44 | |
| 45 | def _dispatch(self, method, params): |
| 46 | """Dispatches the XML-RPC method. |
| 47 | |
| 48 | Overwriting to put some extra checks before calling a method. |
| 49 | """ |
| 50 | |
| 51 | func = None |
| 52 | try: |
| 53 | # check to see if a matching function has been registered |
| 54 | func = self.funcs[method] |
| 55 | except KeyError: |
| 56 | if self.instance is not None: |
| 57 | # check for a _dispatch method |
| 58 | if hasattr(self.instance, '_dispatch'): |
| 59 | return apply( |
| 60 | getattr(self.instance,'_dispatch'), |
| 61 | (method, params) |
| 62 | ) |
| 63 | else: |
| 64 | # call instance method directly |
| 65 | try: |
| 66 | func = resolve_dotted_attribute( |
| 67 | self.instance, |
| 68 | method |
| 69 | ) |
| 70 | except AttributeError: |
| 71 | pass |
| 72 | |
| 73 | if func is not None and hasattr(func, 'public') and func.public: |
| 74 | return apply(func, params) |
| 75 | else: |
| 76 | raise Exception('method "%s" is not supported' % method) |
| 77 | |