XmlRpcMethodImpl.cc 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  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(gid_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. gid_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<gid_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] =
  429. util::uitos(countSeeder(peers.begin(), peers.end()));
  430. }
  431. }
  432. static void gatherPeer(BDE& peers, const SharedHandle<PeerStorage>& ps)
  433. {
  434. std::vector<SharedHandle<Peer> > activePeers;
  435. ps->getActivePeers(activePeers);
  436. for(std::vector<SharedHandle<Peer> >::const_iterator i =
  437. activePeers.begin(), eoi = activePeers.end(); i != eoi; ++i) {
  438. BDE peerEntry = BDE::dict();
  439. peerEntry[KEY_PEER_ID] = util::torrentPercentEncode((*i)->getPeerId(),
  440. PEER_ID_LENGTH);
  441. peerEntry[KEY_IP] = (*i)->ipaddr;
  442. if((*i)->isIncomingPeer()) {
  443. peerEntry[KEY_PORT] = std::string("0");
  444. } else {
  445. peerEntry[KEY_PORT] = util::uitos((*i)->port);
  446. }
  447. peerEntry[KEY_BITFIELD] = util::toHex((*i)->getBitfield(),
  448. (*i)->getBitfieldLength());
  449. peerEntry[KEY_AM_CHOKING] = (*i)->amChoking()?BDE_TRUE:BDE_FALSE;
  450. peerEntry[KEY_PEER_CHOKING] = (*i)->peerChoking()?BDE_TRUE:BDE_FALSE;
  451. TransferStat stat = ps->getTransferStatFor(*i);
  452. peerEntry[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  453. peerEntry[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  454. peerEntry[KEY_SEEDER] = (*i)->isSeeder()?BDE_TRUE:BDE_FALSE;
  455. peers << peerEntry;
  456. }
  457. }
  458. #endif // ENABLE_BITTORRENT
  459. static void gatherProgress
  460. (BDE& entryDict, const SharedHandle<RequestGroup>& group, DownloadEngine* e)
  461. {
  462. gatherProgressCommon(entryDict, group);
  463. #ifdef ENABLE_BITTORRENT
  464. if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
  465. const BDE& torrentAttrs =
  466. group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
  467. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  468. gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
  469. }
  470. #endif // ENABLE_BITTORRENT
  471. }
  472. void gatherStoppedDownload
  473. (BDE& entryDict, const SharedHandle<DownloadResult>& ds)
  474. {
  475. entryDict[KEY_GID] = util::itos(ds->gid);
  476. entryDict[KEY_ERROR_CODE] = util::itos(static_cast<int>(ds->result));
  477. if(ds->result == downloadresultcode::IN_PROGRESS) {
  478. entryDict[KEY_STATUS] = BDE_REMOVED;
  479. } else if(ds->result == downloadresultcode::FINISHED) {
  480. entryDict[KEY_STATUS] = BDE_COMPLETE;
  481. } else {
  482. entryDict[KEY_STATUS] = BDE_ERROR;
  483. }
  484. if(!ds->followedBy.empty()) {
  485. BDE list = BDE::list();
  486. // The element is GID.
  487. for(std::vector<gid_t>::const_iterator i = ds->followedBy.begin(),
  488. eoi = ds->followedBy.end(); i != eoi; ++i) {
  489. list << util::itos(*i);
  490. }
  491. entryDict[KEY_FOLLOWED_BY] = list;
  492. }
  493. if(ds->belongsTo) {
  494. entryDict[KEY_BELONGS_TO] = util::itos(ds->belongsTo);
  495. }
  496. BDE files = BDE::list();
  497. createFileEntry(files, ds->fileEntries.begin(), ds->fileEntries.end());
  498. entryDict[KEY_FILES] = files;
  499. }
  500. static
  501. SharedHandle<RequestGroup>
  502. findRequestGroup(const SharedHandle<RequestGroupMan>& rgman, gid_t gid)
  503. {
  504. SharedHandle<RequestGroup> group = rgman->findRequestGroup(gid);
  505. if(group.isNull()) {
  506. group = rgman->findReservedGroup(gid);
  507. }
  508. return group;
  509. }
  510. BDE GetFilesXmlRpcMethod::process
  511. (const XmlRpcRequest& req, DownloadEngine* e)
  512. {
  513. const BDE& params = req._params;
  514. assert(params.isList());
  515. if(params.empty() || !params[0].isString()) {
  516. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  517. }
  518. gid_t gid = util::parseInt(params[0].s());
  519. BDE files = BDE::list();
  520. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  521. if(group.isNull()) {
  522. SharedHandle<DownloadResult> dr =
  523. e->_requestGroupMan->findDownloadResult(gid);
  524. if(dr.isNull()) {
  525. throw DL_ABORT_EX
  526. (StringFormat("No file data is available for GID#%d", gid).str());
  527. } else {
  528. createFileEntry(files, dr->fileEntries.begin(), dr->fileEntries.end());
  529. }
  530. } else {
  531. createFileEntry(files,
  532. group->getDownloadContext()->getFileEntries().begin(),
  533. group->getDownloadContext()->getFileEntries().end());
  534. }
  535. return files;
  536. }
  537. BDE GetUrisXmlRpcMethod::process
  538. (const XmlRpcRequest& req, DownloadEngine* e)
  539. {
  540. const BDE& params = req._params;
  541. assert(params.isList());
  542. if(params.empty() || !params[0].isString()) {
  543. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  544. }
  545. gid_t gid = util::parseInt(params[0].s());
  546. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  547. if(group.isNull()) {
  548. throw DL_ABORT_EX
  549. (StringFormat("No URI data is available for GID#%d", gid).str());
  550. }
  551. BDE uriList = BDE::list();
  552. // TODO Current implementation just returns first FileEntry's URIs.
  553. if(!group->getDownloadContext()->getFileEntries().empty()) {
  554. createUriEntry(uriList, group->getDownloadContext()->getFirstFileEntry());
  555. }
  556. return uriList;
  557. }
  558. #ifdef ENABLE_BITTORRENT
  559. BDE GetPeersXmlRpcMethod::process
  560. (const XmlRpcRequest& req, DownloadEngine* e)
  561. {
  562. const BDE& params = req._params;
  563. assert(params.isList());
  564. if(params.empty() || !params[0].isString()) {
  565. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  566. }
  567. gid_t gid = util::parseInt(params[0].s());
  568. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  569. if(group.isNull()) {
  570. throw DL_ABORT_EX
  571. (StringFormat("No peer data is available for GID#%d", gid).str());
  572. }
  573. BDE peers = BDE::list();
  574. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  575. if(!btObject.isNull()) {
  576. assert(!btObject._peerStorage.isNull());
  577. gatherPeer(peers, btObject._peerStorage);
  578. }
  579. return peers;
  580. }
  581. #endif // ENABLE_BITTORRENT
  582. BDE TellStatusXmlRpcMethod::process
  583. (const XmlRpcRequest& req, DownloadEngine* e)
  584. {
  585. const BDE& params = req._params;
  586. assert(params.isList());
  587. if(params.empty() || !params[0].isString()) {
  588. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  589. }
  590. gid_t gid = util::parseInt(params[0].s());
  591. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  592. BDE entryDict = BDE::dict();
  593. if(group.isNull()) {
  594. group = e->_requestGroupMan->findReservedGroup(gid);
  595. if(group.isNull()) {
  596. SharedHandle<DownloadResult> ds =
  597. e->_requestGroupMan->findDownloadResult(gid);
  598. if(ds.isNull()) {
  599. throw DL_ABORT_EX
  600. (StringFormat("No such download for GID#%d", gid).str());
  601. }
  602. gatherStoppedDownload(entryDict, ds);
  603. } else {
  604. entryDict[KEY_STATUS] = BDE_WAITING;
  605. gatherProgress(entryDict, group, e);
  606. }
  607. } else {
  608. entryDict[KEY_STATUS] = BDE_ACTIVE;
  609. gatherProgress(entryDict, group, e);
  610. }
  611. return entryDict;
  612. }
  613. BDE TellActiveXmlRpcMethod::process
  614. (const XmlRpcRequest& req, DownloadEngine* e)
  615. {
  616. BDE list = BDE::list();
  617. const std::deque<SharedHandle<RequestGroup> >& groups =
  618. e->_requestGroupMan->getRequestGroups();
  619. for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
  620. groups.begin(), eoi = groups.end(); i != eoi; ++i) {
  621. BDE entryDict = BDE::dict();
  622. entryDict[KEY_STATUS] = BDE_ACTIVE;
  623. gatherProgress(entryDict, *i, e);
  624. list << entryDict;
  625. }
  626. return list;
  627. }
  628. const std::deque<SharedHandle<RequestGroup> >&
  629. TellWaitingXmlRpcMethod::getItems(DownloadEngine* e) const
  630. {
  631. return e->_requestGroupMan->getReservedGroups();
  632. }
  633. void TellWaitingXmlRpcMethod::createEntry
  634. (BDE& entryDict, const SharedHandle<RequestGroup>& item,
  635. DownloadEngine* e) const
  636. {
  637. entryDict[KEY_STATUS] = BDE_WAITING;
  638. gatherProgress(entryDict, item, e);
  639. }
  640. const std::deque<SharedHandle<DownloadResult> >&
  641. TellStoppedXmlRpcMethod::getItems(DownloadEngine* e) const
  642. {
  643. return e->_requestGroupMan->getDownloadResults();
  644. }
  645. void TellStoppedXmlRpcMethod::createEntry
  646. (BDE& entryDict, const SharedHandle<DownloadResult>& item,
  647. DownloadEngine* e) const
  648. {
  649. gatherStoppedDownload(entryDict, item);
  650. }
  651. BDE PurgeDownloadResultXmlRpcMethod::process
  652. (const XmlRpcRequest& req, DownloadEngine* e)
  653. {
  654. e->_requestGroupMan->purgeDownloadResult();
  655. return BDE_OK;
  656. }
  657. BDE ChangeOptionXmlRpcMethod::process
  658. (const XmlRpcRequest& req, DownloadEngine* e)
  659. {
  660. const BDE& params = req._params;
  661. assert(params.isList());
  662. if(params.empty() || !params[0].isString()) {
  663. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  664. }
  665. gid_t gid = util::parseInt(params[0].s());
  666. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  667. if(group.isNull()) {
  668. throw DL_ABORT_EX
  669. (StringFormat("Cannot change option for GID#%d", gid).str());
  670. }
  671. SharedHandle<Option> option(new Option());
  672. if(params.size() > 1 && params[1].isDict()) {
  673. gatherChangeableOption(option, params[1]);
  674. applyChangeableOption(group->getOption().get(), option.get());
  675. if(option->defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  676. group->setMaxDownloadSpeedLimit
  677. (option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  678. }
  679. if(option->defined(PREF_MAX_UPLOAD_LIMIT)) {
  680. group->setMaxUploadSpeedLimit(option->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  681. }
  682. #ifdef ENABLE_BITTORRENT
  683. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  684. if(!btObject.isNull()) {
  685. if(option->defined(PREF_BT_MAX_PEERS)) {
  686. btObject._btRuntime->setMaxPeers(option->getAsInt(PREF_BT_MAX_PEERS));
  687. }
  688. }
  689. #endif // ENABLE_BITTORRENT
  690. }
  691. return BDE_OK;
  692. }
  693. BDE ChangeGlobalOptionXmlRpcMethod::process
  694. (const XmlRpcRequest& req, DownloadEngine* e)
  695. {
  696. const BDE& params = req._params;
  697. assert(params.isList());
  698. if(params.empty() || !params[0].isDict()) {
  699. return BDE_OK;
  700. }
  701. SharedHandle<Option> option(new Option());
  702. gatherChangeableGlobalOption(option, params[0]);
  703. applyChangeableGlobalOption(e->option, option.get());
  704. if(option->defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  705. e->_requestGroupMan->setMaxOverallDownloadSpeedLimit
  706. (option->getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  707. }
  708. if(option->defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  709. e->_requestGroupMan->setMaxOverallUploadSpeedLimit
  710. (option->getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  711. }
  712. if(option->defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  713. e->_requestGroupMan->setMaxSimultaneousDownloads
  714. (option->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  715. e->_requestGroupMan->requestQueueCheck();
  716. }
  717. return BDE_OK;
  718. }
  719. BDE GetVersionXmlRpcMethod::process
  720. (const XmlRpcRequest& req, DownloadEngine* e)
  721. {
  722. BDE result = BDE::dict();
  723. result[KEY_VERSION] = std::string(PACKAGE_VERSION);
  724. BDE featureList = BDE::list();
  725. const FeatureMap& features = FeatureConfig::getInstance()->getFeatures();
  726. for(FeatureMap::const_iterator i = features.begin(), eoi = features.end();
  727. i != eoi;++i){
  728. if((*i).second) {
  729. featureList << (*i).first;
  730. }
  731. }
  732. result[KEY_ENABLED_FEATURES] = featureList;
  733. return result;
  734. }
  735. template<typename InputIterator>
  736. static void pushRequestOption
  737. (BDE& dict, InputIterator optionFirst, InputIterator optionLast)
  738. {
  739. const std::set<std::string>& requestOptions = listRequestOptions();
  740. for(; optionFirst != optionLast; ++optionFirst) {
  741. if(requestOptions.count((*optionFirst).first)) {
  742. dict[(*optionFirst).first] = (*optionFirst).second;
  743. }
  744. }
  745. }
  746. BDE GetOptionXmlRpcMethod::process
  747. (const XmlRpcRequest& req, DownloadEngine* e)
  748. {
  749. const BDE& params = req._params;
  750. assert(params.isList());
  751. if(params.empty() || !params[0].isString()) {
  752. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  753. }
  754. gid_t gid = util::parseInt(params[0].s());
  755. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  756. if(group.isNull()) {
  757. throw DL_ABORT_EX
  758. (StringFormat("Cannot get option for GID#%d", gid).str());
  759. }
  760. BDE result = BDE::dict();
  761. SharedHandle<Option> option = group->getOption();
  762. pushRequestOption(result, option->begin(), option->end());
  763. return result;
  764. }
  765. BDE GetGlobalOptionXmlRpcMethod::process
  766. (const XmlRpcRequest& req, DownloadEngine* e)
  767. {
  768. BDE result = BDE::dict();
  769. for(std::map<std::string, std::string>::const_iterator i = e->option->begin(),
  770. eoi = e->option->end(); i != eoi; ++i) {
  771. SharedHandle<OptionHandler> h = _optionParser->findByName((*i).first);
  772. if(!h.isNull() && !h->isHidden()) {
  773. result[(*i).first] = (*i).second;
  774. }
  775. }
  776. return result;
  777. }
  778. BDE ChangePositionXmlRpcMethod::process
  779. (const XmlRpcRequest& req, DownloadEngine* e)
  780. {
  781. const BDE& params = req._params;
  782. assert(params.isList());
  783. if(params.size() != 3 ||
  784. !params[0].isString() || !params[1].isInteger() || !params[2].isString()) {
  785. throw DL_ABORT_EX("Illegal argument.");
  786. }
  787. gid_t gid = util::parseInt(params[0].s());
  788. int pos = params[1].i();
  789. const std::string& howStr = params[2].s();
  790. RequestGroupMan::HOW how;
  791. if(howStr == "POS_SET") {
  792. how = RequestGroupMan::POS_SET;
  793. } else if(howStr == "POS_CUR") {
  794. how = RequestGroupMan::POS_CUR;
  795. } else if(howStr == "POS_END") {
  796. how = RequestGroupMan::POS_END;
  797. } else {
  798. throw DL_ABORT_EX("Illegal argument.");
  799. }
  800. size_t destPos =
  801. e->_requestGroupMan->changeReservedGroupPosition(gid, pos, how);
  802. BDE result(destPos);
  803. return result;
  804. }
  805. BDE GetSessionInfoXmlRpcMethod::process
  806. (const XmlRpcRequest& req, DownloadEngine* e)
  807. {
  808. BDE result = BDE::dict();
  809. result[KEY_SESSION_ID] = util::toHex(e->getSessionId());
  810. return result;
  811. }
  812. BDE GetServersXmlRpcMethod::process
  813. (const XmlRpcRequest& req, DownloadEngine* e)
  814. {
  815. const BDE& params = req._params;
  816. assert(params.isList());
  817. if(params.empty() || !params[0].isString()) {
  818. throw DL_ABORT_EX("Bad request");
  819. }
  820. gid_t gid = util::parseInt(params[0].s());
  821. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  822. if(group.isNull()) {
  823. throw DL_ABORT_EX(StringFormat("No active download for GID#%d", gid).str());
  824. }
  825. SharedHandle<DownloadContext> dctx = group->getDownloadContext();
  826. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  827. BDE result = BDE::list();
  828. size_t index = 1;
  829. for(std::vector<SharedHandle<FileEntry> >::const_iterator fi = files.begin(),
  830. eoi = files.end(); fi != eoi; ++fi, ++index) {
  831. BDE fileEntry = BDE::dict();
  832. fileEntry[KEY_INDEX] = util::uitos(index);
  833. BDE servers = BDE::list();
  834. const std::deque<SharedHandle<Request> >& requests =
  835. (*fi)->getInFlightRequests();
  836. for(std::deque<SharedHandle<Request> >::const_iterator ri =requests.begin(),
  837. eoi = requests.end(); ri != eoi; ++ri) {
  838. SharedHandle<PeerStat> ps = (*ri)->getPeerStat();
  839. if(!ps.isNull()) {
  840. BDE serverEntry = BDE::dict();
  841. serverEntry[KEY_URI] = (*ri)->getUri();
  842. serverEntry[KEY_CURRENT_URI] = (*ri)->getCurrentUri();
  843. serverEntry[KEY_DOWNLOAD_SPEED] =
  844. util::uitos(ps->calculateDownloadSpeed());
  845. servers << serverEntry;
  846. }
  847. }
  848. fileEntry[KEY_SERVERS] = servers;
  849. result << fileEntry;
  850. }
  851. return result;
  852. }
  853. BDE ChangeUriXmlRpcMethod::process
  854. (const XmlRpcRequest& req, DownloadEngine* e)
  855. {
  856. const BDE& params = req._params;
  857. assert(params.isList());
  858. if(params.size() < 4 ||
  859. !params[0].isString() || !params[1].isInteger() ||
  860. !params[2].isList() || !params[3].isList() ||
  861. params[1].i() <= 0) {
  862. throw DL_ABORT_EX("Bad request");
  863. }
  864. size_t pos = 0;
  865. bool posGiven = false;
  866. getPosParam(params, 4, posGiven, pos);
  867. gid_t gid = util::parseInt(params[0].s());
  868. size_t index = params[1].i()-1;
  869. const BDE& deluris = params[2];
  870. const BDE& adduris = params[3];
  871. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  872. if(group.isNull()) {
  873. throw DL_ABORT_EX
  874. (StringFormat("Cannot remove URIs from GID#%d", gid).str());
  875. }
  876. SharedHandle<DownloadContext> dctx = group->getDownloadContext();
  877. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  878. if(files.size() <= index) {
  879. throw DL_ABORT_EX(StringFormat("fileIndex is out of range").str());
  880. }
  881. SharedHandle<FileEntry> s = files[index];
  882. size_t delcount = 0;
  883. for(BDE::List::const_iterator i = deluris.listBegin(),
  884. eoi = deluris.listEnd(); i != eoi; ++i) {
  885. if(s->removeUri((*i).s())) {
  886. ++delcount;
  887. }
  888. }
  889. size_t addcount = 0;
  890. if(posGiven) {
  891. for(BDE::List::const_iterator i = adduris.listBegin(),
  892. eoi = adduris.listEnd(); i != eoi; ++i) {
  893. if(s->insertUri((*i).s(), pos)) {
  894. ++addcount;
  895. ++pos;
  896. }
  897. }
  898. } else {
  899. for(BDE::List::const_iterator i = adduris.listBegin(),
  900. eoi = adduris.listEnd(); i != eoi; ++i) {
  901. if(s->addUri((*i).s())) {
  902. ++addcount;
  903. }
  904. }
  905. }
  906. if(addcount) {
  907. std::vector<Command*> commands;
  908. group->createNextCommand(commands, e);
  909. e->addCommand(commands);
  910. }
  911. BDE res = BDE::list();
  912. res << delcount;
  913. res << addcount;
  914. return res;
  915. }
  916. BDE SystemMulticallXmlRpcMethod::process
  917. (const XmlRpcRequest& req, DownloadEngine* e)
  918. {
  919. const BDE& params = req._params;
  920. assert(params.isList());
  921. if(params.size() != 1) {
  922. throw DL_ABORT_EX("Illegal argument. One item list is expected.");
  923. }
  924. const BDE& methodSpecs = params[0];
  925. BDE list = BDE::list();
  926. for(BDE::List::const_iterator i = methodSpecs.listBegin(),
  927. eoi = methodSpecs.listEnd(); i != eoi; ++i) {
  928. if(!(*i).isDict()) {
  929. list << createErrorResponse
  930. (DL_ABORT_EX("system.multicall expected struct."));
  931. continue;
  932. }
  933. if(!(*i).containsKey(KEY_METHOD_NAME) ||
  934. !(*i).containsKey(KEY_PARAMS)) {
  935. list << createErrorResponse
  936. (DL_ABORT_EX("Missing methodName or params."));
  937. continue;
  938. }
  939. const std::string& methodName = (*i)[KEY_METHOD_NAME].s();
  940. if(methodName == getMethodName()) {
  941. list << createErrorResponse
  942. (DL_ABORT_EX("Recursive system.multicall forbidden."));
  943. continue;
  944. }
  945. SharedHandle<XmlRpcMethod> method = XmlRpcMethodFactory::create(methodName);
  946. XmlRpcRequest innerReq(methodName, (*i)[KEY_PARAMS]);
  947. XmlRpcResponse res = method->execute(innerReq, e);
  948. if(res._code == 0) {
  949. BDE l = BDE::list();
  950. l << res._param;
  951. list << l;
  952. } else {
  953. list << res._param;
  954. }
  955. }
  956. return list;
  957. }
  958. BDE NoSuchMethodXmlRpcMethod::process
  959. (const XmlRpcRequest& req, DownloadEngine* e)
  960. {
  961. throw DL_ABORT_EX
  962. (StringFormat("No such method: %s", req._methodName.c_str()).str());
  963. }
  964. } // namespace xmlrpc
  965. } // namespace aria2