XmlRpcMethodImpl.cc 30 KB

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