diff --git a/odoo/service/wsgi_server.py b/odoo/service/wsgi_server.py index ec699dc13e0..95276f336b1 100644 --- a/odoo/service/wsgi_server.py +++ b/odoo/service/wsgi_server.py @@ -12,12 +12,15 @@ import sys import threading import traceback + try: from xmlrpc import client as xmlrpclib except ImportError: # pylint: disable=bad-python3-import import xmlrpclib +import werkzeug.exceptions +import werkzeug.wrappers import werkzeug.serving import werkzeug.contrib.fixers @@ -36,90 +39,54 @@ RPC_FAULT_CODE_WARNING = 2 RPC_FAULT_CODE_ACCESS_DENIED = 3 RPC_FAULT_CODE_ACCESS_ERROR = 4 -def xmlrpc_return(start_response, service, method, params, string_faultcode=False): - """ - Helper to call a service's method with some params, using a wsgi-supplied - ``start_response`` callback. - - This is the place to look at to see the mapping between core exceptions - and XML-RPC fault codes. - """ - # Map OpenERP core exceptions to XML-RPC fault codes. Specific exceptions - # defined in ``odoo.exceptions`` are mapped to specific fault codes; - # all the other exceptions are mapped to the generic - # RPC_FAULT_CODE_APPLICATION_ERROR value. - # This also mimics SimpleXMLRPCDispatcher._marshaled_dispatch() for - # exception handling. - try: - result = odoo.http.dispatch_rpc(service, method, params) - response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None) - except Exception as e: - if string_faultcode: - response = xmlrpc_handle_exception_string(e) - else: - response = xmlrpc_handle_exception_int(e) - start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))]) - return [response] - def xmlrpc_handle_exception_int(e): if isinstance(e, odoo.exceptions.UserError): fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING, odoo.tools.ustr(e.value)) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.RedirectWarning): fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING, str(e)) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.MissingError): fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING, str(e)) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance (e, odoo.exceptions.AccessError): fault = xmlrpclib.Fault(RPC_FAULT_CODE_ACCESS_ERROR, str(e)) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.AccessDenied): fault = xmlrpclib.Fault(RPC_FAULT_CODE_ACCESS_DENIED, str(e)) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.DeferredException): info = e.traceback # Which one is the best ? formatted_info = "".join(traceback.format_exception(*info)) #formatted_info = odoo.tools.exception_to_unicode(e) + '\n' + info fault = xmlrpclib.Fault(RPC_FAULT_CODE_APPLICATION_ERROR, formatted_info) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) else: info = sys.exc_info() # Which one is the best ? formatted_info = "".join(traceback.format_exception(*info)) #formatted_info = odoo.tools.exception_to_unicode(e) + '\n' + info fault = xmlrpclib.Fault(RPC_FAULT_CODE_APPLICATION_ERROR, formatted_info) - response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) - return response + + return xmlrpclib.dumps(fault, allow_none=None) def xmlrpc_handle_exception_string(e): if isinstance(e, odoo.exceptions.UserError): fault = xmlrpclib.Fault('warning -- %s\n\n%s' % (e.name, e.value), '') - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.RedirectWarning): fault = xmlrpclib.Fault('warning -- Warning\n\n' + str(e), '') elif isinstance(e, odoo.exceptions.MissingError): fault = xmlrpclib.Fault('warning -- MissingError\n\n' + str(e), '') - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.AccessError): fault = xmlrpclib.Fault('warning -- AccessError\n\n' + str(e), '') - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.AccessDenied): fault = xmlrpclib.Fault('AccessDenied', str(e)) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) elif isinstance(e, odoo.exceptions.DeferredException): info = e.traceback formatted_info = "".join(traceback.format_exception(*info)) fault = xmlrpclib.Fault(odoo.tools.ustr(e), formatted_info) - response = xmlrpclib.dumps(fault, allow_none=False, encoding=None) #InternalError else: info = sys.exc_info() formatted_info = "".join(traceback.format_exception(*info)) fault = xmlrpclib.Fault(odoo.tools.exception_to_unicode(e), formatted_info) - response = xmlrpclib.dumps(fault, allow_none=None, encoding=None) - return response + + return xmlrpclib.dumps(fault, allow_none=None, encoding=None) def wsgi_xmlrpc(environ, start_response): """ Two routes are available for XML-RPC @@ -136,14 +103,25 @@ def wsgi_xmlrpc(environ, start_response): # Distinguish betweed the 2 faultCode modes string_faultcode = True + service = environ['PATH_INFO'][len('/xmlrpc/'):] if environ['PATH_INFO'].startswith('/xmlrpc/2/'): - service = environ['PATH_INFO'][len('/xmlrpc/2/'):] + service = service[len('2/'):] string_faultcode = False - else: - service = environ['PATH_INFO'][len('/xmlrpc/'):] params, method = xmlrpclib.loads(data) - return xmlrpc_return(start_response, service, method, params, string_faultcode) + try: + result = odoo.http.dispatch_rpc(service, method, params) + response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False) + except Exception as e: + if string_faultcode: + response = xmlrpc_handle_exception_string(e) + else: + response = xmlrpc_handle_exception_int(e) + + return werkzeug.wrappers.Response( + response=response, + mimetype='text/xml', + )(environ, start_response) def application_unproxied(environ, start_response): """ WSGI entry point.""" @@ -168,9 +146,7 @@ def application_unproxied(environ, start_response): return result # We never returned from the loop. - response = 'No handler found.\n' - start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(response)))]) - return [response] + return werkzeug.exceptions.NotFound("No handler found.\n")(environ, start_response) def application(environ, start_response): if config['proxy_mode'] and 'HTTP_X_FORWARDED_HOST' in environ: