[#2724] [Web] Forward exceptions in JSON-RPC back to caller

Exceptions raised by calls performed by a JSON request would
not always be handled properly resulting in no reply to be sent
leading to browser timeouts.

Fix this by including the raised error in the JSON data of a
regular (successful) HTTP response.
This commit is contained in:
bendikro 2015-12-15 18:26:50 +01:00
parent 93023c5bfc
commit 533951afea
1 changed files with 26 additions and 18 deletions

View File

@ -18,7 +18,7 @@ import time
from types import FunctionType
from urllib import unquote_plus
from twisted.internet import reactor
from twisted.internet import defer, reactor
from twisted.internet.defer import Deferred, DeferredList
from twisted.web import http, resource, server
@ -91,20 +91,18 @@ class JSON(resource.Resource, component.Component):
self._local_methods = {}
if client.is_classicmode():
self.get_remote_methods()
else:
client.disconnect_callback = self._on_client_disconnect
def on_get_methods(self, methods):
"""
Handles receiving the method names.
"""
self._remote_methods = methods
def get_remote_methods(self, result=None):
"""
Updates remote methods from the daemon.
Returns:
t.i.d.Deferred: A deferred returning the available remote methods
"""
return client.daemon.get_method_list().addCallback(self.on_get_methods)
def on_get_methods(methods):
self._remote_methods = methods
return methods
return client.daemon.get_method_list().addCallback(on_get_methods)
def connect(self, host="localhost", port=58846, username="", password=""):
"""
@ -127,8 +125,11 @@ class JSON(resource.Resource, component.Component):
def disable(self):
if not client.is_classicmode():
client.disconnect()
client.set_disconnect_callback(None)
def enable(self):
if not client.is_classicmode():
client.set_disconnect_callback(self._on_client_disconnect)
client.register_event_handler("PluginEnabledEvent", self.get_remote_methods)
client.register_event_handler("PluginDisabledEvent", self.get_remote_methods)
if component.get("DelugeWeb").config["default_daemon"]:
@ -203,8 +204,7 @@ class JSON(resource.Resource, component.Component):
except Exception as ex:
log.error("Error calling method `%s`", method)
log.exception(ex)
error = {"message": ex.message, "code": 3}
error = {"message": "%s: %s" % (ex.__class__.__name__, str(ex)), "code": 3}
return request_id, result, error
@ -219,8 +219,9 @@ class JSON(resource.Resource, component.Component):
"""
Handles any failures that occurred while making an rpc call.
"""
request.setResponseCode(http.INTERNAL_SERVER_ERROR)
return ""
log.exception(reason)
response["error"] = {"message": "%s: %s" % (reason.__class__.__name__, str(reason)), "code": 4}
return self._send_response(request, response)
def _on_json_request(self, request):
"""
@ -241,13 +242,17 @@ class JSON(resource.Resource, component.Component):
def _on_json_request_failed(self, reason, request):
"""
Errback handler to return a HTTP code of 500.
Returns the error in json response.
"""
log.exception(reason)
request.setResponseCode(http.INTERNAL_SERVER_ERROR)
return ""
response = {"result": None, "id": None,
"error": {"code": 5,
"message": "%s: %s" % (reason.__class__.__name__, str(reason))}}
return self._send_response(request, response)
def _send_response(self, request, response):
if request._disconnected:
return ""
response = json.dumps(response)
request.setHeader("content-type", "application/x-json")
request.write(compress(response, request))
@ -260,7 +265,8 @@ class JSON(resource.Resource, component.Component):
if request.method != "POST":
request.setResponseCode(http.NOT_ALLOWED)
return ""
request.finish()
return server.NOT_DONE_YET
try:
request.content.seek(0)
@ -453,6 +459,8 @@ class WebApi(JSONComponent):
host = self.get_host(host_id)
if host:
self._json.connect(*host[1:]).addCallback(on_connected)
else:
return defer.fail(Exception("Bad host id"))
return d
@export