MetalinkParserController.cc 15 KB

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