MetalinkParserController.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 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 "MetalinkParserController.h"
  36. #include <algorithm>
  37. #include "Metalinker.h"
  38. #include "MetalinkEntry.h"
  39. #include "MetalinkResource.h"
  40. #include "MetalinkMetaurl.h"
  41. #include "FileEntry.h"
  42. #include "a2functional.h"
  43. #include "A2STR.h"
  44. #include "uri.h"
  45. #include "Signature.h"
  46. #include "util.h"
  47. #include "Checksum.h"
  48. #include "ChunkChecksum.h"
  49. #include "MessageDigest.h"
  50. #ifdef ENABLE_BITTORRENT
  51. #include "magnet.h"
  52. #endif // ENABLE_BITTORRENT
  53. namespace aria2 {
  54. MetalinkParserController::MetalinkParserController()
  55. : metalinker_{make_unique<Metalinker>()}
  56. {
  57. }
  58. MetalinkParserController::~MetalinkParserController() {}
  59. void MetalinkParserController::reset()
  60. {
  61. metalinker_ = make_unique<Metalinker>();
  62. }
  63. std::unique_ptr<Metalinker> MetalinkParserController::getResult()
  64. {
  65. return std::move(metalinker_);
  66. }
  67. void MetalinkParserController::newEntryTransaction()
  68. {
  69. tEntry_ = make_unique<MetalinkEntry>();
  70. tResource_.reset();
  71. tMetaurl_.reset();
  72. tChecksum_.reset();
  73. tChunkChecksumV4_.reset();
  74. tChunkChecksum_.reset();
  75. }
  76. void MetalinkParserController::setFileNameOfEntry(std::string filename)
  77. {
  78. if (!tEntry_) {
  79. return;
  80. }
  81. if (!tEntry_->file) {
  82. tEntry_->file = make_unique<FileEntry>(util::escapePath(filename), 0, 0);
  83. }
  84. else {
  85. tEntry_->file->setPath(util::escapePath(filename));
  86. }
  87. }
  88. void MetalinkParserController::setFileLengthOfEntry(int64_t length)
  89. {
  90. if (!tEntry_) {
  91. return;
  92. }
  93. if (!tEntry_->file) {
  94. return;
  95. }
  96. tEntry_->file->setLength(length);
  97. tEntry_->sizeKnown = true;
  98. }
  99. void MetalinkParserController::setVersionOfEntry(std::string version)
  100. {
  101. if (!tEntry_) {
  102. return;
  103. }
  104. tEntry_->version = std::move(version);
  105. }
  106. void MetalinkParserController::setLanguageOfEntry(std::string language)
  107. {
  108. if (!tEntry_) {
  109. return;
  110. }
  111. tEntry_->languages.push_back(std::move(language));
  112. }
  113. void MetalinkParserController::setOSOfEntry(std::string os)
  114. {
  115. if (!tEntry_) {
  116. return;
  117. }
  118. tEntry_->oses.push_back(std::move(os));
  119. }
  120. void MetalinkParserController::setMaxConnectionsOfEntry(int maxConnections)
  121. {
  122. if (!tEntry_) {
  123. return;
  124. }
  125. tEntry_->maxConnections = maxConnections;
  126. }
  127. void MetalinkParserController::commitEntryTransaction()
  128. {
  129. if (!tEntry_) {
  130. return;
  131. }
  132. commitResourceTransaction();
  133. commitMetaurlTransaction();
  134. commitChecksumTransaction();
  135. commitChunkChecksumTransactionV4();
  136. commitChunkChecksumTransaction();
  137. commitSignatureTransaction();
  138. metalinker_->addEntry(std::move(tEntry_));
  139. }
  140. void MetalinkParserController::cancelEntryTransaction()
  141. {
  142. cancelResourceTransaction();
  143. cancelMetaurlTransaction();
  144. cancelChecksumTransaction();
  145. cancelChunkChecksumTransactionV4();
  146. cancelChunkChecksumTransaction();
  147. cancelSignatureTransaction();
  148. tEntry_.reset();
  149. }
  150. void MetalinkParserController::newResourceTransaction()
  151. {
  152. if (!tEntry_) {
  153. return;
  154. }
  155. tResource_ = make_unique<MetalinkResource>();
  156. }
  157. void MetalinkParserController::setURLOfResource(std::string url)
  158. {
  159. if (!tResource_) {
  160. return;
  161. }
  162. std::string u = uri::joinUri(baseUri_, url);
  163. uri_split_result us;
  164. if (uri_split(&us, u.c_str()) == 0) {
  165. tResource_->url = std::move(u);
  166. if (tResource_->type == MetalinkResource::TYPE_UNKNOWN) {
  167. setTypeOfResource(
  168. uri::getFieldString(us, USR_SCHEME, tResource_->url.c_str()));
  169. }
  170. }
  171. else {
  172. tResource_->url = std::move(url);
  173. }
  174. }
  175. void MetalinkParserController::setTypeOfResource(std::string type)
  176. {
  177. if (!tResource_) {
  178. return;
  179. }
  180. if (type == "ftp" || type == "sftp") {
  181. tResource_->type = MetalinkResource::TYPE_FTP;
  182. }
  183. else if (type == "http") {
  184. tResource_->type = MetalinkResource::TYPE_HTTP;
  185. }
  186. else if (type == "https") {
  187. tResource_->type = MetalinkResource::TYPE_HTTPS;
  188. }
  189. else if (type == "bittorrent" || type == "torrent") {
  190. // "torrent" is Metalink4Spec
  191. tResource_->type = MetalinkResource::TYPE_BITTORRENT;
  192. }
  193. else {
  194. tResource_->type = MetalinkResource::TYPE_NOT_SUPPORTED;
  195. }
  196. }
  197. void MetalinkParserController::setLocationOfResource(std::string location)
  198. {
  199. if (!tResource_) {
  200. return;
  201. }
  202. tResource_->location = std::move(location);
  203. }
  204. void MetalinkParserController::setPriorityOfResource(int priority)
  205. {
  206. if (!tResource_) {
  207. return;
  208. }
  209. tResource_->priority = priority;
  210. }
  211. void MetalinkParserController::setMaxConnectionsOfResource(int maxConnections)
  212. {
  213. if (!tResource_) {
  214. return;
  215. }
  216. tResource_->maxConnections = maxConnections;
  217. }
  218. void MetalinkParserController::commitResourceTransaction()
  219. {
  220. if (!tResource_) {
  221. return;
  222. }
  223. #ifdef ENABLE_BITTORRENT
  224. if (tResource_->type == MetalinkResource::TYPE_BITTORRENT) {
  225. auto metaurl = make_unique<MetalinkMetaurl>();
  226. metaurl->url = std::move(tResource_->url);
  227. metaurl->priority = tResource_->priority;
  228. metaurl->mediatype = MetalinkMetaurl::MEDIATYPE_TORRENT;
  229. tEntry_->metaurls.push_back(std::move(metaurl));
  230. }
  231. else {
  232. tEntry_->resources.push_back(std::move(tResource_));
  233. }
  234. #else // !ENABLE_BITTORRENT
  235. tEntry_->resources.push_back(std::move(tResource_));
  236. #endif // !ENABLE_BITTORRENT
  237. tResource_.reset();
  238. }
  239. void MetalinkParserController::cancelResourceTransaction()
  240. {
  241. tResource_.reset();
  242. }
  243. void MetalinkParserController::newChecksumTransaction()
  244. {
  245. if (!tEntry_) {
  246. return;
  247. }
  248. tChecksum_ = make_unique<Checksum>();
  249. }
  250. void MetalinkParserController::setTypeOfChecksum(std::string type)
  251. {
  252. if (!tChecksum_) {
  253. return;
  254. }
  255. std::string calgo = MessageDigest::getCanonicalHashType(type);
  256. if (MessageDigest::supports(calgo)) {
  257. tChecksum_->setHashType(std::move(calgo));
  258. }
  259. else {
  260. cancelChecksumTransaction();
  261. }
  262. }
  263. void MetalinkParserController::setHashOfChecksum(std::string md)
  264. {
  265. if (!tChecksum_) {
  266. return;
  267. }
  268. if (MessageDigest::isValidHash(tChecksum_->getHashType(), md)) {
  269. tChecksum_->setDigest(util::fromHex(md.begin(), md.end()));
  270. }
  271. else {
  272. cancelChecksumTransaction();
  273. }
  274. }
  275. void MetalinkParserController::commitChecksumTransaction()
  276. {
  277. if (!tChecksum_) {
  278. return;
  279. }
  280. if (!tEntry_->checksum ||
  281. MessageDigest::isStronger(tChecksum_->getHashType(),
  282. tEntry_->checksum->getHashType())) {
  283. tEntry_->checksum = std::move(tChecksum_);
  284. }
  285. tChecksum_.reset();
  286. }
  287. void MetalinkParserController::cancelChecksumTransaction()
  288. {
  289. tChecksum_.reset();
  290. }
  291. void MetalinkParserController::newChunkChecksumTransactionV4()
  292. {
  293. if (!tEntry_) {
  294. return;
  295. }
  296. tChunkChecksumV4_ = make_unique<ChunkChecksum>();
  297. tempChunkChecksumsV4_.clear();
  298. }
  299. void MetalinkParserController::setTypeOfChunkChecksumV4(std::string type)
  300. {
  301. if (!tChunkChecksumV4_) {
  302. return;
  303. }
  304. std::string calgo = MessageDigest::getCanonicalHashType(type);
  305. if (MessageDigest::supports(calgo)) {
  306. tChunkChecksumV4_->setHashType(std::move(calgo));
  307. }
  308. else {
  309. cancelChunkChecksumTransactionV4();
  310. }
  311. }
  312. void MetalinkParserController::setLengthOfChunkChecksumV4(size_t length)
  313. {
  314. if (!tChunkChecksumV4_) {
  315. return;
  316. }
  317. if (length > 0) {
  318. tChunkChecksumV4_->setPieceLength(length);
  319. }
  320. else {
  321. cancelChunkChecksumTransactionV4();
  322. }
  323. }
  324. void MetalinkParserController::addHashOfChunkChecksumV4(std::string md)
  325. {
  326. if (!tChunkChecksumV4_) {
  327. return;
  328. }
  329. if (MessageDigest::isValidHash(tChunkChecksumV4_->getHashType(), md)) {
  330. tempChunkChecksumsV4_.push_back(util::fromHex(md.begin(), md.end()));
  331. }
  332. else {
  333. cancelChunkChecksumTransactionV4();
  334. }
  335. }
  336. void MetalinkParserController::commitChunkChecksumTransactionV4()
  337. {
  338. if (!tChunkChecksumV4_) {
  339. return;
  340. }
  341. if (!tEntry_->chunkChecksum ||
  342. MessageDigest::isStronger(tChunkChecksumV4_->getHashType(),
  343. tEntry_->chunkChecksum->getHashType())) {
  344. tChunkChecksumV4_->setPieceHashes(std::move(tempChunkChecksumsV4_));
  345. tEntry_->chunkChecksum = std::move(tChunkChecksumV4_);
  346. }
  347. tChunkChecksumV4_.reset();
  348. }
  349. void MetalinkParserController::cancelChunkChecksumTransactionV4()
  350. {
  351. tChunkChecksumV4_.reset();
  352. }
  353. void MetalinkParserController::newChunkChecksumTransaction()
  354. {
  355. if (!tEntry_) {
  356. return;
  357. }
  358. tChunkChecksum_ = make_unique<ChunkChecksum>();
  359. tempChunkChecksums_.clear();
  360. }
  361. void MetalinkParserController::setTypeOfChunkChecksum(std::string type)
  362. {
  363. if (!tChunkChecksum_) {
  364. return;
  365. }
  366. std::string calgo = MessageDigest::getCanonicalHashType(type);
  367. if (MessageDigest::supports(calgo)) {
  368. tChunkChecksum_->setHashType(std::move(calgo));
  369. }
  370. else {
  371. cancelChunkChecksumTransaction();
  372. }
  373. }
  374. void MetalinkParserController::setLengthOfChunkChecksum(size_t length)
  375. {
  376. if (!tChunkChecksum_) {
  377. return;
  378. }
  379. if (length > 0) {
  380. tChunkChecksum_->setPieceLength(length);
  381. }
  382. else {
  383. cancelChunkChecksumTransaction();
  384. }
  385. }
  386. void MetalinkParserController::addHashOfChunkChecksum(size_t order,
  387. std::string md)
  388. {
  389. if (!tChunkChecksum_) {
  390. return;
  391. }
  392. if (MessageDigest::isValidHash(tChunkChecksum_->getHashType(), md)) {
  393. tempChunkChecksums_.push_back(std::make_pair(order, std::move(md)));
  394. }
  395. else {
  396. cancelChunkChecksumTransaction();
  397. }
  398. }
  399. void MetalinkParserController::createNewHashOfChunkChecksum(size_t order)
  400. {
  401. if (!tChunkChecksum_) {
  402. return;
  403. }
  404. tempHashPair_.first = order;
  405. }
  406. void MetalinkParserController::setMessageDigestOfChunkChecksum(std::string md)
  407. {
  408. if (!tChunkChecksum_) {
  409. return;
  410. }
  411. if (MessageDigest::isValidHash(tChunkChecksum_->getHashType(), md)) {
  412. tempHashPair_.second = util::fromHex(md.begin(), md.end());
  413. }
  414. else {
  415. cancelChunkChecksumTransaction();
  416. }
  417. }
  418. void MetalinkParserController::addHashOfChunkChecksum()
  419. {
  420. if (!tChunkChecksum_) {
  421. return;
  422. }
  423. tempChunkChecksums_.push_back(tempHashPair_);
  424. }
  425. void MetalinkParserController::commitChunkChecksumTransaction()
  426. {
  427. if (!tChunkChecksum_) {
  428. return;
  429. }
  430. if (!tEntry_->chunkChecksum ||
  431. MessageDigest::isStronger(tChunkChecksum_->getHashType(),
  432. tEntry_->chunkChecksum->getHashType())) {
  433. std::sort(std::begin(tempChunkChecksums_), std::end(tempChunkChecksums_));
  434. std::vector<std::string> pieceHashes;
  435. std::transform(
  436. std::begin(tempChunkChecksums_), std::end(tempChunkChecksums_),
  437. std::back_inserter(pieceHashes),
  438. [](const std::pair<size_t, std::string>& p) { return p.second; });
  439. tChunkChecksum_->setPieceHashes(std::move(pieceHashes));
  440. tEntry_->chunkChecksum = std::move(tChunkChecksum_);
  441. }
  442. tChunkChecksum_.reset();
  443. }
  444. void MetalinkParserController::cancelChunkChecksumTransaction()
  445. {
  446. tChunkChecksum_.reset();
  447. }
  448. void MetalinkParserController::newSignatureTransaction()
  449. {
  450. if (!tEntry_) {
  451. return;
  452. }
  453. tSignature_ = make_unique<Signature>();
  454. }
  455. void MetalinkParserController::setTypeOfSignature(std::string type)
  456. {
  457. if (!tSignature_) {
  458. return;
  459. }
  460. tSignature_->setType(std::move(type));
  461. }
  462. void MetalinkParserController::setFileOfSignature(std::string file)
  463. {
  464. if (!tSignature_) {
  465. return;
  466. }
  467. tSignature_->setFile(std::move(file));
  468. }
  469. void MetalinkParserController::setBodyOfSignature(std::string body)
  470. {
  471. if (!tSignature_) {
  472. return;
  473. }
  474. tSignature_->setBody(std::move(body));
  475. }
  476. void MetalinkParserController::commitSignatureTransaction()
  477. {
  478. if (!tSignature_) {
  479. return;
  480. }
  481. tEntry_->setSignature(std::move(tSignature_));
  482. }
  483. void MetalinkParserController::cancelSignatureTransaction()
  484. {
  485. tSignature_.reset();
  486. }
  487. void MetalinkParserController::newMetaurlTransaction()
  488. {
  489. if (!tEntry_) {
  490. return;
  491. }
  492. tMetaurl_ = make_unique<MetalinkMetaurl>();
  493. }
  494. void MetalinkParserController::setURLOfMetaurl(std::string url)
  495. {
  496. if (!tMetaurl_) {
  497. return;
  498. }
  499. #ifdef ENABLE_BITTORRENT
  500. if (magnet::parse(url)) {
  501. tMetaurl_->url = std::move(url);
  502. }
  503. else
  504. #endif // ENABLE_BITTORRENT
  505. {
  506. std::string u = uri::joinUri(baseUri_, url);
  507. if (uri_split(nullptr, u.c_str()) == 0) {
  508. tMetaurl_->url = std::move(u);
  509. }
  510. else {
  511. tMetaurl_->url = std::move(url);
  512. }
  513. }
  514. }
  515. void MetalinkParserController::setMediatypeOfMetaurl(std::string mediatype)
  516. {
  517. if (!tMetaurl_) {
  518. return;
  519. }
  520. tMetaurl_->mediatype = std::move(mediatype);
  521. }
  522. void MetalinkParserController::setPriorityOfMetaurl(int priority)
  523. {
  524. if (!tMetaurl_) {
  525. return;
  526. }
  527. tMetaurl_->priority = priority;
  528. }
  529. void MetalinkParserController::setNameOfMetaurl(std::string name)
  530. {
  531. if (!tMetaurl_) {
  532. return;
  533. }
  534. tMetaurl_->name = std::move(name);
  535. }
  536. void MetalinkParserController::commitMetaurlTransaction()
  537. {
  538. if (!tMetaurl_) {
  539. return;
  540. }
  541. #ifdef ENABLE_BITTORRENT
  542. if (tMetaurl_->mediatype == MetalinkMetaurl::MEDIATYPE_TORRENT) {
  543. tEntry_->metaurls.push_back(std::move(tMetaurl_));
  544. }
  545. #endif // ENABLE_BITTORRENT
  546. tMetaurl_.reset();
  547. }
  548. void MetalinkParserController::cancelMetaurlTransaction() { tMetaurl_.reset(); }
  549. } // namespace aria2