From af20aea88c13cb2ff255dbcc1bed50cba452423f Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 26 Dec 2009 10:16:56 +0000 Subject: [PATCH] 2009-12-26 Tatsuhiro Tsujikawa Added system.multicall XML-RPC method. * src/XmlRpcMethod.cc * src/XmlRpcMethod.h * src/XmlRpcMethodFactory.cc * src/XmlRpcMethodImpl.cc * src/XmlRpcMethodImpl.h * test/XmlRpcMethodTest.cc --- ChangeLog | 10 ++++++ src/XmlRpcMethod.cc | 2 +- src/XmlRpcMethod.h | 3 ++ src/XmlRpcMethodFactory.cc | 2 ++ src/XmlRpcMethodImpl.cc | 48 +++++++++++++++++++++++++++ src/XmlRpcMethodImpl.h | 5 +++ test/XmlRpcMethodTest.cc | 66 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 135 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 216c0736..aeb1aa64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-12-26 Tatsuhiro Tsujikawa + + Added system.multicall XML-RPC method. + * src/XmlRpcMethod.cc + * src/XmlRpcMethod.h + * src/XmlRpcMethodFactory.cc + * src/XmlRpcMethodImpl.cc + * src/XmlRpcMethodImpl.h + * test/XmlRpcMethodTest.cc + 2009-12-25 Tatsuhiro Tsujikawa Check structure depth when decoding. diff --git a/src/XmlRpcMethod.cc b/src/XmlRpcMethod.cc index 16e9909f..1772d2e7 100644 --- a/src/XmlRpcMethod.cc +++ b/src/XmlRpcMethod.cc @@ -56,7 +56,7 @@ XmlRpcMethod::XmlRpcMethod(): _optionParser(OptionParser::getInstance()), _logger(LogFactory::getInstance()) {} -static BDE createErrorResponse(const Exception& e) +BDE XmlRpcMethod::createErrorResponse(const Exception& e) { BDE params = BDE::dict(); params["faultCode"] = BDE(1); diff --git a/src/XmlRpcMethod.h b/src/XmlRpcMethod.h index 476917f2..2cc06582 100644 --- a/src/XmlRpcMethod.h +++ b/src/XmlRpcMethod.h @@ -48,6 +48,7 @@ class OptionParser; class BDE; class Logger; class Option; +class Exception; namespace xmlrpc { @@ -88,6 +89,8 @@ protected: // Copy options which is changeable in XML-RPC changeGlobalOption // command to dest. void applyChangeableGlobalOption(Option* dest, Option* src) const; + + BDE createErrorResponse(const Exception& e); public: XmlRpcMethod(); diff --git a/src/XmlRpcMethodFactory.cc b/src/XmlRpcMethodFactory.cc index 98eb5f5a..f37afddb 100644 --- a/src/XmlRpcMethodFactory.cc +++ b/src/XmlRpcMethodFactory.cc @@ -89,6 +89,8 @@ XmlRpcMethodFactory::create(const std::string& methodName) return SharedHandle(new PurgeDownloadResultXmlRpcMethod()); } else if(methodName == "aria2.getVersion") { return SharedHandle(new GetVersionXmlRpcMethod()); + } else if(methodName == "system.multicall") { + return SharedHandle(new SystemMulticallXmlRpcMethod()); } else { return SharedHandle(new NoSuchMethodXmlRpcMethod()); } diff --git a/src/XmlRpcMethodImpl.cc b/src/XmlRpcMethodImpl.cc index 2898e51c..6fd8bdfb 100644 --- a/src/XmlRpcMethodImpl.cc +++ b/src/XmlRpcMethodImpl.cc @@ -59,6 +59,8 @@ #include "message.h" #include "FeatureConfig.h" #include "array_fun.h" +#include "XmlRpcMethodFactory.h" +#include "XmlRpcResponse.h" #ifdef ENABLE_BITTORRENT # include "bittorrent_helper.h" # include "BtRegistry.h" @@ -111,6 +113,8 @@ const std::string KEY_LENGTH = "length"; const std::string KEY_URI = "uri"; const std::string KEY_VERSION = "version"; const std::string KEY_ENABLED_FEATURES = "enabledFeatures"; +const std::string KEY_METHOD_NAME = "methodName"; +const std::string KEY_PARAMS = "params"; } static BDE createGIDResponse(int32_t gid) @@ -815,6 +819,50 @@ BDE ChangePositionXmlRpcMethod::process return result; } +BDE SystemMulticallXmlRpcMethod::process +(const XmlRpcRequest& req, DownloadEngine* e) +{ + const BDE& params = req._params; + assert(params.isList()); + + if(params.size() != 1) { + throw DL_ABORT_EX("Illegal argument. One item list is expected."); + } + const BDE& methodSpecs = params[0]; + BDE list = BDE::list(); + for(BDE::List::const_iterator i = methodSpecs.listBegin(); + i != methodSpecs.listEnd(); ++i) { + if(!(*i).isDict()) { + list << createErrorResponse + (DL_ABORT_EX("system.multicall expected struct.")); + continue; + } + if(!(*i).containsKey(KEY_METHOD_NAME) || + !(*i).containsKey(KEY_PARAMS)) { + list << createErrorResponse + (DL_ABORT_EX("Missing methodName or params.")); + continue; + } + const std::string& methodName = (*i)[KEY_METHOD_NAME].s(); + if(methodName == "system.multicall") { + list << createErrorResponse + (DL_ABORT_EX("Recursive system.multicall forbidden.")); + continue; + } + SharedHandle method = XmlRpcMethodFactory::create(methodName); + XmlRpcRequest innerReq(methodName, (*i)[KEY_PARAMS]); + XmlRpcResponse res = method->execute(innerReq, e); + if(res._code == 0) { + BDE l = BDE::list(); + l << res._param; + list << l; + } else { + list << res._param; + } + } + return list; +} + BDE NoSuchMethodXmlRpcMethod::process (const XmlRpcRequest& req, DownloadEngine* e) { diff --git a/src/XmlRpcMethodImpl.h b/src/XmlRpcMethodImpl.h index f8cc2c20..962207ad 100644 --- a/src/XmlRpcMethodImpl.h +++ b/src/XmlRpcMethodImpl.h @@ -140,6 +140,11 @@ protected: virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e); }; +class SystemMulticallXmlRpcMethod:public XmlRpcMethod { +protected: + virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e); +}; + class NoSuchMethodXmlRpcMethod:public XmlRpcMethod { protected: virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e); diff --git a/test/XmlRpcMethodTest.cc b/test/XmlRpcMethodTest.cc index 79658061..14a20e52 100644 --- a/test/XmlRpcMethodTest.cc +++ b/test/XmlRpcMethodTest.cc @@ -69,6 +69,8 @@ class XmlRpcMethodTest:public CppUnit::TestFixture { CPPUNIT_TEST(testGatherProgressCommon); CPPUNIT_TEST(testChangePosition); CPPUNIT_TEST(testChangePosition_fail); + CPPUNIT_TEST(testSystemMulticall); + CPPUNIT_TEST(testSystemMulticall_fail); CPPUNIT_TEST_SUITE_END(); private: SharedHandle _e; @@ -123,6 +125,8 @@ public: void testGatherProgressCommon(); void testChangePosition(); void testChangePosition_fail(); + void testSystemMulticall(); + void testSystemMulticall_fail(); }; @@ -712,6 +716,68 @@ void XmlRpcMethodTest::testChangePosition_fail() CPPUNIT_ASSERT_EQUAL(1, res._code); } +void XmlRpcMethodTest::testSystemMulticall() +{ + SystemMulticallXmlRpcMethod m; + XmlRpcRequest req("system.multicall", BDE::list()); + BDE reqparams = BDE::list(); + req._params << reqparams; + for(int i = 0; i < 2; ++i) { + BDE dict = BDE::dict(); + dict["methodName"] = std::string("aria2.addUri"); + BDE params = BDE::list(); + params << BDE::list(); + params[0] << BDE("http://localhost/"+util::itos(i)); + dict["params"] = params; + reqparams << dict; + } + { + BDE dict = BDE::dict(); + dict["methodName"] = std::string("not exists"); + dict["params"] = BDE::list(); + reqparams << dict; + } + { + reqparams << std::string("not struct"); + } + { + BDE dict = BDE::dict(); + dict["methodName"] = std::string("system.multicall"); + dict["params"] = BDE::list(); + reqparams << dict; + } + { + // missing params + BDE dict = BDE::dict(); + dict["methodName"] = std::string("aria2.getVersion"); + reqparams << dict; + } + { + BDE dict = BDE::dict(); + dict["methodName"] = std::string("aria2.getVersion"); + dict["params"] = BDE::list(); + reqparams << dict; + } + XmlRpcResponse res = m.execute(req, _e.get()); + CPPUNIT_ASSERT_EQUAL(0, res._code); + CPPUNIT_ASSERT_EQUAL((size_t)7, res._param.size()); + CPPUNIT_ASSERT_EQUAL(std::string("1"), res._param[0][0].s()); + CPPUNIT_ASSERT_EQUAL(std::string("2"), res._param[1][0].s()); + CPPUNIT_ASSERT_EQUAL((int64_t)1, res._param[2]["faultCode"].i()); + CPPUNIT_ASSERT_EQUAL((int64_t)1, res._param[3]["faultCode"].i()); + CPPUNIT_ASSERT_EQUAL((int64_t)1, res._param[4]["faultCode"].i()); + CPPUNIT_ASSERT_EQUAL((int64_t)1, res._param[5]["faultCode"].i()); + CPPUNIT_ASSERT(res._param[6].isList()); +} + +void XmlRpcMethodTest::testSystemMulticall_fail() +{ + SystemMulticallXmlRpcMethod m; + XmlRpcRequest req("system.multicall", BDE::list()); + XmlRpcResponse res = m.execute(req, _e.get()); + CPPUNIT_ASSERT_EQUAL(1, res._code); +} + } // namespace xmlrpc } // namespace aria2