From 8809c77f6088c140355fba5f862c0335b1d90c4e Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 28 Mar 2014 15:27:48 +0100 Subject: [PATCH] [FIX] http,ir.http: refactor exception handling to allow request-specific handling Typically an exception during a JSON-RPC request must be handled specifically and return a JSON-RPC error in all cases. Previously the _authenticate() step could fail during ir_http.dispatch() and bubble up to werkzeug, yielding a dumb "Internal Server Error 500" even for a JSON-RPC request. bzr revid: odo@openerp.com-20140328142748-00haplmkc3fv6f9y --- openerp/addons/base/ir/ir_http.py | 4 +- openerp/http.py | 79 ++++++++++++++++++------------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py index 93dc4d84e76..bd211d14cb8 100644 --- a/openerp/addons/base/ir/ir_http.py +++ b/openerp/addons/base/ir/ir_http.py @@ -85,8 +85,8 @@ class ir_http(osv.AbstractModel): return auth_method def _handle_exception(self, exception): - # If handle exception return something different than None, it will be used as a response - raise + # If handle_exception returns something different than None, it will be used as a response + return request._handle_exception(exception) def _dispatch(self): # locate the controller method diff --git a/openerp/http.py b/openerp/http.py index 61c90929aa2..24f538f3828 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -202,6 +202,13 @@ class WebRequest(object): self.func_arguments = arguments self.auth_method = auth + + def _handle_exception(self, exception): + """Called within an except block to allow converting exceptions + to abitrary responses. Anything returned (except None) will + be used as response.""" + raise + def _call_function(self, *args, **kwargs): request = self if self.func_request_type != self._request_type: @@ -338,37 +345,15 @@ class JsonRequest(WebRequest): self.params = dict(self.jsonrequest.get("params", {})) self.context = self.params.pop('context', dict(self.session.context)) - def dispatch(self): - """ Calls the method asked for by the JSON-RPC2 or JSONP request - """ - if self.jsonp_handler: - return self.jsonp_handler() - response = {"jsonrpc": "2.0" } - error = None - - try: - response['id'] = self.jsonrequest.get('id') - response["result"] = self._call_function(**self.params) - except AuthenticationError, e: - _logger.exception("Exception during JSON request handling.") - se = serialize_exception(e) - error = { - 'code': 100, - 'message': "OpenERP Session Invalid", - 'data': se - } - self._failed = e # prevent tx commit - except Exception, e: - _logger.exception("Exception during JSON request handling.") - se = serialize_exception(e) - error = { - 'code': 200, - 'message': "OpenERP Server Error", - 'data': se - } - self._failed = e # prevent tx commit - if error: - response["error"] = error + def _json_response(self, result=None, error=None): + response = { + 'jsonrpc': '2.0', + 'id': self.jsonrequest.get('id') + } + if error is not None: + response['error'] = error + if result is not None: + response['result'] = result if self.jsonp: # If we use jsonp, that's mean we are called from another host @@ -381,8 +366,36 @@ class JsonRequest(WebRequest): mime = 'application/json' body = simplejson.dumps(response) - r = werkzeug.wrappers.Response(body, headers=[('Content-Type', mime), ('Content-Length', len(body))]) - return r + return werkzeug.wrappers.Response( + body, headers=[('Content-Type', mime), + ('Content-Length', len(body))]) + + def _handle_exception(self, exception): + """Called within an except block to allow converting exceptions + to abitrary responses. Anything returned (except None) will + be used as response.""" + _logger.exception("Exception during JSON request handling.") + self._failed = exception # prevent tx commit + error = { + 'code': 200, + 'message': "OpenERP Server Error", + 'data': serialize_exception(exception) + } + if isinstance(exception, AuthenticationError): + error['code'] = 100 + error['message'] = "OpenERP Session Invalid" + return self._json_response(error=error) + + def dispatch(self): + """ Calls the method asked for by the JSON-RPC2 or JSONP request + """ + if self.jsonp_handler: + return self.jsonp_handler() + try: + result = self._call_function(**self.params) + return self._json_response(result) + except Exception, e: + return self._handle_exception(e) def serialize_exception(e): tmp = {