XmlRpcMethodImpl.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  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 BDE BDE_USED = BDE("used");
  82. const std::string KEY_GID = "gid";
  83. const std::string KEY_ERROR_CODE = "errorCode";
  84. const std::string KEY_STATUS = "status";
  85. const std::string KEY_TOTAL_LENGTH = "totalLength";
  86. const std::string KEY_COMPLETED_LENGTH = "completedLength";
  87. const std::string KEY_DOWNLOAD_SPEED = "downloadSpeed";
  88. const std::string KEY_UPLOAD_SPEED = "uploadSpeed";
  89. const std::string KEY_UPLOAD_LENGTH = "uploadLength";
  90. const std::string KEY_CONNECTIONS = "connections";
  91. const std::string KEY_BITFIELD = "bitfield";
  92. const std::string KEY_PIECE_LENGTH = "pieceLength";
  93. const std::string KEY_NUM_PIECES = "numPieces";
  94. const std::string KEY_FOLLOWED_BY = "followedBy";
  95. const std::string KEY_BELONGS_TO = "belongsTo";
  96. const std::string KEY_INFO_HASH = "infoHash";
  97. const std::string KEY_NUM_SEEDERS = "numSeeders";
  98. const std::string KEY_PEER_ID = "peerId";
  99. const std::string KEY_IP = "ip";
  100. const std::string KEY_PORT = "port";
  101. const std::string KEY_AM_CHOKING = "amChoking";
  102. const std::string KEY_PEER_CHOKING = "peerChoking";
  103. const std::string KEY_SEEDER = "seeder";
  104. const std::string KEY_INDEX = "index";
  105. const std::string KEY_PATH = "path";
  106. const std::string KEY_SELECTED = "selected";
  107. const std::string KEY_LENGTH = "length";
  108. const std::string KEY_URI = "uri";
  109. const std::string KEY_CURRENT_URI = "currentUri";
  110. const std::string KEY_VERSION = "version";
  111. const std::string KEY_ENABLED_FEATURES = "enabledFeatures";
  112. const std::string KEY_METHOD_NAME = "methodName";
  113. const std::string KEY_PARAMS = "params";
  114. const std::string KEY_SESSION_ID = "sessionId";
  115. const std::string KEY_FILES = "files";
  116. const std::string KEY_DIR = "dir";
  117. const std::string KEY_URIS = "uris";
  118. const std::string KEY_BITTORRENT = "bittorrent";
  119. const std::string KEY_INFO = "info";
  120. const std::string KEY_NAME = "name";
  121. const std::string KEY_ANNOUNCE_LIST = "announceList";
  122. const std::string KEY_COMMENT = "comment";
  123. const std::string KEY_CREATION_DATE = "creationDate";
  124. const std::string KEY_MODE = "mode";
  125. const std::string KEY_SERVERS = "servers";
  126. }
  127. static BDE createGIDResponse(int32_t gid)
  128. {
  129. return BDE(util::itos(gid));
  130. }
  131. static BDE addRequestGroup(const SharedHandle<RequestGroup>& group,
  132. DownloadEngine* e,
  133. bool posGiven, int pos)
  134. {
  135. if(posGiven) {
  136. e->_requestGroupMan->insertReservedGroup(pos, group);
  137. } else {
  138. e->_requestGroupMan->addReservedGroup(group);
  139. }
  140. return createGIDResponse(group->getGID());
  141. }
  142. static bool hasDictParam(const BDE& params, size_t index)
  143. {
  144. return params.size() > index && params[index].isDict();
  145. }
  146. static void getPosParam(const BDE& params, size_t posParamIndex,
  147. bool& posGiven, size_t& pos)
  148. {
  149. if(params.size() > posParamIndex && params[posParamIndex].isInteger()) {
  150. if(params[posParamIndex].i() >= 0) {
  151. pos = params[posParamIndex].i();
  152. posGiven = true;
  153. } else {
  154. throw DL_ABORT_EX("Position must be greater than or equal to 0.");
  155. }
  156. } else {
  157. posGiven = false;
  158. }
  159. }
  160. template<typename OutputIterator>
  161. static void extractUris(OutputIterator out, const BDE& src)
  162. {
  163. for(BDE::List::const_iterator i = src.listBegin(), eoi = src.listEnd();
  164. i != eoi; ++i) {
  165. if((*i).isString()) {
  166. out++ = (*i).s();
  167. }
  168. }
  169. }
  170. BDE AddUriXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  171. {
  172. const BDE& params = req._params;
  173. assert(params.isList());
  174. if(params.empty() || !params[0].isList() || params[0].empty()) {
  175. throw DL_ABORT_EX("URI is not provided.");
  176. }
  177. std::vector<std::string> uris;
  178. extractUris(std::back_inserter(uris), params[0]);
  179. SharedHandle<Option> requestOption(new Option(*e->option));
  180. if(hasDictParam(params, 1)) {
  181. gatherRequestOption(requestOption, params[1]);
  182. }
  183. size_t pos = 0;
  184. bool posGiven = false;
  185. getPosParam(params, 2, posGiven, pos);
  186. std::vector<SharedHandle<RequestGroup> > result;
  187. createRequestGroupForUri(result, requestOption, uris,
  188. /* ignoreForceSeq = */ true,
  189. /* ignoreLocalPath = */ true);
  190. if(!result.empty()) {
  191. return addRequestGroup(result.front(), e, posGiven, pos);
  192. } else {
  193. throw DL_ABORT_EX("No URI to download.");
  194. }
  195. }
  196. #ifdef ENABLE_BITTORRENT
  197. BDE AddTorrentXmlRpcMethod::process
  198. (const XmlRpcRequest& req, DownloadEngine* e)
  199. {
  200. const BDE& params = req._params;
  201. assert(params.isList());
  202. if(params.empty() || !params[0].isString()) {
  203. throw DL_ABORT_EX("Torrent data is not provided.");
  204. }
  205. std::vector<std::string> uris;
  206. if(params.size() > 1 && params[1].isList()) {
  207. extractUris(std::back_inserter(uris), params[1]);
  208. }
  209. SharedHandle<Option> requestOption(new Option(*e->option));
  210. if(hasDictParam(params, 2)) {
  211. gatherRequestOption(requestOption, params[2]);
  212. }
  213. size_t pos = 0;
  214. bool posGiven = false;
  215. getPosParam(params, 3, posGiven, pos);
  216. std::vector<SharedHandle<RequestGroup> > result;
  217. createRequestGroupForBitTorrent(result, requestOption,
  218. uris,
  219. params[0].s());
  220. if(!result.empty()) {
  221. return addRequestGroup(result.front(), e, posGiven, pos);
  222. } else {
  223. throw DL_ABORT_EX("No Torrent to download.");
  224. }
  225. }
  226. #endif // ENABLE_BITTORRENT
  227. #ifdef ENABLE_METALINK
  228. BDE AddMetalinkXmlRpcMethod::process
  229. (const XmlRpcRequest& req, DownloadEngine* e)
  230. {
  231. const BDE& params = req._params;
  232. assert(params.isList());
  233. if(params.empty() || !params[0].isString()) {
  234. throw DL_ABORT_EX("Metalink data is not provided.");
  235. }
  236. SharedHandle<Option> requestOption(new Option(*e->option));
  237. if(hasDictParam(params, 1)) {
  238. gatherRequestOption(requestOption, params[1]);
  239. };
  240. size_t pos = 0;
  241. bool posGiven = false;
  242. getPosParam(params, 2, posGiven, pos);
  243. std::vector<SharedHandle<RequestGroup> > result;
  244. createRequestGroupForMetalink(result, requestOption, params[0].s());
  245. if(!result.empty()) {
  246. if(posGiven) {
  247. e->_requestGroupMan->insertReservedGroup(pos, result);
  248. } else {
  249. e->_requestGroupMan->addReservedGroup(result);
  250. }
  251. BDE gids = BDE::list();
  252. for(std::vector<SharedHandle<RequestGroup> >::const_iterator i =
  253. result.begin(), eoi = result.end(); i != eoi; ++i) {
  254. gids << BDE(util::itos((*i)->getGID()));
  255. }
  256. return gids;
  257. } else {
  258. throw DL_ABORT_EX("No files to download.");
  259. }
  260. }
  261. #endif // ENABLE_METALINK
  262. static BDE removeDownload
  263. (const XmlRpcRequest& req, DownloadEngine* e, bool forceRemove)
  264. {
  265. const BDE& params = req._params;
  266. assert(params.isList());
  267. if(params.empty() || !params[0].isString()) {
  268. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  269. }
  270. int32_t gid = util::parseInt(params[0].s());
  271. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  272. if(group.isNull()) {
  273. group = e->_requestGroupMan->findReservedGroup(gid);
  274. if(group.isNull()) {
  275. throw DL_ABORT_EX
  276. (StringFormat("Active Download not found for GID#%d", gid).str());
  277. }
  278. if(group->isDependencyResolved()) {
  279. e->_requestGroupMan->removeReservedGroup(gid);
  280. } else {
  281. throw DL_ABORT_EX
  282. (StringFormat("GID#%d cannot be removed now", gid).str());
  283. }
  284. } else {
  285. if(forceRemove) {
  286. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  287. } else {
  288. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  289. }
  290. }
  291. return createGIDResponse(gid);
  292. }
  293. BDE RemoveXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  294. {
  295. return removeDownload(req, e, false);
  296. }
  297. BDE ForceRemoveXmlRpcMethod::process
  298. (const XmlRpcRequest& req, DownloadEngine* e)
  299. {
  300. return removeDownload(req, e, true);
  301. }
  302. static void createUriEntry(BDE& uriList, const SharedHandle<FileEntry>& file)
  303. {
  304. {
  305. const std::deque<std::string>& uris = file->getSpentUris();
  306. for(std::deque<std::string>::const_iterator i = uris.begin(),
  307. eoi = uris.end(); i != eoi; ++i) {
  308. BDE entry = BDE::dict();
  309. entry[KEY_URI] = *i;
  310. entry[KEY_STATUS] = BDE_USED;
  311. uriList << entry;
  312. }
  313. }
  314. {
  315. const std::deque<std::string>& uris = file->getRemainingUris();
  316. for(std::deque<std::string>::const_iterator i = uris.begin(),
  317. eoi = uris.end(); i != eoi; ++i) {
  318. BDE entry = BDE::dict();
  319. entry[KEY_URI] = *i;
  320. entry[KEY_STATUS] = BDE_WAITING;
  321. uriList << entry;
  322. }
  323. }
  324. }
  325. template<typename InputIterator>
  326. static void createFileEntry(BDE& files, InputIterator first, InputIterator last)
  327. {
  328. size_t index = 1;
  329. for(; first != last; ++first, ++index) {
  330. BDE entry = BDE::dict();
  331. entry[KEY_INDEX] = util::uitos(index);
  332. entry[KEY_PATH] = (*first)->getPath();
  333. entry[KEY_SELECTED] = (*first)->isRequested()?BDE_TRUE:BDE_FALSE;
  334. entry[KEY_LENGTH] = util::uitos((*first)->getLength());
  335. BDE uriList = BDE::list();
  336. createUriEntry(uriList, *first);
  337. entry[KEY_URIS] = uriList;
  338. files << entry;
  339. }
  340. }
  341. void gatherProgressCommon
  342. (BDE& entryDict, const SharedHandle<RequestGroup>& group)
  343. {
  344. entryDict[KEY_GID] = util::itos(group->getGID());
  345. // This is "filtered" total length if --select-file is used.
  346. entryDict[KEY_TOTAL_LENGTH] = util::uitos(group->getTotalLength());
  347. // This is "filtered" total length if --select-file is used.
  348. entryDict[KEY_COMPLETED_LENGTH] = util::uitos(group->getCompletedLength());
  349. TransferStat stat = group->calculateStat();
  350. entryDict[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  351. entryDict[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  352. entryDict[KEY_UPLOAD_LENGTH] = util::uitos(stat.getAllTimeUploadLength());
  353. entryDict[KEY_CONNECTIONS] = util::uitos(group->getNumConnection());
  354. SharedHandle<PieceStorage> ps = group->getPieceStorage();
  355. if(!ps.isNull()) {
  356. if(ps->getBitfieldLength() > 0) {
  357. entryDict[KEY_BITFIELD] = util::toHex(ps->getBitfield(),
  358. ps->getBitfieldLength());
  359. }
  360. }
  361. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  362. entryDict[KEY_PIECE_LENGTH] = util::uitos(dctx->getPieceLength());
  363. entryDict[KEY_NUM_PIECES] = util::uitos(dctx->getNumPieces());
  364. if(!group->followedBy().empty()) {
  365. BDE list = BDE::list();
  366. // The element is GID.
  367. for(std::vector<int32_t>::const_iterator i = group->followedBy().begin(),
  368. eoi = group->followedBy().end(); i != eoi; ++i) {
  369. list << util::itos(*i);
  370. }
  371. entryDict[KEY_FOLLOWED_BY] = list;
  372. }
  373. if(group->belongsTo()) {
  374. entryDict[KEY_BELONGS_TO] = util::itos(group->belongsTo());
  375. }
  376. BDE files = BDE::list();
  377. createFileEntry
  378. (files, dctx->getFileEntries().begin(), dctx->getFileEntries().end());
  379. entryDict[KEY_FILES] = files;
  380. entryDict[KEY_DIR] = group->getOption()->get(PREF_DIR);
  381. }
  382. #ifdef ENABLE_BITTORRENT
  383. void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs)
  384. {
  385. if(torrentAttrs.containsKey(bittorrent::COMMENT)) {
  386. btDict[KEY_COMMENT] = torrentAttrs[bittorrent::COMMENT];
  387. }
  388. if(torrentAttrs.containsKey(bittorrent::CREATION_DATE)) {
  389. btDict[KEY_CREATION_DATE] = torrentAttrs[bittorrent::CREATION_DATE];
  390. }
  391. if(torrentAttrs.containsKey(bittorrent::MODE)) {
  392. btDict[KEY_MODE] = torrentAttrs[bittorrent::MODE];
  393. }
  394. // Copy announceList to avoid modification on entyDict to be
  395. // affected original announceList.
  396. // TODO Would it be good to add copy() method in BDE?
  397. const BDE& announceList = torrentAttrs[bittorrent::ANNOUNCE_LIST];
  398. BDE destAnnounceList = BDE::list();
  399. for(BDE::List::const_iterator l = announceList.listBegin(),
  400. eoi = announceList.listEnd(); l != eoi; ++l) {
  401. BDE destAnnounceTier = BDE::list();
  402. for(BDE::List::const_iterator t = (*l).listBegin(),
  403. eoi2 = (*l).listEnd(); t != eoi2; ++t) {
  404. destAnnounceTier << (*t);
  405. }
  406. destAnnounceList << destAnnounceTier;
  407. }
  408. btDict[KEY_ANNOUNCE_LIST] = destAnnounceList;
  409. if(torrentAttrs.containsKey(bittorrent::METADATA)) {
  410. BDE infoDict = BDE::dict();
  411. infoDict[KEY_NAME] = torrentAttrs[bittorrent::NAME];
  412. btDict[KEY_INFO] = infoDict;
  413. }
  414. }
  415. static void gatherProgressBitTorrent
  416. (BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject)
  417. {
  418. const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s();
  419. entryDict[KEY_INFO_HASH] = util::toHex(infoHash);
  420. BDE btDict = BDE::dict();
  421. gatherBitTorrentMetadata(btDict, torrentAttrs);
  422. entryDict[KEY_BITTORRENT] = btDict;
  423. if(!btObject.isNull()) {
  424. SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
  425. assert(!peerStorage.isNull());
  426. std::vector<SharedHandle<Peer> > peers;
  427. peerStorage->getActivePeers(peers);
  428. entryDict[KEY_NUM_SEEDERS] = countSeeder(peers.begin(), peers.end());
  429. }
  430. }
  431. static void gatherPeer(BDE& peers, const SharedHandle<PeerStorage>& ps)
  432. {
  433. std::vector<SharedHandle<Peer> > activePeers;
  434. ps->getActivePeers(activePeers);
  435. for(std::vector<SharedHandle<Peer> >::const_iterator i =
  436. activePeers.begin(), eoi = activePeers.end(); i != eoi; ++i) {
  437. BDE peerEntry = BDE::dict();
  438. peerEntry[KEY_PEER_ID] = util::torrentUrlencode((*i)->getPeerId(),
  439. PEER_ID_LENGTH);
  440. peerEntry[KEY_IP] = (*i)->ipaddr;
  441. peerEntry[KEY_PORT] = util::uitos((*i)->port);
  442. peerEntry[KEY_BITFIELD] = util::toHex((*i)->getBitfield(),
  443. (*i)->getBitfieldLength());
  444. peerEntry[KEY_AM_CHOKING] = (*i)->amChoking()?BDE_TRUE:BDE_FALSE;
  445. peerEntry[KEY_PEER_CHOKING] = (*i)->peerChoking()?BDE_TRUE:BDE_FALSE;
  446. TransferStat stat = ps->getTransferStatFor(*i);
  447. peerEntry[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  448. peerEntry[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  449. peerEntry[KEY_SEEDER] = (*i)->isSeeder()?BDE_TRUE:BDE_FALSE;
  450. peers << peerEntry;
  451. }
  452. }
  453. #endif // ENABLE_BITTORRENT
  454. static void gatherProgress
  455. (BDE& entryDict, const SharedHandle<RequestGroup>& group, DownloadEngine* e)
  456. {
  457. gatherProgressCommon(entryDict, group);
  458. #ifdef ENABLE_BITTORRENT
  459. if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
  460. const BDE& torrentAttrs =
  461. group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
  462. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  463. gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
  464. }
  465. #endif // ENABLE_BITTORRENT
  466. }
  467. void gatherStoppedDownload
  468. (BDE& entryDict, const SharedHandle<DownloadResult>& ds)
  469. {
  470. entryDict[KEY_GID] = util::itos(ds->gid);
  471. entryDict[KEY_ERROR_CODE] = util::itos(static_cast<int>(ds->result));
  472. if(ds->result == downloadresultcode::IN_PROGRESS) {
  473. entryDict[KEY_STATUS] = BDE_REMOVED;
  474. } else if(ds->result == downloadresultcode::FINISHED) {
  475. entryDict[KEY_STATUS] = BDE_COMPLETE;
  476. } else {
  477. entryDict[KEY_STATUS] = BDE_ERROR;
  478. }
  479. if(!ds->followedBy.empty()) {
  480. BDE list = BDE::list();
  481. // The element is GID.
  482. for(std::vector<int32_t>::const_iterator i = ds->followedBy.begin(),
  483. eoi = ds->followedBy.end(); i != eoi; ++i) {
  484. list << util::itos(*i);
  485. }
  486. entryDict[KEY_FOLLOWED_BY] = list;
  487. }
  488. if(ds->belongsTo) {
  489. entryDict[KEY_BELONGS_TO] = util::itos(ds->belongsTo);
  490. }
  491. BDE files = BDE::list();
  492. createFileEntry(files, ds->fileEntries.begin(), ds->fileEntries.end());
  493. entryDict[KEY_FILES] = files;
  494. }
  495. static
  496. SharedHandle<RequestGroup>
  497. findRequestGroup(const SharedHandle<RequestGroupMan>& rgman, int32_t gid)
  498. {
  499. SharedHandle<RequestGroup> group = rgman->findRequestGroup(gid);
  500. if(group.isNull()) {
  501. group = rgman->findReservedGroup(gid);
  502. }
  503. return group;
  504. }
  505. BDE GetFilesXmlRpcMethod::process
  506. (const XmlRpcRequest& req, DownloadEngine* e)
  507. {
  508. const BDE& params = req._params;
  509. assert(params.isList());
  510. if(params.empty() || !params[0].isString()) {
  511. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  512. }
  513. int32_t gid = util::parseInt(params[0].s());
  514. BDE files = BDE::list();
  515. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  516. if(group.isNull()) {
  517. SharedHandle<DownloadResult> dr =
  518. e->_requestGroupMan->findDownloadResult(gid);
  519. if(dr.isNull()) {
  520. throw DL_ABORT_EX
  521. (StringFormat("No file data is available for GID#%d", gid).str());
  522. } else {
  523. createFileEntry(files, dr->fileEntries.begin(), dr->fileEntries.end());
  524. }
  525. } else {
  526. createFileEntry(files,
  527. group->getDownloadContext()->getFileEntries().begin(),
  528. group->getDownloadContext()->getFileEntries().end());
  529. }
  530. return files;
  531. }
  532. BDE GetUrisXmlRpcMethod::process
  533. (const XmlRpcRequest& req, DownloadEngine* e)
  534. {
  535. const BDE& params = req._params;
  536. assert(params.isList());
  537. if(params.empty() || !params[0].isString()) {
  538. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  539. }
  540. int32_t gid = util::parseInt(params[0].s());
  541. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  542. if(group.isNull()) {
  543. throw DL_ABORT_EX
  544. (StringFormat("No URI data is available for GID#%d", gid).str());
  545. }
  546. BDE uriList = BDE::list();
  547. // TODO Current implementation just returns first FileEntry's URIs.
  548. if(!group->getDownloadContext()->getFileEntries().empty()) {
  549. createUriEntry(uriList, group->getDownloadContext()->getFirstFileEntry());
  550. }
  551. return uriList;
  552. }
  553. #ifdef ENABLE_BITTORRENT
  554. BDE GetPeersXmlRpcMethod::process
  555. (const XmlRpcRequest& req, DownloadEngine* e)
  556. {
  557. const BDE& params = req._params;
  558. assert(params.isList());
  559. if(params.empty() || !params[0].isString()) {
  560. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  561. }
  562. int32_t gid = util::parseInt(params[0].s());
  563. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  564. if(group.isNull()) {
  565. throw DL_ABORT_EX
  566. (StringFormat("No peer data is available for GID#%d", gid).str());
  567. }
  568. BDE peers = BDE::list();
  569. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  570. if(!btObject.isNull()) {
  571. assert(!btObject._peerStorage.isNull());
  572. gatherPeer(peers, btObject._peerStorage);
  573. }
  574. return peers;
  575. }
  576. #endif // ENABLE_BITTORRENT
  577. BDE TellStatusXmlRpcMethod::process
  578. (const XmlRpcRequest& req, DownloadEngine* e)
  579. {
  580. const BDE& params = req._params;
  581. assert(params.isList());
  582. if(params.empty() || !params[0].isString()) {
  583. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  584. }
  585. int32_t gid = util::parseInt(params[0].s());
  586. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  587. BDE entryDict = BDE::dict();
  588. if(group.isNull()) {
  589. group = e->_requestGroupMan->findReservedGroup(gid);
  590. if(group.isNull()) {
  591. SharedHandle<DownloadResult> ds =
  592. e->_requestGroupMan->findDownloadResult(gid);
  593. if(ds.isNull()) {
  594. throw DL_ABORT_EX
  595. (StringFormat("No such download for GID#%d", gid).str());
  596. }
  597. gatherStoppedDownload(entryDict, ds);
  598. } else {
  599. entryDict[KEY_STATUS] = BDE_WAITING;
  600. gatherProgress(entryDict, group, e);
  601. }
  602. } else {
  603. entryDict[KEY_STATUS] = BDE_ACTIVE;
  604. gatherProgress(entryDict, group, e);
  605. }
  606. return entryDict;
  607. }
  608. BDE TellActiveXmlRpcMethod::process
  609. (const XmlRpcRequest& req, DownloadEngine* e)
  610. {
  611. BDE list = BDE::list();
  612. const std::deque<SharedHandle<RequestGroup> >& groups =
  613. e->_requestGroupMan->getRequestGroups();
  614. for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
  615. groups.begin(), eoi = groups.end(); i != eoi; ++i) {
  616. BDE entryDict = BDE::dict();
  617. entryDict[KEY_STATUS] = BDE_ACTIVE;
  618. gatherProgress(entryDict, *i, e);
  619. list << entryDict;
  620. }
  621. return list;
  622. }
  623. const std::deque<SharedHandle<RequestGroup> >&
  624. TellWaitingXmlRpcMethod::getItems(DownloadEngine* e) const
  625. {
  626. return e->_requestGroupMan->getReservedGroups();
  627. }
  628. void TellWaitingXmlRpcMethod::createEntry
  629. (BDE& entryDict, const SharedHandle<RequestGroup>& item,
  630. DownloadEngine* e) const
  631. {
  632. entryDict[KEY_STATUS] = BDE_WAITING;
  633. gatherProgress(entryDict, item, e);
  634. }
  635. const std::deque<SharedHandle<DownloadResult> >&
  636. TellStoppedXmlRpcMethod::getItems(DownloadEngine* e) const
  637. {
  638. return e->_requestGroupMan->getDownloadResults();
  639. }
  640. void TellStoppedXmlRpcMethod::createEntry
  641. (BDE& entryDict, const SharedHandle<DownloadResult>& item,
  642. DownloadEngine* e) const
  643. {
  644. gatherStoppedDownload(entryDict, item);
  645. }
  646. BDE PurgeDownloadResultXmlRpcMethod::process
  647. (const XmlRpcRequest& req, DownloadEngine* e)
  648. {
  649. e->_requestGroupMan->purgeDownloadResult();
  650. return BDE_OK;
  651. }
  652. BDE ChangeOptionXmlRpcMethod::process
  653. (const XmlRpcRequest& req, DownloadEngine* e)
  654. {
  655. const BDE& params = req._params;
  656. assert(params.isList());
  657. if(params.empty() || !params[0].isString()) {
  658. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  659. }
  660. int32_t gid = util::parseInt(params[0].s());
  661. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  662. if(group.isNull()) {
  663. throw DL_ABORT_EX
  664. (StringFormat("Cannot change option for GID#%d", gid).str());
  665. }
  666. SharedHandle<Option> option(new Option());
  667. if(params.size() > 1 && params[1].isDict()) {
  668. gatherChangeableOption(option, params[1]);
  669. applyChangeableOption(group->getOption().get(), option.get());
  670. if(option->defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  671. group->setMaxDownloadSpeedLimit
  672. (option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  673. }
  674. if(option->defined(PREF_MAX_UPLOAD_LIMIT)) {
  675. group->setMaxUploadSpeedLimit(option->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  676. }
  677. #ifdef ENABLE_BITTORRENT
  678. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  679. if(!btObject.isNull()) {
  680. if(option->defined(PREF_BT_MAX_PEERS)) {
  681. btObject._btRuntime->setMaxPeers(option->getAsInt(PREF_BT_MAX_PEERS));
  682. }
  683. }
  684. #endif // ENABLE_BITTORRENT
  685. }
  686. return BDE_OK;
  687. }
  688. BDE ChangeGlobalOptionXmlRpcMethod::process
  689. (const XmlRpcRequest& req, DownloadEngine* e)
  690. {
  691. const BDE& params = req._params;
  692. assert(params.isList());
  693. if(params.empty() || !params[0].isDict()) {
  694. return BDE_OK;
  695. }
  696. SharedHandle<Option> option(new Option());
  697. gatherChangeableGlobalOption(option, params[0]);
  698. applyChangeableGlobalOption(e->option, option.get());
  699. if(option->defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  700. e->_requestGroupMan->setMaxOverallDownloadSpeedLimit
  701. (option->getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  702. }
  703. if(option->defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  704. e->_requestGroupMan->setMaxOverallUploadSpeedLimit
  705. (option->getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  706. }
  707. if(option->defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  708. e->_requestGroupMan->setMaxSimultaneousDownloads
  709. (option->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  710. e->_requestGroupMan->requestQueueCheck();
  711. }
  712. return BDE_OK;
  713. }
  714. BDE GetVersionXmlRpcMethod::process
  715. (const XmlRpcRequest& req, DownloadEngine* e)
  716. {
  717. BDE result = BDE::dict();
  718. result[KEY_VERSION] = std::string(PACKAGE_VERSION);
  719. BDE featureList = BDE::list();
  720. const FeatureMap& features = FeatureConfig::getInstance()->getFeatures();
  721. for(FeatureMap::const_iterator i = features.begin(), eoi = features.end();
  722. i != eoi;++i){
  723. if((*i).second) {
  724. featureList << (*i).first;
  725. }
  726. }
  727. result[KEY_ENABLED_FEATURES] = featureList;
  728. return result;
  729. }
  730. template<typename InputIterator>
  731. static void pushRequestOption
  732. (BDE& dict, InputIterator optionFirst, InputIterator optionLast)
  733. {
  734. const std::set<std::string>& requestOptions = listRequestOptions();
  735. for(; optionFirst != optionLast; ++optionFirst) {
  736. if(requestOptions.count((*optionFirst).first)) {
  737. dict[(*optionFirst).first] = (*optionFirst).second;
  738. }
  739. }
  740. }
  741. BDE GetOptionXmlRpcMethod::process
  742. (const XmlRpcRequest& req, DownloadEngine* e)
  743. {
  744. const BDE& params = req._params;
  745. assert(params.isList());
  746. if(params.empty() || !params[0].isString()) {
  747. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  748. }
  749. int32_t gid = util::parseInt(params[0].s());
  750. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  751. if(group.isNull()) {
  752. throw DL_ABORT_EX
  753. (StringFormat("Cannot get option for GID#%d", gid).str());
  754. }
  755. BDE result = BDE::dict();
  756. SharedHandle<Option> option = group->getOption();
  757. pushRequestOption(result, option->begin(), option->end());
  758. return result;
  759. }
  760. BDE GetGlobalOptionXmlRpcMethod::process
  761. (const XmlRpcRequest& req, DownloadEngine* e)
  762. {
  763. BDE result = BDE::dict();
  764. for(std::map<std::string, std::string>::const_iterator i = e->option->begin(),
  765. eoi = e->option->end(); i != eoi; ++i) {
  766. SharedHandle<OptionHandler> h = _optionParser->findByName((*i).first);
  767. if(!h.isNull() && !h->isHidden()) {
  768. result[(*i).first] = (*i).second;
  769. }
  770. }
  771. return result;
  772. }
  773. BDE ChangePositionXmlRpcMethod::process
  774. (const XmlRpcRequest& req, DownloadEngine* e)
  775. {
  776. const BDE& params = req._params;
  777. assert(params.isList());
  778. if(params.size() != 3 ||
  779. !params[0].isString() || !params[1].isInteger() || !params[2].isString()) {
  780. throw DL_ABORT_EX("Illegal argument.");
  781. }
  782. int32_t gid = util::parseInt(params[0].s());
  783. int pos = params[1].i();
  784. const std::string& howStr = params[2].s();
  785. RequestGroupMan::HOW how;
  786. if(howStr == "POS_SET") {
  787. how = RequestGroupMan::POS_SET;
  788. } else if(howStr == "POS_CUR") {
  789. how = RequestGroupMan::POS_CUR;
  790. } else if(howStr == "POS_END") {
  791. how = RequestGroupMan::POS_END;
  792. } else {
  793. throw DL_ABORT_EX("Illegal argument.");
  794. }
  795. size_t destPos =
  796. e->_requestGroupMan->changeReservedGroupPosition(gid, pos, how);
  797. BDE result(destPos);
  798. return result;
  799. }
  800. BDE GetSessionInfoXmlRpcMethod::process
  801. (const XmlRpcRequest& req, DownloadEngine* e)
  802. {
  803. BDE result = BDE::dict();
  804. result[KEY_SESSION_ID] = util::toHex(e->getSessionId());
  805. return result;
  806. }
  807. BDE GetServersXmlRpcMethod::process
  808. (const XmlRpcRequest& req, DownloadEngine* e)
  809. {
  810. const BDE& params = req._params;
  811. assert(params.isList());
  812. if(params.empty() || !params[0].isString()) {
  813. throw DL_ABORT_EX("Bad request");
  814. }
  815. int32_t gid = util::parseInt(params[0].s());
  816. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  817. if(group.isNull()) {
  818. throw DL_ABORT_EX(StringFormat("No active download for GID#%d", gid).str());
  819. }
  820. SharedHandle<DownloadContext> dctx = group->getDownloadContext();
  821. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  822. BDE result = BDE::list();
  823. size_t index = 1;
  824. for(std::vector<SharedHandle<FileEntry> >::const_iterator fi = files.begin(),
  825. eoi = files.end(); fi != eoi; ++fi, ++index) {
  826. BDE fileEntry = BDE::dict();
  827. fileEntry[KEY_INDEX] = util::uitos(index);
  828. BDE servers = BDE::list();
  829. const std::deque<SharedHandle<Request> >& requests =
  830. (*fi)->getInFlightRequests();
  831. for(std::deque<SharedHandle<Request> >::const_iterator ri =requests.begin(),
  832. eoi = requests.end(); ri != eoi; ++ri) {
  833. SharedHandle<PeerStat> ps = (*ri)->getPeerStat();
  834. if(!ps.isNull()) {
  835. BDE serverEntry = BDE::dict();
  836. serverEntry[KEY_URI] = (*ri)->getUrl();
  837. serverEntry[KEY_CURRENT_URI] = (*ri)->getCurrentUrl();
  838. serverEntry[KEY_DOWNLOAD_SPEED] =
  839. util::uitos(ps->calculateDownloadSpeed());
  840. servers << serverEntry;
  841. }
  842. }
  843. fileEntry[KEY_SERVERS] = servers;
  844. result << fileEntry;
  845. }
  846. return result;
  847. }
  848. BDE ChangeUriXmlRpcMethod::process
  849. (const XmlRpcRequest& req, DownloadEngine* e)
  850. {
  851. const BDE& params = req._params;
  852. assert(params.isList());
  853. if(params.size() < 4 ||
  854. !params[0].isString() || !params[1].isInteger() ||
  855. !params[2].isList() || !params[3].isList() ||
  856. params[1].i() <= 0) {
  857. throw DL_ABORT_EX("Bad request");
  858. }
  859. size_t pos = 0;
  860. bool posGiven = false;
  861. getPosParam(params, 4, posGiven, pos);
  862. int32_t gid = util::parseInt(params[0].s());
  863. size_t index = params[1].i()-1;
  864. const BDE& deluris = params[2];
  865. const BDE& adduris = params[3];
  866. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  867. if(group.isNull()) {
  868. throw DL_ABORT_EX
  869. (StringFormat("Cannot remove URIs from GID#%d", gid).str());
  870. }
  871. SharedHandle<DownloadContext> dctx = group->getDownloadContext();
  872. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  873. if(files.size() <= index) {
  874. throw DL_ABORT_EX(StringFormat("fileIndex is out of range").str());
  875. }
  876. SharedHandle<FileEntry> s = files[index];
  877. size_t delcount = 0;
  878. for(BDE::List::const_iterator i = deluris.listBegin(),
  879. eoi = deluris.listEnd(); i != eoi; ++i) {
  880. if(s->removeUri((*i).s())) {
  881. ++delcount;
  882. }
  883. }
  884. size_t addcount = 0;
  885. if(posGiven) {
  886. for(BDE::List::const_iterator i = adduris.listBegin(),
  887. eoi = adduris.listEnd(); i != eoi; ++i) {
  888. if(s->insertUri((*i).s(), pos)) {
  889. ++addcount;
  890. ++pos;
  891. }
  892. }
  893. } else {
  894. for(BDE::List::const_iterator i = adduris.listBegin(),
  895. eoi = adduris.listEnd(); i != eoi; ++i) {
  896. if(s->addUri((*i).s())) {
  897. ++addcount;
  898. }
  899. }
  900. }
  901. if(addcount) {
  902. std::vector<Command*> commands;
  903. group->createNextCommand(commands, e);
  904. e->addCommand(commands);
  905. }
  906. BDE res = BDE::list();
  907. res << delcount;
  908. res << addcount;
  909. return res;
  910. }
  911. BDE SystemMulticallXmlRpcMethod::process
  912. (const XmlRpcRequest& req, DownloadEngine* e)
  913. {
  914. const BDE& params = req._params;
  915. assert(params.isList());
  916. if(params.size() != 1) {
  917. throw DL_ABORT_EX("Illegal argument. One item list is expected.");
  918. }
  919. const BDE& methodSpecs = params[0];
  920. BDE list = BDE::list();
  921. for(BDE::List::const_iterator i = methodSpecs.listBegin(),
  922. eoi = methodSpecs.listEnd(); i != eoi; ++i) {
  923. if(!(*i).isDict()) {
  924. list << createErrorResponse
  925. (DL_ABORT_EX("system.multicall expected struct."));
  926. continue;
  927. }
  928. if(!(*i).containsKey(KEY_METHOD_NAME) ||
  929. !(*i).containsKey(KEY_PARAMS)) {
  930. list << createErrorResponse
  931. (DL_ABORT_EX("Missing methodName or params."));
  932. continue;
  933. }
  934. const std::string& methodName = (*i)[KEY_METHOD_NAME].s();
  935. if(methodName == getMethodName()) {
  936. list << createErrorResponse
  937. (DL_ABORT_EX("Recursive system.multicall forbidden."));
  938. continue;
  939. }
  940. SharedHandle<XmlRpcMethod> method = XmlRpcMethodFactory::create(methodName);
  941. XmlRpcRequest innerReq(methodName, (*i)[KEY_PARAMS]);
  942. XmlRpcResponse res = method->execute(innerReq, e);
  943. if(res._code == 0) {
  944. BDE l = BDE::list();
  945. l << res._param;
  946. list << l;
  947. } else {
  948. list << res._param;
  949. }
  950. }
  951. return list;
  952. }
  953. BDE NoSuchMethodXmlRpcMethod::process
  954. (const XmlRpcRequest& req, DownloadEngine* e)
  955. {
  956. throw DL_ABORT_EX
  957. (StringFormat("No such method: %s", req._methodName.c_str()).str());
  958. }
  959. } // namespace xmlrpc
  960. } // namespace aria2