From 8fa79ba27ddbd67dad797a3d551f27243e88cdd1 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 30 Sep 2011 14:55:38 +0200 Subject: [PATCH] [IMP] xmlrpc: handle exceptions with isinstance instead of re-raising them, use the openerp xml-rpc protocol version 1 path, return an xmlrpclib Fault when the request is wrong. bzr revid: vmt@openerp.com-20110930125538-8mo5tqdmjbb88fa8 --- openerp/wsgi.py | 53 +++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/openerp/wsgi.py b/openerp/wsgi.py index b334c72b3ef..36d9f252f32 100644 --- a/openerp/wsgi.py +++ b/openerp/wsgi.py @@ -47,6 +47,7 @@ import service.websrv_lib as websrv_lib # constants are also defined client-side and must remain in sync. # User code must use the exceptions defined in ``openerp.exceptions`` (not # create directly ``xmlrpclib.Fault`` objects). +XML_RPC_FAULT_CODE_CLIENT_ERROR = 1 # again, indistinguishable from app. error. XML_RPC_FAULT_CODE_APPLICATION_ERROR = 1 # Unused, deferred errors are indistinguishable from normal application # errors. We keep them so we can use the word 'indistinguishable' twice @@ -56,6 +57,12 @@ XML_RPC_FAULT_CODE_ACCESS_DENIED = 3 XML_RPC_FAULT_CODE_ACCESS_ERROR = 4 XML_RPC_FAULT_CODE_WARNING = 5 +# The new (6.1) versioned RPC paths. +XML_RPC_PATH = '/openerp/xmlrpc' +XML_RPC_PATH_1 = '/openerp/xmlrpc/1' +JSON_RPC_PATH = '/openerp/jsonrpc' +JSON_RPC_PATH_1 = '/openerp/jsonrpc/1' + def xmlrpc_return(start_response, service, method, params, legacy_exceptions=False): """ Helper to call a service's method with some params, using a wsgi-supplied @@ -82,28 +89,26 @@ def xmlrpc_return(start_response, service, method, params, legacy_exceptions=Fal return [response] def xmlrpc_handle_exception(e): - try: - raise e - except openerp.osv.osv.except_osv, e: # legacy + if isinstance(e, openerp.osv.osv.except_osv): # legacy fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_WARNING, openerp.tools.ustr(e.value)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.Warning, e: + elif isinstance(e, openerp.exceptions.Warning): fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_WARNING, str(e)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.AccessError, e: + elif isinstance (e, openerp.exceptions.AccessError): fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_ACCESS_ERROR, str(e)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.AccessDenied, e: + elif isinstance(e, openerp.exceptions.AccessDenied): fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_ACCESS_DENIED, str(e)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.DeferredException, e: + elif isinstance(e, openerp.exceptions.DeferredException): info = e.traceback # Which one is the best ? formatted_info = "".join(traceback.format_exception(*info)) #formatted_info = openerp.tools.exception_to_unicode(e) + '\n' + info fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_APPLICATION_ERROR, formatted_info) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except Exception, e: + else: if hasattr(e, 'message') and e.message == 'AccessDenied': # legacy fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_ACCESS_DENIED, str(e)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) @@ -117,26 +122,24 @@ def xmlrpc_handle_exception(e): return response def xmlrpc_handle_exception_legacy(e): - try: - raise e - except openerp.osv.osv.except_osv, e: + if isinstance(e, openerp.osv.osv.except_osv): fault = xmlrpclib.Fault('warning -- ' + e.name + '\n\n' + e.value, '') response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.Warning, e: + elif isinstance(e, openerp.exceptions.Warning): fault = xmlrpclib.Fault('warning -- Warning\n\n' + str(e), '') response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.AccessError, e: + elif isinstance(e, openerp.exceptions.AccessError): fault = xmlrpclib.Fault('warning -- AccessError\n\n' + str(e), '') response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.AccessDenied, e: + elif isinstance(e, openerp.exceptions.AccessDenied): fault = xmlrpclib.Fault('AccessDenied', str(e)) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except openerp.exceptions.DeferredException, e: + elif isinstance(e, openerp.exceptions.DeferredException): info = e.traceback formatted_info = "".join(traceback.format_exception(*info)) fault = xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info) response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) - except Exception, e: + else: info = sys.exc_info() formatted_info = "".join(traceback.format_exception(*info)) fault = xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info) @@ -145,13 +148,13 @@ def xmlrpc_handle_exception_legacy(e): def wsgi_xmlrpc(environ, start_response): """ The main OpenERP WSGI handler.""" - if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/openerp/6.1/xmlrpc'): + if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith(XML_RPC_PATH_1): length = int(environ['CONTENT_LENGTH']) data = environ['wsgi.input'].read(length) params, method = xmlrpclib.loads(data) - path = environ['PATH_INFO'][len('/openerp/6.1/xmlrpc'):] + path = environ['PATH_INFO'][len(XML_RPC_PATH_1):] if path.startswith('/'): path = path[1:] if path.endswith('/'): p = path[:-1] path = path.split('/') @@ -172,11 +175,19 @@ def wsgi_xmlrpc(environ, start_response): service, db_name = path params = (db_name,) + params - if service == 'model': - service = 'object' return xmlrpc_return(start_response, service, method, params) - # TODO the body has been read, need to raise an exception (not return None). + # A db segment and a model segment must be given. + elif len(path) == 3 and path[0] == 'model': + service, db_name, model_name = path + params = (db_name,) + params[:2] + (model_name,) + params[2:] + service = 'object' + return xmlrpc_return(start_response, service, method, params) + + # The body has been read, need to raise an exception (not return None). + fault = xmlrpclib.Fault(XML_RPC_FAULT_CODE_CLIENT_ERROR, '') + response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) + return response def legacy_wsgi_xmlrpc(environ, start_response): if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/xmlrpc/'):