diff -ruN virgin/SimpleXMLRPCServer.py patched/SimpleXMLRPCServer.py --- virgin/SimpleXMLRPCServer.py 2005-11-17 21:17:45.000000000 -0500 +++ patched/SimpleXMLRPCServer.py 2005-11-18 11:10:44.000000000 -0500 @@ -159,9 +159,15 @@ reason to instantiate this class directly. """ + defaultFaultCode = 1 + unknownMethodFaultCode = 1 + badXMLFaultCode = 1 + badXMLRPCFaultCode = 1 + def __init__(self): self.funcs = {} self.instance = None + self.capabilities = {} def register_instance(self, instance, allow_dotted_names=False): """Registers an instance to respond to XML-RPC requests. @@ -221,6 +227,22 @@ 'system.methodSignature' : self.system_methodSignature, 'system.methodHelp' : self.system_methodHelp}) + def register_fault_interop_spec(self): + """Registers the XMLRPC Fault Interoperability specification""" + self.defaultFaultCode = xmlrpclib.APPLICATION_ERROR + self.badXMLFaultCode = xmlrpclib.PARSE_ERROR + self.badXMLRPCFaultCode = xmlrpclib.INVALID_XMLRPC + self.unknownMethodFaultCode = xmlrpclib.METHOD_NOT_FOUND + self.funcs.update({'system.getCapabilities' : self.system_getCapabilities}) + self.register_capability('faults_interop', + '20010516', + 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php') + + def register_capability(self, spec, version, url): + """Register an implemented capability of this listener.""" + self.capabilities.update({spec: {'specVersion': version, + 'specUrl': url}}) + def register_multicall_functions(self): """Registers the XML-RPC multicall method in the system namespace. @@ -240,11 +262,9 @@ existing method through subclassing is the prefered means of changing method dispatch behavior. """ - - params, method = xmlrpclib.loads(data) - # generate response try: + params, method = xmlrpclib.loads(data) if dispatch_method is not None: response = dispatch_method(method, params) else: @@ -254,10 +274,21 @@ response = xmlrpclib.dumps(response, methodresponse=1) except Fault, fault: response = xmlrpclib.dumps(fault) + except xmlrpclib.ParseError, e: + response = xmlrpclib.dumps( + xmlrpclib.Fault(self.badXMLFaultCode, + str(e)) + ) + except xmlrpclib.ResponseError, e: + response = xmlrpclib.dumps( + xmlrpclib.Fault(self.badXMLRPCFaultCode, + str(e)) + ) except: # report exception back to server response = xmlrpclib.dumps( - xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)) + xmlrpclib.Fault(self.defaultFaultCode, + "%s:%s" % (sys.exc_type, sys.exc_value)) ) return response @@ -297,6 +328,15 @@ # See http://xmlrpc.usefulinc.com/doc/sysmethodsig.html return 'signatures not supported' + + def system_getCapabilities(self): + """system.getCapabilities() => + {'faults_interop': {'specVersion': '20010516', + 'specurl': 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php'}} + + Returns the specifications implemented by this XMLRPC listener. + """ + return self.capabilities def system_methodHelp(self, method_name): """system.methodHelp('add') => "Adds two integers together" @@ -354,9 +394,19 @@ {'faultCode' : fault.faultCode, 'faultString' : fault.faultString} ) + except xmlrpclib.ParseError, e: + results.append( + {'faultCode' : self.badXMLFaultCode, + 'faultString': str(e)} + ) + except xmlrpclib.ResponseError, e: + reslts.append( + {'faultCode': self.badXMLRPCFaultCode, + 'faultString': str(e)} + ) except: results.append( - {'faultCode' : 1, + {'faultCode' : self.defaultFaultCode, 'faultString' : "%s:%s" % (sys.exc_type, sys.exc_value)} ) return results @@ -405,7 +455,8 @@ if func is not None: return func(*params) else: - raise Exception('method "%s" is not supported' % method) + raise Fault(self.unknownMethodFaultCode, + 'method "%s" is not supported' % method) class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """Simple XML-RPC request handler class. @@ -531,6 +582,8 @@ if __name__ == '__main__': server = SimpleXMLRPCServer(("localhost", 8000)) + server.register_introspection_functions() + server.register_fault_interop_spec() server.register_function(pow) server.register_function(lambda x,y: x+y, 'add') server.serve_forever() diff -ruN virgin/xmlrpclib.py patched/xmlrpclib.py --- virgin/xmlrpclib.py 2005-11-17 21:54:12.000000000 -0500 +++ patched/xmlrpclib.py 2005-11-17 22:35:15.000000000 -0500 @@ -49,6 +49,7 @@ # 2003-07-12 gp Correct marshalling of Faults # 2003-10-31 mvl Add multicall support # 2004-08-20 mvl Bump minimum supported Python version to 2.1 +# 2005-11-17 jag Added error handling for better fault interoperability # # Copyright (c) 1999-2002 by Secret Labs AB. # Copyright (c) 1999-2002 by Fredrik Lundh. @@ -136,7 +137,7 @@ name (None if not present). """ -import re, string, time, operator +import re, string, time, operator, sys from types import * @@ -246,6 +247,14 @@ pass ## +# Indicates malformed XML. This exception is raised by the +# unmarshalling layer if the XML is not well-formed. + +class ParseError(Error): + """Indicates that the XML being loaded is not well-formed.""" + pass + +## # Indicates an XML-RPC fault response package. This exception is # raised by the unmarshalling layer, if the XML-RPC response contains # a fault string. This exception can also used as a class, to @@ -1076,11 +1085,14 @@ raises a Fault exception. """ p, u = getparser() - p.feed(data) + try: + p.feed(data) + except Exception, e: + error_msg = "%s:%s" % (sys.exc_type, sys.exc_value) + raise ParseError, error_msg p.close() return u.close(), u.getmethodname() - # -------------------------------------------------------------------- # request dispatcher