XmlRpcMethodImpl.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2009 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "XmlRpcMethodImpl.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include "Logger.h"
  39. #include "BDE.h"
  40. #include "DlAbortEx.h"
  41. #include "Option.h"
  42. #include "OptionParser.h"
  43. #include "OptionHandler.h"
  44. #include "DownloadEngine.h"
  45. #include "RequestGroup.h"
  46. #include "download_helper.h"
  47. #include "util.h"
  48. #include "RequestGroupMan.h"
  49. #include "StringFormat.h"
  50. #include "XmlRpcRequest.h"
  51. #include "PieceStorage.h"
  52. #include "DownloadContext.h"
  53. #include "DiskAdaptor.h"
  54. #include "FileEntry.h"
  55. #include "BtProgressInfoFile.h"
  56. #include "prefs.h"
  57. #include "message.h"
  58. #include "FeatureConfig.h"
  59. #include "array_fun.h"
  60. #include "XmlRpcMethodFactory.h"
  61. #include "XmlRpcResponse.h"
  62. #ifdef ENABLE_BITTORRENT
  63. # include "bittorrent_helper.h"
  64. # include "BtRegistry.h"
  65. # include "PeerStorage.h"
  66. # include "Peer.h"
  67. # include "BtRuntime.h"
  68. # include "BtAnnounce.h"
  69. #endif // ENABLE_BITTORRENT
  70. namespace aria2 {
  71. namespace xmlrpc {
  72. namespace {
  73. const BDE BDE_TRUE = BDE("true");
  74. const BDE BDE_FALSE = BDE("false");
  75. const BDE BDE_OK = BDE("OK");
  76. const BDE BDE_ACTIVE = BDE("active");
  77. const BDE BDE_WAITING = BDE("waiting");
  78. const BDE BDE_REMOVED = BDE("removed");
  79. const BDE BDE_ERROR = BDE("error");
  80. const BDE BDE_COMPLETE = BDE("complete");
  81. const std::string KEY_GID = "gid";
  82. const std::string KEY_ERROR_CODE = "errorCode";
  83. const std::string KEY_STATUS = "status";
  84. const std::string KEY_TOTAL_LENGTH = "totalLength";
  85. const std::string KEY_COMPLETED_LENGTH = "completedLength";
  86. const std::string KEY_DOWNLOAD_SPEED = "downloadSpeed";
  87. const std::string KEY_UPLOAD_SPEED = "uploadSpeed";
  88. const std::string KEY_UPLOAD_LENGTH = "uploadLength";
  89. const std::string KEY_CONNECTIONS = "connections";
  90. const std::string KEY_BITFIELD = "bitfield";
  91. const std::string KEY_PIECE_LENGTH = "pieceLength";
  92. const std::string KEY_NUM_PIECES = "numPieces";
  93. const std::string KEY_FOLLOWED_BY = "followedBy";
  94. const std::string KEY_BELONGS_TO = "belongsTo";
  95. const std::string KEY_INFO_HASH = "infoHash";
  96. const std::string KEY_NUM_SEEDERS = "numSeeders";
  97. const std::string KEY_PEER_ID = "peerId";
  98. const std::string KEY_IP = "ip";
  99. const std::string KEY_PORT = "port";
  100. const std::string KEY_AM_CHOKING = "amChoking";
  101. const std::string KEY_PEER_CHOKING = "peerChoking";
  102. const std::string KEY_SEEDER = "seeder";
  103. const std::string KEY_INDEX = "index";
  104. const std::string KEY_PATH = "path";
  105. const std::string KEY_SELECTED = "selected";
  106. const std::string KEY_LENGTH = "length";
  107. const std::string KEY_URI = "uri";
  108. const std::string KEY_VERSION = "version";
  109. const std::string KEY_ENABLED_FEATURES = "enabledFeatures";
  110. const std::string KEY_METHOD_NAME = "methodName";
  111. const std::string KEY_PARAMS = "params";
  112. }
  113. static BDE createGIDResponse(int32_t gid)
  114. {
  115. return BDE(util::itos(gid));
  116. }
  117. static BDE addRequestGroup(const SharedHandle<RequestGroup>& group,
  118. DownloadEngine* e,
  119. bool posGiven, int pos)
  120. {
  121. if(posGiven) {
  122. e->_requestGroupMan->insertReservedGroup(pos, group);
  123. } else {
  124. e->_requestGroupMan->addReservedGroup(group);
  125. }
  126. return createGIDResponse(group->getGID());
  127. }
  128. static bool hasDictParam(const BDE& params, size_t index)
  129. {
  130. return params.size() > index && params[index].isDict();
  131. }
  132. static void getPosParam(const BDE& params, size_t posParamIndex,
  133. bool& posGiven, size_t& pos)
  134. {
  135. if(params.size() > posParamIndex && params[posParamIndex].isInteger()) {
  136. if(params[posParamIndex].i() >= 0) {
  137. pos = params[posParamIndex].i();
  138. posGiven = true;
  139. } else {
  140. throw DL_ABORT_EX("Position must be greater than or equal to 0.");
  141. }
  142. } else {
  143. posGiven = false;
  144. }
  145. }
  146. BDE AddUriXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  147. {
  148. const BDE& params = req._params;
  149. assert(params.isList());
  150. if(params.empty() || !params[0].isList() || params[0].empty()) {
  151. throw DL_ABORT_EX("URI is not provided.");
  152. }
  153. std::deque<std::string> uris;
  154. for(BDE::List::const_iterator i = params[0].listBegin();
  155. i != params[0].listEnd(); ++i) {
  156. if((*i).isString()) {
  157. uris.push_back((*i).s());
  158. }
  159. }
  160. SharedHandle<Option> requestOption(new Option(*e->option));
  161. if(hasDictParam(params, 1)) {
  162. gatherRequestOption(requestOption, params[1]);
  163. }
  164. size_t pos = 0;
  165. bool posGiven = false;
  166. getPosParam(params, 2, posGiven, pos);
  167. std::deque<SharedHandle<RequestGroup> > result;
  168. createRequestGroupForUri(result, requestOption, uris,
  169. /* ignoreForceSeq = */ true,
  170. /* ignoreLocalPath = */ true);
  171. if(!result.empty()) {
  172. return addRequestGroup(result.front(), e, posGiven, pos);
  173. } else {
  174. throw DL_ABORT_EX("No URI to download.");
  175. }
  176. }
  177. #ifdef ENABLE_BITTORRENT
  178. BDE AddTorrentXmlRpcMethod::process
  179. (const XmlRpcRequest& req, DownloadEngine* e)
  180. {
  181. const BDE& params = req._params;
  182. assert(params.isList());
  183. if(params.empty() || !params[0].isString()) {
  184. throw DL_ABORT_EX("Torrent data is not provided.");
  185. }
  186. std::deque<std::string> uris;
  187. if(params.size() > 1 && params[1].isList()) {
  188. for(BDE::List::const_iterator i = params[1].listBegin();
  189. i != params[1].listEnd(); ++i) {
  190. if((*i).isString()) {
  191. uris.push_back((*i).s());
  192. }
  193. }
  194. }
  195. SharedHandle<Option> requestOption(new Option(*e->option));
  196. if(hasDictParam(params, 2)) {
  197. gatherRequestOption(requestOption, params[2]);
  198. }
  199. size_t pos = 0;
  200. bool posGiven = false;
  201. getPosParam(params, 3, posGiven, pos);
  202. std::deque<SharedHandle<RequestGroup> > result;
  203. createRequestGroupForBitTorrent(result, requestOption,
  204. uris,
  205. params[0].s());
  206. if(!result.empty()) {
  207. return addRequestGroup(result.front(), e, posGiven, pos);
  208. } else {
  209. throw DL_ABORT_EX("No Torrent to download.");
  210. }
  211. }
  212. #endif // ENABLE_BITTORRENT
  213. #ifdef ENABLE_METALINK
  214. BDE AddMetalinkXmlRpcMethod::process
  215. (const XmlRpcRequest& req, DownloadEngine* e)
  216. {
  217. const BDE& params = req._params;
  218. assert(params.isList());
  219. if(params.empty() || !params[0].isString()) {
  220. throw DL_ABORT_EX("Metalink data is not provided.");
  221. }
  222. SharedHandle<Option> requestOption(new Option(*e->option));
  223. if(hasDictParam(params, 1)) {
  224. gatherRequestOption(requestOption, params[1]);
  225. };
  226. size_t pos = 0;
  227. bool posGiven = false;
  228. getPosParam(params, 2, posGiven, pos);
  229. std::deque<SharedHandle<RequestGroup> > result;
  230. createRequestGroupForMetalink(result, requestOption, params[0].s());
  231. if(!result.empty()) {
  232. if(posGiven) {
  233. e->_requestGroupMan->insertReservedGroup(pos, result);
  234. } else {
  235. e->_requestGroupMan->addReservedGroup(result);
  236. }
  237. BDE gids = BDE::list();
  238. for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
  239. result.begin(); i != result.end(); ++i) {
  240. gids << BDE(util::itos((*i)->getGID()));
  241. }
  242. return gids;
  243. } else {
  244. throw DL_ABORT_EX("No files to download.");
  245. }
  246. }
  247. #endif // ENABLE_METALINK
  248. BDE RemoveXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  249. {
  250. const BDE& params = req._params;
  251. assert(params.isList());
  252. if(params.empty() || !params[0].isString()) {
  253. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  254. }
  255. int32_t gid = util::parseInt(params[0].s());
  256. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  257. if(group.isNull()) {
  258. group = e->_requestGroupMan->findReservedGroup(gid);
  259. if(group.isNull()) {
  260. throw DL_ABORT_EX
  261. (StringFormat("Active Download not found for GID#%d", gid).str());
  262. }
  263. if(group->isDependencyResolved()) {
  264. e->_requestGroupMan->removeReservedGroup(gid);
  265. } else {
  266. throw DL_ABORT_EX
  267. (StringFormat("GID#%d cannot be removed now", gid).str());
  268. }
  269. } else {
  270. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  271. }
  272. return createGIDResponse(gid);
  273. }
  274. void gatherProgressCommon
  275. (BDE& entryDict, const SharedHandle<RequestGroup>& group)
  276. {
  277. entryDict[KEY_GID] = util::itos(group->getGID());
  278. // This is "filtered" total length if --select-file is used.
  279. entryDict[KEY_TOTAL_LENGTH] = util::uitos(group->getTotalLength());
  280. // This is "filtered" total length if --select-file is used.
  281. entryDict[KEY_COMPLETED_LENGTH] = util::uitos(group->getCompletedLength());
  282. TransferStat stat = group->calculateStat();
  283. entryDict[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  284. entryDict[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  285. entryDict[KEY_UPLOAD_LENGTH] = util::uitos(stat.getAllTimeUploadLength());
  286. entryDict[KEY_CONNECTIONS] = util::uitos(group->getNumConnection());
  287. SharedHandle<PieceStorage> ps = group->getPieceStorage();
  288. if(!ps.isNull()) {
  289. if(ps->getBitfieldLength() > 0) {
  290. entryDict[KEY_BITFIELD] = util::toHex(ps->getBitfield(),
  291. ps->getBitfieldLength());
  292. }
  293. }
  294. entryDict[KEY_PIECE_LENGTH] =
  295. util::uitos(group->getDownloadContext()->getPieceLength());
  296. entryDict[KEY_NUM_PIECES] =
  297. util::uitos(group->getDownloadContext()->getNumPieces());
  298. if(!group->followedBy().empty()) {
  299. BDE list = BDE::list();
  300. // The element is GID.
  301. for(std::vector<int32_t>::const_iterator i = group->followedBy().begin();
  302. i != group->followedBy().end(); ++i) {
  303. list << util::itos(*i);
  304. }
  305. entryDict[KEY_FOLLOWED_BY] = list;
  306. }
  307. if(group->belongsTo()) {
  308. entryDict[KEY_BELONGS_TO] = util::itos(group->belongsTo());
  309. }
  310. }
  311. #ifdef ENABLE_BITTORRENT
  312. static void gatherProgressBitTorrent
  313. (BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject)
  314. {
  315. const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s();
  316. entryDict[KEY_INFO_HASH] = util::toHex(infoHash);
  317. if(!btObject.isNull()) {
  318. SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
  319. assert(!peerStorage.isNull());
  320. std::deque<SharedHandle<Peer> > peers;
  321. peerStorage->getActivePeers(peers);
  322. entryDict[KEY_NUM_SEEDERS] = countSeeder(peers.begin(), peers.end());
  323. }
  324. }
  325. static void gatherPeer(BDE& peers, const SharedHandle<PeerStorage>& ps)
  326. {
  327. std::deque<SharedHandle<Peer> > activePeers;
  328. ps->getActivePeers(activePeers);
  329. for(std::deque<SharedHandle<Peer> >::const_iterator i =
  330. activePeers.begin(); i != activePeers.end(); ++i) {
  331. BDE peerEntry = BDE::dict();
  332. peerEntry[KEY_PEER_ID] = util::torrentUrlencode((*i)->getPeerId(),
  333. PEER_ID_LENGTH);
  334. peerEntry[KEY_IP] = (*i)->ipaddr;
  335. peerEntry[KEY_PORT] = util::uitos((*i)->port);
  336. peerEntry[KEY_BITFIELD] = util::toHex((*i)->getBitfield(),
  337. (*i)->getBitfieldLength());
  338. peerEntry[KEY_AM_CHOKING] = (*i)->amChoking()?BDE_TRUE:BDE_FALSE;
  339. peerEntry[KEY_PEER_CHOKING] = (*i)->peerChoking()?BDE_TRUE:BDE_FALSE;
  340. TransferStat stat = ps->getTransferStatFor(*i);
  341. peerEntry[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  342. peerEntry[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  343. peerEntry[KEY_SEEDER] = (*i)->isSeeder()?BDE_TRUE:BDE_FALSE;
  344. peers << peerEntry;
  345. }
  346. }
  347. #endif // ENABLE_BITTORRENT
  348. static void gatherProgress
  349. (BDE& entryDict, const SharedHandle<RequestGroup>& group, DownloadEngine* e)
  350. {
  351. gatherProgressCommon(entryDict, group);
  352. #ifdef ENABLE_BITTORRENT
  353. if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
  354. const BDE& torrentAttrs =
  355. group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
  356. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  357. gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
  358. }
  359. #endif // ENABLE_BITTORRENT
  360. }
  361. void gatherStoppedDownload
  362. (BDE& entryDict, const SharedHandle<DownloadResult>& ds)
  363. {
  364. entryDict[KEY_GID] = util::itos(ds->gid);
  365. entryDict[KEY_ERROR_CODE] = util::itos(static_cast<int>(ds->result));
  366. if(ds->result == downloadresultcode::IN_PROGRESS) {
  367. entryDict[KEY_STATUS] = BDE_REMOVED;
  368. } else if(ds->result == downloadresultcode::FINISHED) {
  369. entryDict[KEY_STATUS] = BDE_COMPLETE;
  370. } else {
  371. entryDict[KEY_STATUS] = BDE_ERROR;
  372. }
  373. if(!ds->followedBy.empty()) {
  374. BDE list = BDE::list();
  375. // The element is GID.
  376. for(std::vector<int32_t>::const_iterator i = ds->followedBy.begin();
  377. i != ds->followedBy.end(); ++i) {
  378. list << util::itos(*i);
  379. }
  380. entryDict[KEY_FOLLOWED_BY] = list;
  381. }
  382. if(ds->belongsTo) {
  383. entryDict[KEY_BELONGS_TO] = util::itos(ds->belongsTo);
  384. }
  385. }
  386. static
  387. SharedHandle<RequestGroup>
  388. findRequestGroup(const SharedHandle<RequestGroupMan>& rgman, int32_t gid)
  389. {
  390. SharedHandle<RequestGroup> group = rgman->findRequestGroup(gid);
  391. if(group.isNull()) {
  392. group = rgman->findReservedGroup(gid);
  393. }
  394. return group;
  395. }
  396. template<typename InputIterator>
  397. static void createFileEntry(BDE& files, InputIterator first, InputIterator last)
  398. {
  399. size_t index = 1;
  400. for(; first != last; ++first, ++index) {
  401. BDE entry = BDE::dict();
  402. entry[KEY_INDEX] = util::uitos(index);
  403. entry[KEY_PATH] = (*first)->getPath();
  404. entry[KEY_SELECTED] = (*first)->isRequested()?BDE_TRUE:BDE_FALSE;
  405. entry[KEY_LENGTH] = util::uitos((*first)->getLength());
  406. files << entry;
  407. }
  408. }
  409. BDE GetFilesXmlRpcMethod::process
  410. (const XmlRpcRequest& req, DownloadEngine* e)
  411. {
  412. const BDE& params = req._params;
  413. assert(params.isList());
  414. if(params.empty() || !params[0].isString()) {
  415. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  416. }
  417. int32_t gid = util::parseInt(params[0].s());
  418. BDE files = BDE::list();
  419. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  420. if(group.isNull()) {
  421. SharedHandle<DownloadResult> dr =
  422. e->_requestGroupMan->findDownloadResult(gid);
  423. if(dr.isNull()) {
  424. throw DL_ABORT_EX
  425. (StringFormat("No file data is available for GID#%d", gid).str());
  426. } else {
  427. createFileEntry(files, dr->fileEntries.begin(), dr->fileEntries.end());
  428. }
  429. } else {
  430. createFileEntry(files,
  431. group->getDownloadContext()->getFileEntries().begin(),
  432. group->getDownloadContext()->getFileEntries().end());
  433. }
  434. return files;
  435. }
  436. BDE GetUrisXmlRpcMethod::process
  437. (const XmlRpcRequest& req, DownloadEngine* e)
  438. {
  439. const BDE& params = req._params;
  440. assert(params.isList());
  441. if(params.empty() || !params[0].isString()) {
  442. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  443. }
  444. int32_t gid = util::parseInt(params[0].s());
  445. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  446. if(group.isNull()) {
  447. throw DL_ABORT_EX
  448. (StringFormat("No URI data is available for GID#%d", gid).str());
  449. }
  450. BDE uriList = BDE::list();
  451. std::deque<std::string> uris;
  452. // TODO Current implementation just returns first FileEntry's URIs.
  453. if(!group->getDownloadContext()->getFileEntries().empty()) {
  454. group->getDownloadContext()->getFirstFileEntry()->getUris(uris);
  455. for(std::deque<std::string>::const_iterator i = uris.begin();
  456. i != uris.end(); ++i) {
  457. BDE entry = BDE::dict();
  458. entry[KEY_URI] = *i;
  459. uriList << entry;
  460. }
  461. }
  462. return uriList;
  463. }
  464. #ifdef ENABLE_BITTORRENT
  465. BDE GetPeersXmlRpcMethod::process
  466. (const XmlRpcRequest& req, DownloadEngine* e)
  467. {
  468. const BDE& params = req._params;
  469. assert(params.isList());
  470. if(params.empty() || !params[0].isString()) {
  471. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  472. }
  473. int32_t gid = util::parseInt(params[0].s());
  474. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  475. if(group.isNull()) {
  476. throw DL_ABORT_EX
  477. (StringFormat("No peer data is available for GID#%d", gid).str());
  478. }
  479. BDE peers = BDE::list();
  480. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  481. if(!btObject.isNull()) {
  482. assert(!btObject._peerStorage.isNull());
  483. gatherPeer(peers, btObject._peerStorage);
  484. }
  485. return peers;
  486. }
  487. #endif // ENABLE_BITTORRENT
  488. BDE TellStatusXmlRpcMethod::process
  489. (const XmlRpcRequest& req, DownloadEngine* e)
  490. {
  491. const BDE& params = req._params;
  492. assert(params.isList());
  493. if(params.empty() || !params[0].isString()) {
  494. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  495. }
  496. int32_t gid = util::parseInt(params[0].s());
  497. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  498. BDE entryDict = BDE::dict();
  499. if(group.isNull()) {
  500. group = e->_requestGroupMan->findReservedGroup(gid);
  501. if(group.isNull()) {
  502. SharedHandle<DownloadResult> ds =
  503. e->_requestGroupMan->findDownloadResult(gid);
  504. if(ds.isNull()) {
  505. throw DL_ABORT_EX
  506. (StringFormat("No such download for GID#%d", gid).str());
  507. }
  508. gatherStoppedDownload(entryDict, ds);
  509. } else {
  510. entryDict[KEY_STATUS] = BDE_WAITING;
  511. gatherProgress(entryDict, group, e);
  512. }
  513. } else {
  514. entryDict[KEY_STATUS] = BDE_ACTIVE;
  515. gatherProgress(entryDict, group, e);
  516. }
  517. return entryDict;
  518. }
  519. BDE TellActiveXmlRpcMethod::process
  520. (const XmlRpcRequest& req, DownloadEngine* e)
  521. {
  522. BDE list = BDE::list();
  523. const std::deque<SharedHandle<RequestGroup> >& groups =
  524. e->_requestGroupMan->getRequestGroups();
  525. for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
  526. groups.begin(); i != groups.end(); ++i) {
  527. BDE entryDict = BDE::dict();
  528. entryDict[KEY_STATUS] = BDE_ACTIVE;
  529. gatherProgress(entryDict, *i, e);
  530. list << entryDict;
  531. }
  532. return list;
  533. }
  534. template<typename InputIterator>
  535. static std::pair<InputIterator, InputIterator>
  536. getPaginationRange
  537. (const XmlRpcRequest& req, InputIterator first, InputIterator last)
  538. {
  539. const BDE& params = req._params;
  540. assert(params.isList());
  541. if(params.size() != 2 ||
  542. !params[0].isInteger() || !params[1].isInteger() ||
  543. params[0].i() < 0 || params[1].i() < 0) {
  544. throw DL_ABORT_EX("Invalid argument. Specify offset and num in integer.");
  545. }
  546. size_t offset = params[0].i();
  547. size_t num = params[1].i();
  548. BDE list = BDE::list();
  549. size_t size = std::distance(first, last);
  550. if(size <= offset) {
  551. return std::make_pair(last, last);
  552. }
  553. size_t lastDistance;
  554. if(size < offset+num) {
  555. lastDistance = size;
  556. } else {
  557. lastDistance = offset+num;
  558. }
  559. last = first;
  560. std::advance(first, offset);
  561. std::advance(last, lastDistance);
  562. return std::make_pair(first, last);
  563. }
  564. BDE TellWaitingXmlRpcMethod::process
  565. (const XmlRpcRequest& req, DownloadEngine* e)
  566. {
  567. const std::deque<SharedHandle<RequestGroup> >& waitings =
  568. e->_requestGroupMan->getReservedGroups();
  569. std::pair<std::deque<SharedHandle<RequestGroup> >::const_iterator,
  570. std::deque<SharedHandle<RequestGroup> >::const_iterator> range =
  571. getPaginationRange(req, waitings.begin(), waitings.end());
  572. BDE list = BDE::list();
  573. for(; range.first != range.second; ++range.first) {
  574. BDE entryDict = BDE::dict();
  575. entryDict[KEY_STATUS] = BDE_WAITING;
  576. gatherProgress(entryDict, *range.first, e);
  577. list << entryDict;
  578. }
  579. return list;
  580. }
  581. BDE TellStoppedXmlRpcMethod::process
  582. (const XmlRpcRequest& req, DownloadEngine* e)
  583. {
  584. const std::deque<SharedHandle<DownloadResult> >& stopped =
  585. e->_requestGroupMan->getDownloadResults();
  586. std::pair<std::deque<SharedHandle<DownloadResult> >::const_iterator,
  587. std::deque<SharedHandle<DownloadResult> >::const_iterator> range =
  588. getPaginationRange(req, stopped.begin(), stopped.end());
  589. BDE list = BDE::list();
  590. for(; range.first != range.second; ++range.first) {
  591. BDE entryDict = BDE::dict();
  592. gatherStoppedDownload(entryDict, *range.first);
  593. list << entryDict;
  594. }
  595. return list;
  596. }
  597. BDE PurgeDownloadResultXmlRpcMethod::process
  598. (const XmlRpcRequest& req, DownloadEngine* e)
  599. {
  600. e->_requestGroupMan->purgeDownloadResult();
  601. return BDE_OK;
  602. }
  603. BDE ChangeOptionXmlRpcMethod::process
  604. (const XmlRpcRequest& req, DownloadEngine* e)
  605. {
  606. const BDE& params = req._params;
  607. assert(params.isList());
  608. if(params.empty() || !params[0].isString()) {
  609. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  610. }
  611. int32_t gid = util::parseInt(params[0].s());
  612. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  613. if(group.isNull()) {
  614. throw DL_ABORT_EX
  615. (StringFormat("Cannot change option for GID#%d", gid).str());
  616. }
  617. SharedHandle<Option> option(new Option());
  618. if(params.size() > 1 && params[1].isDict()) {
  619. gatherChangeableOption(option, params[1]);
  620. applyChangeableOption(group->getOption().get(), option.get());
  621. if(option->defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  622. group->setMaxDownloadSpeedLimit
  623. (option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  624. }
  625. if(option->defined(PREF_MAX_UPLOAD_LIMIT)) {
  626. group->setMaxUploadSpeedLimit(option->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  627. }
  628. #ifdef ENABLE_BITTORRENT
  629. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  630. if(!btObject.isNull()) {
  631. if(option->defined(PREF_BT_MAX_PEERS)) {
  632. btObject._btRuntime->setMaxPeers(option->getAsInt(PREF_BT_MAX_PEERS));
  633. }
  634. }
  635. #endif // ENABLE_BITTORRENT
  636. }
  637. return BDE_OK;
  638. }
  639. BDE ChangeGlobalOptionXmlRpcMethod::process
  640. (const XmlRpcRequest& req, DownloadEngine* e)
  641. {
  642. const BDE& params = req._params;
  643. assert(params.isList());
  644. if(params.empty() || !params[0].isDict()) {
  645. return BDE_OK;
  646. }
  647. SharedHandle<Option> option(new Option());
  648. gatherChangeableGlobalOption(option, params[0]);
  649. applyChangeableGlobalOption(e->option, option.get());
  650. if(option->defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  651. e->_requestGroupMan->setMaxOverallDownloadSpeedLimit
  652. (option->getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  653. }
  654. if(option->defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  655. e->_requestGroupMan->setMaxOverallUploadSpeedLimit
  656. (option->getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  657. }
  658. if(option->defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  659. e->_requestGroupMan->setMaxSimultaneousDownloads
  660. (option->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  661. }
  662. return BDE_OK;
  663. }
  664. BDE GetVersionXmlRpcMethod::process
  665. (const XmlRpcRequest& req, DownloadEngine* e)
  666. {
  667. BDE result = BDE::dict();
  668. result[KEY_VERSION] = std::string(PACKAGE_VERSION);
  669. BDE featureList = BDE::list();
  670. const FeatureMap& features = FeatureConfig::getInstance()->getFeatures();
  671. for(FeatureMap::const_iterator i = features.begin(); i != features.end();++i){
  672. if((*i).second) {
  673. featureList << (*i).first;
  674. }
  675. }
  676. result[KEY_ENABLED_FEATURES] = featureList;
  677. return result;
  678. }
  679. template<typename InputIterator>
  680. static void pushRequestOption
  681. (BDE& dict, InputIterator optionFirst, InputIterator optionLast)
  682. {
  683. const std::set<std::string>& requestOptions = listRequestOptions();
  684. for(; optionFirst != optionLast; ++optionFirst) {
  685. if(requestOptions.count((*optionFirst).first)) {
  686. dict[(*optionFirst).first] = (*optionFirst).second;
  687. }
  688. }
  689. }
  690. BDE GetOptionXmlRpcMethod::process
  691. (const XmlRpcRequest& req, DownloadEngine* e)
  692. {
  693. const BDE& params = req._params;
  694. assert(params.isList());
  695. if(params.empty() || !params[0].isString()) {
  696. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  697. }
  698. int32_t gid = util::parseInt(params[0].s());
  699. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  700. if(group.isNull()) {
  701. throw DL_ABORT_EX
  702. (StringFormat("Cannot get option for GID#%d", gid).str());
  703. }
  704. BDE result = BDE::dict();
  705. SharedHandle<Option> option = group->getOption();
  706. pushRequestOption(result, option->begin(), option->end());
  707. return result;
  708. }
  709. BDE GetGlobalOptionXmlRpcMethod::process
  710. (const XmlRpcRequest& req, DownloadEngine* e)
  711. {
  712. BDE result = BDE::dict();
  713. for(std::map<std::string, std::string>::const_iterator i = e->option->begin();
  714. i != e->option->end(); ++i) {
  715. SharedHandle<OptionHandler> h = _optionParser->findByName((*i).first);
  716. if(!h.isNull() && !h->isHidden()) {
  717. result[(*i).first] = (*i).second;
  718. }
  719. }
  720. return result;
  721. }
  722. BDE ChangePositionXmlRpcMethod::process
  723. (const XmlRpcRequest& req, DownloadEngine* e)
  724. {
  725. const BDE& params = req._params;
  726. assert(params.isList());
  727. if(params.size() != 3 ||
  728. !params[0].isString() || !params[1].isInteger() || !params[2].isString()) {
  729. throw DL_ABORT_EX("Illegal argument.");
  730. }
  731. int32_t gid = util::parseInt(params[0].s());
  732. int pos = params[1].i();
  733. const std::string& howStr = params[2].s();
  734. RequestGroupMan::HOW how;
  735. if(howStr == "POS_SET") {
  736. how = RequestGroupMan::POS_SET;
  737. } else if(howStr == "POS_CUR") {
  738. how = RequestGroupMan::POS_CUR;
  739. } else if(howStr == "POS_END") {
  740. how = RequestGroupMan::POS_END;
  741. } else {
  742. throw DL_ABORT_EX("Illegal argument.");
  743. }
  744. size_t destPos =
  745. e->_requestGroupMan->changeReservedGroupPosition(gid, pos, how);
  746. BDE result(destPos);
  747. return result;
  748. }
  749. BDE SystemMulticallXmlRpcMethod::process
  750. (const XmlRpcRequest& req, DownloadEngine* e)
  751. {
  752. const BDE& params = req._params;
  753. assert(params.isList());
  754. if(params.size() != 1) {
  755. throw DL_ABORT_EX("Illegal argument. One item list is expected.");
  756. }
  757. const BDE& methodSpecs = params[0];
  758. BDE list = BDE::list();
  759. for(BDE::List::const_iterator i = methodSpecs.listBegin();
  760. i != methodSpecs.listEnd(); ++i) {
  761. if(!(*i).isDict()) {
  762. list << createErrorResponse
  763. (DL_ABORT_EX("system.multicall expected struct."));
  764. continue;
  765. }
  766. if(!(*i).containsKey(KEY_METHOD_NAME) ||
  767. !(*i).containsKey(KEY_PARAMS)) {
  768. list << createErrorResponse
  769. (DL_ABORT_EX("Missing methodName or params."));
  770. continue;
  771. }
  772. const std::string& methodName = (*i)[KEY_METHOD_NAME].s();
  773. if(methodName == getMethodName()) {
  774. list << createErrorResponse
  775. (DL_ABORT_EX("Recursive system.multicall forbidden."));
  776. continue;
  777. }
  778. SharedHandle<XmlRpcMethod> method = XmlRpcMethodFactory::create(methodName);
  779. XmlRpcRequest innerReq(methodName, (*i)[KEY_PARAMS]);
  780. XmlRpcResponse res = method->execute(innerReq, e);
  781. if(res._code == 0) {
  782. BDE l = BDE::list();
  783. l << res._param;
  784. list << l;
  785. } else {
  786. list << res._param;
  787. }
  788. }
  789. return list;
  790. }
  791. BDE NoSuchMethodXmlRpcMethod::process
  792. (const XmlRpcRequest& req, DownloadEngine* e)
  793. {
  794. throw DL_ABORT_EX
  795. (StringFormat("No such method: %s", req._methodName.c_str()).str());
  796. }
  797. } // namespace xmlrpc
  798. } // namespace aria2