summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Motejlek <petr@motejlek.net>2017-03-01 17:21:28 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2017-03-01 17:21:28 (GMT)
commit3c6314c08d8ab1cfefbf6c2e27c095a7d4ba5f6e (patch)
treedd7b4ce05680b683cd882798a3fc42e6bd8b2069
parentda62373b0d32c14a4137512ef6f13c24fbcaa2c1 (diff)
downloadcpython-3c6314c08d8ab1cfefbf6c2e27c095a7d4ba5f6e.zip
cpython-3c6314c08d8ab1cfefbf6c2e27c095a7d4ba5f6e.tar.gz
cpython-3c6314c08d8ab1cfefbf6c2e27c095a7d4ba5f6e.tar.bz2
bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (#260)
(or any other exception) to exception(s) raised in the dispatched methods. Patch by Petr Motejlek.
-rw-r--r--Lib/test/test_xmlrpc.py90
-rw-r--r--Lib/xmlrpc/server.py43
-rw-r--r--Misc/NEWS4
3 files changed, 117 insertions, 20 deletions
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index ef8ad21..57a1efc 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -343,6 +343,94 @@ class XMLRPCTestCase(unittest.TestCase):
self.assertEqual(p.method(), 5)
self.assertEqual(p.method(), 5)
+
+class SimpleXMLRPCDispatcherTestCase(unittest.TestCase):
+ class DispatchExc(Exception):
+ """Raised inside the dispatched functions when checking for
+ chained exceptions"""
+
+ def test_call_registered_func(self):
+ """Calls explicitly registered function"""
+ # Makes sure any exception raised inside the function has no other
+ # exception chained to it
+
+ exp_params = 1, 2, 3
+
+ def dispatched_func(*params):
+ raise self.DispatchExc(params)
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_function(dispatched_func)
+ with self.assertRaises(self.DispatchExc) as exc_ctx:
+ dispatcher._dispatch('dispatched_func', exp_params)
+ self.assertEqual(exc_ctx.exception.args, (exp_params,))
+ self.assertIsNone(exc_ctx.exception.__cause__)
+ self.assertIsNone(exc_ctx.exception.__context__)
+
+ def test_call_instance_func(self):
+ """Calls a registered instance attribute as a function"""
+ # Makes sure any exception raised inside the function has no other
+ # exception chained to it
+
+ exp_params = 1, 2, 3
+
+ class DispatchedClass:
+ def dispatched_func(self, *params):
+ raise SimpleXMLRPCDispatcherTestCase.DispatchExc(params)
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_instance(DispatchedClass())
+ with self.assertRaises(self.DispatchExc) as exc_ctx:
+ dispatcher._dispatch('dispatched_func', exp_params)
+ self.assertEqual(exc_ctx.exception.args, (exp_params,))
+ self.assertIsNone(exc_ctx.exception.__cause__)
+ self.assertIsNone(exc_ctx.exception.__context__)
+
+ def test_call_dispatch_func(self):
+ """Calls the registered instance's `_dispatch` function"""
+ # Makes sure any exception raised inside the function has no other
+ # exception chained to it
+
+ exp_method = 'method'
+ exp_params = 1, 2, 3
+
+ class TestInstance:
+ def _dispatch(self, method, params):
+ raise SimpleXMLRPCDispatcherTestCase.DispatchExc(
+ method, params)
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_instance(TestInstance())
+ with self.assertRaises(self.DispatchExc) as exc_ctx:
+ dispatcher._dispatch(exp_method, exp_params)
+ self.assertEqual(exc_ctx.exception.args, (exp_method, exp_params))
+ self.assertIsNone(exc_ctx.exception.__cause__)
+ self.assertIsNone(exc_ctx.exception.__context__)
+
+ def test_registered_func_is_none(self):
+ """Calls explicitly registered function which is None"""
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_function(None, name='method')
+ with self.assertRaises(Exception, expected_regex='method'):
+ dispatcher._dispatch('method', ('param',))
+
+ def test_instance_has_no_func(self):
+ """Attempts to call nonexistent function on a registered instance"""
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_instance(object())
+ with self.assertRaises(Exception, expected_regex='method'):
+ dispatcher._dispatch('method', ('param',))
+
+ def test_cannot_locate_func(self):
+ """Calls a function that the dispatcher cannot locate"""
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ with self.assertRaises(Exception, expected_regex='method'):
+ dispatcher._dispatch('method', ('param',))
+
+
class HelperTestCase(unittest.TestCase):
def test_escape(self):
self.assertEqual(xmlrpclib.escape("a&b"), "a&amp;b")
@@ -1313,7 +1401,7 @@ def test_main():
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
GzipServerTestCase, GzipUtilTestCase,
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
- CGIHandlerTestCase)
+ CGIHandlerTestCase, SimpleXMLRPCDispatcherTestCase)
if __name__ == "__main__":
diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py
index a6275a1..bb86fe6 100644
--- a/Lib/xmlrpc/server.py
+++ b/Lib/xmlrpc/server.py
@@ -392,31 +392,36 @@ class SimpleXMLRPCDispatcher:
not be called.
"""
- func = None
try:
- # check to see if a matching function has been registered
+ # call the matching registered function
func = self.funcs[method]
except KeyError:
- if self.instance is not None:
- # check for a _dispatch method
- if hasattr(self.instance, '_dispatch'):
- return self.instance._dispatch(method, params)
- else:
- # call instance method directly
- try:
- func = resolve_dotted_attribute(
- self.instance,
- method,
- self.allow_dotted_names
- )
- except AttributeError:
- pass
-
- if func is not None:
- return func(*params)
+ pass
else:
+ if func is not None:
+ return func(*params)
raise Exception('method "%s" is not supported' % method)
+ if self.instance is not None:
+ if hasattr(self.instance, '_dispatch'):
+ # call the `_dispatch` method on the instance
+ return self.instance._dispatch(method, params)
+
+ # call the instance's method directly
+ try:
+ func = resolve_dotted_attribute(
+ self.instance,
+ method,
+ self.allow_dotted_names
+ )
+ except AttributeError:
+ pass
+ else:
+ if func is not None:
+ return func(*params)
+
+ raise Exception('method "%s" is not supported' % method)
+
class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
"""Simple XML-RPC request handler class.
diff --git a/Misc/NEWS b/Misc/NEWS
index 6af6601..d2280ab 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -253,6 +253,10 @@ Extension Modules
Library
-------
+- bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other
+ exception) to exception(s) raised in the dispatched methods.
+ Patch by Petr Motejlek.
+
- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCDispatcher
and its subclasses can now be used as a decorator.