[Core] Raise AttributeError on RPC call to invalid function

Also catch and log errors in rcpserver.sendData
This commit is contained in:
bendikro 2015-07-13 18:15:16 +02:00 committed by Calum Lind
parent 382a99ad61
commit a987c3ed39
3 changed files with 83 additions and 37 deletions

View File

@ -142,7 +142,12 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
:type data: object
"""
try:
self.transfer_message(data)
except Exception as ex:
log.warn("Error occurred when sending message: %s.", ex)
log.exception(ex)
raise
def connectionMade(self): # NOQA
"""
@ -215,7 +220,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
"send(causing exception goes next):\n%s", formated_tb)
try:
raise WrappedException(str(exceptionValue), exceptionType.__name__, formated_tb)
except Exception:
except WrappedException:
send_error()
except Exception as ex:
log.error("An exception occurred while sending RPC_ERROR to client: %s", ex)
@ -245,7 +250,12 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
if not ret:
self.transport.loseConnection()
return
elif method == "daemon.set_event_interest" and self.valid_session():
# Anything below requires a valid session
if not self.valid_session():
return
if method == "daemon.set_event_interest":
log.debug("RPC dispatch daemon.set_event_interest")
# This special case is to allow clients to set which events they are
# interested in receiving.
@ -260,15 +270,22 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
self.sendData((RPC_RESPONSE, request_id, (True)))
return
if method in self.factory.methods and self.valid_session():
if method not in self.factory.methods:
try:
# Raise exception to be sent back to client
raise AttributeError("RPC call on invalid function '%s'." % method)
except AttributeError:
send_error()
return
log.debug("RPC dispatch %s", method)
try:
method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
if auth_level < method_auth_requirement:
# This session is not allowed to call this method
log.debug("Session %s is trying to call a method it is not "
"authorized to call!", self.transport.sessionno)
log.debug("Session %s is attempting an unauthorized method call!",
self.transport.sessionno)
raise NotAuthorizedError(auth_level, method_auth_requirement)
# Set the session_id in the factory so that methods can know
# which session is calling it.
@ -285,7 +302,10 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
# wait for it to fire before sending the RPC_RESPONSE
if isinstance(ret, defer.Deferred):
def on_success(result):
try:
self.sendData((RPC_RESPONSE, request_id, result))
except Exception:
send_error()
return result
def on_fail(failure):

View File

@ -144,6 +144,22 @@ class ClientTestCase(BaseTestCase):
d.addErrback(on_failure)
return d
@defer.inlineCallbacks
def test_invalid_rpc_method_call(self):
yield client.connect(
"localhost", self.listen_port, username="", password=""
)
d = client.core.invalid_method()
def on_failure(failure):
self.assertEqual(
failure.trap(error.WrappedException),
error.WrappedException
)
self.addCleanup(client.disconnect)
d.addErrback(on_failure)
yield d
def test_connect_without_sending_client_version_fails(self):
username, password = deluge.ui.common.get_localhost_auth()
no_version_sending_client = NoVersionSendingClient()

View File

@ -78,7 +78,7 @@ class RPCServerTestCase(BaseTestCase):
def test_client_login_error(self):
# This test causes error log prints while running the test...
self.protocol.transport = None # This should causes AttributeError
self.protocol.transport = None # This should cause AttributeError
self.authmanager = AuthManager()
auth = get_localhost_auth()
self.protocol.dispatch(self.request_id, "daemon.login", auth, {"client_version": "Test"})
@ -88,6 +88,16 @@ class RPCServerTestCase(BaseTestCase):
self.assertEquals(msg[2], "WrappedException")
self.assertEquals(msg[3][1], "AttributeError")
def test_client_invalid_method_call(self):
self.authmanager = AuthManager()
auth = get_localhost_auth()
self.protocol.dispatch(self.request_id, "invalid_function", auth, {})
msg = self.protocol.messages.pop()
self.assertEquals(msg[0], rpcserver.RPC_ERROR)
self.assertEquals(msg[1], self.request_id)
self.assertEquals(msg[2], "WrappedException")
self.assertEquals(msg[3][1], "AttributeError")
def test_daemon_info(self):
self.protocol.dispatch(self.request_id, "daemon.info", [], {})
msg = self.protocol.messages.pop()