Skip to content

Commit 3c6314c

Browse files
petr-motejlekserhiy-storchaka
authored andcommitted
bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (#260)
(or any other exception) to exception(s) raised in the dispatched methods. Patch by Petr Motejlek.
1 parent da62373 commit 3c6314c

File tree

3 files changed

+117
-20
lines changed

3 files changed

+117
-20
lines changed

Lib/test/test_xmlrpc.py

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,94 @@ def run_server():
343343
self.assertEqual(p.method(), 5)
344344
self.assertEqual(p.method(), 5)
345345

346+
347+
class SimpleXMLRPCDispatcherTestCase(unittest.TestCase):
348+
class DispatchExc(Exception):
349+
"""Raised inside the dispatched functions when checking for
350+
chained exceptions"""
351+
352+
def test_call_registered_func(self):
353+
"""Calls explicitly registered function"""
354+
# Makes sure any exception raised inside the function has no other
355+
# exception chained to it
356+
357+
exp_params = 1, 2, 3
358+
359+
def dispatched_func(*params):
360+
raise self.DispatchExc(params)
361+
362+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
363+
dispatcher.register_function(dispatched_func)
364+
with self.assertRaises(self.DispatchExc) as exc_ctx:
365+
dispatcher._dispatch('dispatched_func', exp_params)
366+
self.assertEqual(exc_ctx.exception.args, (exp_params,))
367+
self.assertIsNone(exc_ctx.exception.__cause__)
368+
self.assertIsNone(exc_ctx.exception.__context__)
369+
370+
def test_call_instance_func(self):
371+
"""Calls a registered instance attribute as a function"""
372+
# Makes sure any exception raised inside the function has no other
373+
# exception chained to it
374+
375+
exp_params = 1, 2, 3
376+
377+
class DispatchedClass:
378+
def dispatched_func(self, *params):
379+
raise SimpleXMLRPCDispatcherTestCase.DispatchExc(params)
380+
381+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
382+
dispatcher.register_instance(DispatchedClass())
383+
with self.assertRaises(self.DispatchExc) as exc_ctx:
384+
dispatcher._dispatch('dispatched_func', exp_params)
385+
self.assertEqual(exc_ctx.exception.args, (exp_params,))
386+
self.assertIsNone(exc_ctx.exception.__cause__)
387+
self.assertIsNone(exc_ctx.exception.__context__)
388+
389+
def test_call_dispatch_func(self):
390+
"""Calls the registered instance's `_dispatch` function"""
391+
# Makes sure any exception raised inside the function has no other
392+
# exception chained to it
393+
394+
exp_method = 'method'
395+
exp_params = 1, 2, 3
396+
397+
class TestInstance:
398+
def _dispatch(self, method, params):
399+
raise SimpleXMLRPCDispatcherTestCase.DispatchExc(
400+
method, params)
401+
402+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
403+
dispatcher.register_instance(TestInstance())
404+
with self.assertRaises(self.DispatchExc) as exc_ctx:
405+
dispatcher._dispatch(exp_method, exp_params)
406+
self.assertEqual(exc_ctx.exception.args, (exp_method, exp_params))
407+
self.assertIsNone(exc_ctx.exception.__cause__)
408+
self.assertIsNone(exc_ctx.exception.__context__)
409+
410+
def test_registered_func_is_none(self):
411+
"""Calls explicitly registered function which is None"""
412+
413+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
414+
dispatcher.register_function(None, name='method')
415+
with self.assertRaises(Exception, expected_regex='method'):
416+
dispatcher._dispatch('method', ('param',))
417+
418+
def test_instance_has_no_func(self):
419+
"""Attempts to call nonexistent function on a registered instance"""
420+
421+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
422+
dispatcher.register_instance(object())
423+
with self.assertRaises(Exception, expected_regex='method'):
424+
dispatcher._dispatch('method', ('param',))
425+
426+
def test_cannot_locate_func(self):
427+
"""Calls a function that the dispatcher cannot locate"""
428+
429+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
430+
with self.assertRaises(Exception, expected_regex='method'):
431+
dispatcher._dispatch('method', ('param',))
432+
433+
346434
class HelperTestCase(unittest.TestCase):
347435
def test_escape(self):
348436
self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
@@ -1313,7 +1401,7 @@ def test_main():
13131401
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
13141402
GzipServerTestCase, GzipUtilTestCase,
13151403
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
1316-
CGIHandlerTestCase)
1404+
CGIHandlerTestCase, SimpleXMLRPCDispatcherTestCase)
13171405

13181406

13191407
if __name__ == "__main__":

Lib/xmlrpc/server.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -392,31 +392,36 @@ def _dispatch(self, method, params):
392392
not be called.
393393
"""
394394

395-
func = None
396395
try:
397-
# check to see if a matching function has been registered
396+
# call the matching registered function
398397
func = self.funcs[method]
399398
except KeyError:
400-
if self.instance is not None:
401-
# check for a _dispatch method
402-
if hasattr(self.instance, '_dispatch'):
403-
return self.instance._dispatch(method, params)
404-
else:
405-
# call instance method directly
406-
try:
407-
func = resolve_dotted_attribute(
408-
self.instance,
409-
method,
410-
self.allow_dotted_names
411-
)
412-
except AttributeError:
413-
pass
414-
415-
if func is not None:
416-
return func(*params)
399+
pass
417400
else:
401+
if func is not None:
402+
return func(*params)
418403
raise Exception('method "%s" is not supported' % method)
419404

405+
if self.instance is not None:
406+
if hasattr(self.instance, '_dispatch'):
407+
# call the `_dispatch` method on the instance
408+
return self.instance._dispatch(method, params)
409+
410+
# call the instance's method directly
411+
try:
412+
func = resolve_dotted_attribute(
413+
self.instance,
414+
method,
415+
self.allow_dotted_names
416+
)
417+
except AttributeError:
418+
pass
419+
else:
420+
if func is not None:
421+
return func(*params)
422+
423+
raise Exception('method "%s" is not supported' % method)
424+
420425
class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
421426
"""Simple XML-RPC request handler class.
422427

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ Extension Modules
253253
Library
254254
-------
255255

256+
- bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other
257+
exception) to exception(s) raised in the dispatched methods.
258+
Patch by Petr Motejlek.
259+
256260
- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCDispatcher
257261
and its subclasses can now be used as a decorator.
258262

0 commit comments

Comments
 (0)