[FIX] http,ir.http: refactor exception handling to allow request-specific handling
authorOlivier Dony <odo@openerp.com>
Fri, 28 Mar 2014 14:27:48 +0000 (15:27 +0100)
committerOlivier Dony <odo@openerp.com>
Fri, 28 Mar 2014 14:27:48 +0000 (15:27 +0100)
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
openerp/http.py

index 93dc4d8..bd211d1 100644 (file)
@@ -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
index 61c9092..24f538f 100644 (file)
@@ -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 = {