瀏覽代碼

2009-12-26 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added system.multicall XML-RPC method.
	* src/XmlRpcMethod.cc
	* src/XmlRpcMethod.h
	* src/XmlRpcMethodFactory.cc
	* src/XmlRpcMethodImpl.cc
	* src/XmlRpcMethodImpl.h
	* test/XmlRpcMethodTest.cc
Tatsuhiro Tsujikawa 16 年之前
父節點
當前提交
af20aea88c
共有 7 個文件被更改,包括 135 次插入1 次删除
  1. 10 0
      ChangeLog
  2. 1 1
      src/XmlRpcMethod.cc
  3. 3 0
      src/XmlRpcMethod.h
  4. 2 0
      src/XmlRpcMethodFactory.cc
  5. 48 0
      src/XmlRpcMethodImpl.cc
  6. 5 0
      src/XmlRpcMethodImpl.h
  7. 66 0
      test/XmlRpcMethodTest.cc

+ 10 - 0
ChangeLog

@@ -1,3 +1,13 @@
+2009-12-26  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	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  <t-tujikawa@users.sourceforge.net>
 
 	Check structure depth when decoding.

+ 1 - 1
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);

+ 3 - 0
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();
 

+ 2 - 0
src/XmlRpcMethodFactory.cc

@@ -89,6 +89,8 @@ XmlRpcMethodFactory::create(const std::string& methodName)
     return SharedHandle<XmlRpcMethod>(new PurgeDownloadResultXmlRpcMethod());
   } else if(methodName == "aria2.getVersion") {
     return SharedHandle<XmlRpcMethod>(new GetVersionXmlRpcMethod());
+  } else if(methodName == "system.multicall") {
+    return SharedHandle<XmlRpcMethod>(new SystemMulticallXmlRpcMethod());
   } else {
     return SharedHandle<XmlRpcMethod>(new NoSuchMethodXmlRpcMethod());
   }

+ 48 - 0
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<XmlRpcMethod> 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)
 {

+ 5 - 0
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);

+ 66 - 0
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<DownloadEngine> _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