MetalinkProcessorTest.cc 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. #include "metalink_helper.h"
  2. #include <iostream>
  3. #include <cppunit/extensions/HelperMacros.h>
  4. #include "MetalinkParserStateMachine.h"
  5. #include "Exception.h"
  6. #include "DefaultDiskWriter.h"
  7. #include "ByteArrayDiskWriter.h"
  8. #include "Metalinker.h"
  9. #include "MetalinkEntry.h"
  10. #include "MetalinkResource.h"
  11. #include "MetalinkMetaurl.h"
  12. #ifdef ENABLE_MESSAGE_DIGEST
  13. # include "MessageDigest.h"
  14. # include "ChunkChecksum.h"
  15. # include "Checksum.h"
  16. #endif // ENABLE_MESSAGE_DIGEST
  17. #include "Signature.h"
  18. #include "fmt.h"
  19. #include "RecoverableException.h"
  20. #include "util.h"
  21. namespace aria2 {
  22. class MetalinkProcessorTest:public CppUnit::TestFixture {
  23. CPPUNIT_TEST_SUITE(MetalinkProcessorTest);
  24. CPPUNIT_TEST(testParseFileV4);
  25. CPPUNIT_TEST(testParseFileV4_attrs);
  26. CPPUNIT_TEST(testParseFile);
  27. CPPUNIT_TEST(testParseFile_dirtraversal);
  28. CPPUNIT_TEST(testParseBinaryStream);
  29. CPPUNIT_TEST(testMalformedXML);
  30. CPPUNIT_TEST(testMalformedXML2);
  31. CPPUNIT_TEST(testBadSize);
  32. CPPUNIT_TEST(testBadSizeV4);
  33. CPPUNIT_TEST(testBadMaxConn);
  34. CPPUNIT_TEST(testNoName);
  35. CPPUNIT_TEST(testBadURLPrefs);
  36. CPPUNIT_TEST(testBadURLMaxConn);
  37. #ifdef ENABLE_MESSAGE_DIGEST
  38. CPPUNIT_TEST(testUnsupportedType);
  39. CPPUNIT_TEST(testMultiplePieces);
  40. CPPUNIT_TEST(testBadPieceNo);
  41. CPPUNIT_TEST(testBadPieceLength);
  42. CPPUNIT_TEST(testUnsupportedType_piece);
  43. #endif // ENABLE_MESSAGE_DIGEST
  44. CPPUNIT_TEST(testLargeFileSize);
  45. CPPUNIT_TEST(testXmlPrefixV3);
  46. CPPUNIT_TEST_SUITE_END();
  47. private:
  48. public:
  49. void testParseFileV4();
  50. void testParseFileV4_attrs();
  51. void testParseFile();
  52. void testParseFile_dirtraversal();
  53. void testParseBinaryStream();
  54. void testMalformedXML();
  55. void testMalformedXML2();
  56. void testBadSize();
  57. void testBadSizeV4();
  58. void testBadMaxConn();
  59. void testNoName();
  60. void testBadURLPrefs();
  61. void testBadURLMaxConn();
  62. #ifdef ENABLE_MESSAGE_DIGEST
  63. void testUnsupportedType();
  64. void testMultiplePieces();
  65. void testBadPieceNo();
  66. void testBadPieceLength();
  67. void testUnsupportedType_piece();
  68. #endif // ENABLE_MESSAGE_DIGEST
  69. void testLargeFileSize();
  70. void testXmlPrefixV3();
  71. };
  72. CPPUNIT_TEST_SUITE_REGISTRATION( MetalinkProcessorTest );
  73. void MetalinkProcessorTest::testParseFileV4()
  74. {
  75. auto m = metalink::parseFile(A2_TEST_DIR"/metalink4.xml");
  76. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  77. auto& e = m->getEntries()[0];
  78. CPPUNIT_ASSERT_EQUAL(std::string("example.ext"), e->getPath());
  79. CPPUNIT_ASSERT_EQUAL((int64_t)786430LL, e->getLength());
  80. CPPUNIT_ASSERT_EQUAL(-1, e->maxConnections);
  81. #ifdef ENABLE_MESSAGE_DIGEST
  82. CPPUNIT_ASSERT_EQUAL(std::string("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
  83. util::toHex(e->checksum->getDigest()));
  84. CPPUNIT_ASSERT(e->checksum);
  85. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), e->checksum->getHashType());
  86. CPPUNIT_ASSERT(e->chunkChecksum);
  87. if(MessageDigest::supports("sha-256")) {
  88. CPPUNIT_ASSERT_EQUAL(std::string("sha-256"), e->chunkChecksum->getHashType());
  89. CPPUNIT_ASSERT_EQUAL(262144, e->chunkChecksum->getPieceLength());
  90. CPPUNIT_ASSERT_EQUAL((size_t)3, e->chunkChecksum->countPieceHash());
  91. CPPUNIT_ASSERT_EQUAL(std::string("0245178074fd042e19b7c3885b360fc21064b30e73f5626c7e3b005d048069c5"),
  92. util::toHex(e->chunkChecksum->getPieceHash(0)));
  93. CPPUNIT_ASSERT_EQUAL(std::string("487ba2299be7f759d7c7bf6a4ac3a32cee81f1bb9332fc485947e32918864fb2"),
  94. util::toHex(e->chunkChecksum->getPieceHash(1)));
  95. CPPUNIT_ASSERT_EQUAL(std::string("37290d74ac4d186e3a8e5785d259d2ec04fac91ae28092e7620ec8bc99e830aa"),
  96. util::toHex(e->chunkChecksum->getPieceHash(2)));
  97. } else {
  98. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), e->chunkChecksum->getHashType());
  99. CPPUNIT_ASSERT_EQUAL(262144, e->chunkChecksum->getPieceLength());
  100. CPPUNIT_ASSERT_EQUAL((size_t)3, e->chunkChecksum->countPieceHash());
  101. CPPUNIT_ASSERT_EQUAL
  102. (std::string("5bd9f7248df0f3a6a86ab6c95f48787d546efa14"),
  103. util::toHex(e->chunkChecksum->getPieceHash(0)));
  104. CPPUNIT_ASSERT_EQUAL
  105. (std::string("9413ee70957a09d55704123687478e07f18c7b29"),
  106. util::toHex(e->chunkChecksum->getPieceHash(1)));
  107. CPPUNIT_ASSERT_EQUAL
  108. (std::string("44213f9f4d59b557314fadcd233232eebcac8012"),
  109. util::toHex(e->chunkChecksum->getPieceHash(2)));
  110. }
  111. #endif // ENABLE_MESSAGE_DIGEST
  112. CPPUNIT_ASSERT(e->getSignature());
  113. CPPUNIT_ASSERT_EQUAL(std::string("application/pgp-signature"),
  114. e->getSignature()->getType());
  115. CPPUNIT_ASSERT_EQUAL(std::string("a signature"),
  116. e->getSignature()->getBody());
  117. CPPUNIT_ASSERT_EQUAL((size_t)2, e->resources.size());
  118. auto& r = e->resources[0];
  119. CPPUNIT_ASSERT_EQUAL(std::string("ftp://ftp.example.com/example.ext"),
  120. r->url);
  121. CPPUNIT_ASSERT_EQUAL(std::string("de"), r->location);
  122. CPPUNIT_ASSERT_EQUAL(1, r->priority);
  123. CPPUNIT_ASSERT_EQUAL(std::string("ftp"),
  124. MetalinkResource::getTypeString(r->type));
  125. CPPUNIT_ASSERT_EQUAL(-1, r->maxConnections);
  126. #ifdef ENABLE_BITTORRENT
  127. CPPUNIT_ASSERT_EQUAL((size_t)1, e->metaurls.size());
  128. auto& mu = e->metaurls[0];
  129. CPPUNIT_ASSERT_EQUAL(std::string("http://example.com/example.ext.torrent"),
  130. mu->url);
  131. CPPUNIT_ASSERT_EQUAL(2, mu->priority);
  132. CPPUNIT_ASSERT_EQUAL(std::string("torrent"), mu->mediatype);
  133. #else // !ENABLE_BITTORRENT
  134. CPPUNIT_ASSERT_EQUAL((size_t)0, e->metaurls.size());
  135. #endif // !ENABLE_BITTORRENT
  136. }
  137. void MetalinkProcessorTest::testParseFileV4_attrs()
  138. {
  139. std::unique_ptr<Metalinker> m;
  140. ByteArrayDiskWriter dw;
  141. {
  142. // Testing file@name
  143. const char* tmpl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  144. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  145. "<file name=\"%s\">"
  146. "<url>http://example.org</url>"
  147. "</file>"
  148. "</metalink>";
  149. dw.setString(fmt(tmpl, "foo"));
  150. m = metalink::parseBinaryStream(&dw);
  151. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  152. // empty name
  153. dw.setString(fmt(tmpl, ""));
  154. try {
  155. metalink::parseBinaryStream(&dw);
  156. CPPUNIT_FAIL("exception must be thrown.");
  157. } catch(RecoverableException& e) {
  158. // success
  159. }
  160. // dir traversing
  161. dw.setString(fmt(tmpl, "../doughnuts"));
  162. try {
  163. m = metalink::parseBinaryStream(&dw);
  164. CPPUNIT_FAIL("exception must be thrown.");
  165. } catch(RecoverableException& e) {
  166. // success
  167. }
  168. }
  169. {
  170. // Testing url@priority
  171. const char* tmpl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  172. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  173. "<file name=\"example.ext\">"
  174. "<url priority=\"%s\">http://example.org</url>"
  175. "</file>"
  176. "</metalink>";
  177. dw.setString(fmt(tmpl, "0"));
  178. try {
  179. metalink::parseBinaryStream(&dw);
  180. CPPUNIT_FAIL("exception must be thrown.");
  181. } catch(RecoverableException& e) {
  182. // success
  183. }
  184. dw.setString(fmt(tmpl, "1"));
  185. m = metalink::parseBinaryStream(&dw);
  186. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  187. dw.setString(fmt(tmpl, "100"));
  188. m = metalink::parseBinaryStream(&dw);
  189. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  190. dw.setString(fmt(tmpl, "999999"));
  191. m = metalink::parseBinaryStream(&dw);
  192. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  193. dw.setString(fmt(tmpl, "1000000"));
  194. try {
  195. m = metalink::parseBinaryStream(&dw);
  196. CPPUNIT_FAIL("exception must be thrown.");
  197. } catch(RecoverableException& e) {
  198. // success
  199. }
  200. dw.setString(fmt(tmpl, "A"));
  201. try {
  202. m = metalink::parseBinaryStream(&dw);
  203. CPPUNIT_FAIL("exception must be thrown.");
  204. } catch(RecoverableException& e) {}
  205. }
  206. {
  207. // Testing metaurl@priority
  208. const char* tmpl =
  209. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  210. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  211. "<file name=\"example.ext\">"
  212. "<metaurl priority=\"%s\" mediatype=\"torrent\">http://example.org</metaurl>"
  213. "</file>"
  214. "</metalink>";
  215. dw.setString(fmt(tmpl, "0"));
  216. try {
  217. m = metalink::parseBinaryStream(&dw);
  218. CPPUNIT_FAIL("exception must be thrown.");
  219. } catch(RecoverableException& e) {
  220. // success
  221. }
  222. dw.setString(fmt(tmpl, "1"));
  223. m = metalink::parseBinaryStream(&dw);
  224. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  225. dw.setString(fmt(tmpl, "100"));
  226. m = metalink::parseBinaryStream(&dw);
  227. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  228. dw.setString(fmt(tmpl, "999999"));
  229. m = metalink::parseBinaryStream(&dw);
  230. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  231. dw.setString(fmt(tmpl, "1000000"));
  232. try {
  233. m = metalink::parseBinaryStream(&dw);
  234. CPPUNIT_FAIL("exception must be thrown.");
  235. } catch(RecoverableException& e) {
  236. // success
  237. }
  238. dw.setString(fmt(tmpl, "A"));
  239. try {
  240. m = metalink::parseBinaryStream(&dw);
  241. CPPUNIT_FAIL("exception must be thrown.");
  242. } catch(RecoverableException& e) {}
  243. }
  244. {
  245. // Testing metaurl@mediatype
  246. // no mediatype
  247. dw.setString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  248. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  249. "<file name=\"example.ext\">"
  250. "<metaurl>http://example.org</metaurl>"
  251. "</file>"
  252. "</metalink>");
  253. try {
  254. m = metalink::parseBinaryStream(&dw);
  255. CPPUNIT_FAIL("exception must be thrown.");
  256. } catch(RecoverableException& e) {
  257. // success
  258. }
  259. const char* tmpl =
  260. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  261. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  262. "<file name=\"example.ext\">"
  263. "<metaurl mediatype=\"%s\">http://example.org</metaurl>"
  264. "</file>"
  265. "</metalink>";
  266. dw.setString(fmt(tmpl, "torrent"));
  267. m = metalink::parseBinaryStream(&dw);
  268. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  269. // empty mediatype
  270. dw.setString(fmt(tmpl, ""));
  271. try {
  272. m = metalink::parseBinaryStream(&dw);
  273. CPPUNIT_FAIL("exception must be thrown.");
  274. } catch(RecoverableException& e) {
  275. // success
  276. }
  277. }
  278. {
  279. // Testing metaurl@name
  280. const char* tmpl =
  281. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  282. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  283. "<file name=\"example.ext\">"
  284. "<metaurl mediatype=\"torrent\" name=\"%s\">http://example.org</metaurl>"
  285. "</file>"
  286. "</metalink>";
  287. dw.setString(fmt(tmpl, "foo"));
  288. m = metalink::parseBinaryStream(&dw);
  289. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  290. // dir traversing
  291. dw.setString(fmt(tmpl, "../doughnuts"));
  292. try {
  293. m = metalink::parseBinaryStream(&dw);
  294. CPPUNIT_FAIL("exception must be thrown.");
  295. } catch(RecoverableException& e) {
  296. // success
  297. }
  298. // empty name
  299. dw.setString(fmt(tmpl, ""));
  300. try {
  301. m = metalink::parseBinaryStream(&dw);
  302. CPPUNIT_FAIL("exception must be thrown.");
  303. } catch(RecoverableException& e) {
  304. // success
  305. }
  306. }
  307. #ifdef ENABLE_MESSAGE_DIGEST
  308. {
  309. // Testing pieces@length
  310. // No pieces@length
  311. dw.setString
  312. ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  313. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  314. "<file name=\"example.ext\">"
  315. "<url>http://example.org</url>"
  316. "<pieces type=\"sha-1\">"
  317. "<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
  318. "</pieces>"
  319. "</file>"
  320. "</metalink>");
  321. try {
  322. m = metalink::parseBinaryStream(&dw);
  323. CPPUNIT_FAIL("exception must be thrown.");
  324. } catch(RecoverableException& e) {}
  325. const char* tmpl =
  326. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  327. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  328. "<file name=\"example.ext\">"
  329. "<url>http://example.org</url>"
  330. "<pieces length=\"%s\" type=\"sha-1\">"
  331. "<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
  332. "</pieces>"
  333. "</file>"
  334. "</metalink>";
  335. dw.setString(fmt(tmpl, "262144"));
  336. m = metalink::parseBinaryStream(&dw);
  337. // empty
  338. try {
  339. dw.setString(fmt(tmpl, ""));
  340. m = metalink::parseBinaryStream(&dw);
  341. CPPUNIT_FAIL("exception must be thrown.");
  342. } catch(RecoverableException& e) {}
  343. // not a number
  344. try {
  345. dw.setString(fmt(tmpl, "A"));
  346. m = metalink::parseBinaryStream(&dw);
  347. CPPUNIT_FAIL("exception must be thrown.");
  348. } catch(RecoverableException& e) {}
  349. }
  350. {
  351. // Testing pieces@type
  352. // No pieces@type
  353. dw.setString
  354. ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  355. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  356. "<file name=\"example.ext\">"
  357. "<url>http://example.org</url>"
  358. "<pieces length=\"262144\">"
  359. "<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
  360. "</pieces>"
  361. "</file>"
  362. "</metalink>");
  363. try {
  364. m = metalink::parseBinaryStream(&dw);
  365. CPPUNIT_FAIL("exception must be thrown.");
  366. } catch(RecoverableException& e) {}
  367. const char* tmpl =
  368. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  369. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  370. "<file name=\"example.ext\">"
  371. "<url>http://example.org</url>"
  372. "<pieces length=\"262144\" type=\"%s\">"
  373. "<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
  374. "</pieces>"
  375. "</file>"
  376. "</metalink>";
  377. dw.setString(fmt(tmpl, "sha-1"));
  378. m = metalink::parseBinaryStream(&dw);
  379. // empty
  380. try {
  381. dw.setString(fmt(tmpl, ""));
  382. m = metalink::parseBinaryStream(&dw);
  383. CPPUNIT_FAIL("exception must be thrown.");
  384. } catch(RecoverableException& e) {}
  385. }
  386. {
  387. // Testing hash@type
  388. // No hash@type
  389. dw.setString
  390. ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  391. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  392. "<file name=\"example.ext\">"
  393. "<url>http://example.org</url>"
  394. "<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
  395. "</file>"
  396. "</metalink>");
  397. try {
  398. m = metalink::parseBinaryStream(&dw);
  399. CPPUNIT_FAIL("exception must be thrown.");
  400. } catch(RecoverableException& e) {}
  401. const char* tmpl =
  402. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  403. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  404. "<file name=\"example.ext\">"
  405. "<url>http://example.org</url>"
  406. "<hash type=\"%s\">0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
  407. "</file>"
  408. "</metalink>";
  409. dw.setString(fmt(tmpl, "sha-1"));
  410. m = metalink::parseBinaryStream(&dw);
  411. // empty
  412. try {
  413. dw.setString(fmt(tmpl, ""));
  414. m = metalink::parseBinaryStream(&dw);
  415. CPPUNIT_FAIL("exception must be thrown.");
  416. } catch(RecoverableException& e) {}
  417. }
  418. #endif // ENABLE_MESSAGE_DIGEST
  419. {
  420. // Testing signature@mediatype
  421. // No hash@type
  422. dw.setString
  423. ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  424. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  425. "<file name=\"example.ext\">"
  426. "<url>http://example.org</url>"
  427. "<signature>sig</signature>"
  428. "</file>"
  429. "</metalink>");
  430. try {
  431. m = metalink::parseBinaryStream(&dw);
  432. CPPUNIT_FAIL("exception must be thrown.");
  433. } catch(RecoverableException& e) {}
  434. const char* tmpl =
  435. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  436. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  437. "<file name=\"example.ext\">"
  438. "<url>http://example.org</url>"
  439. "<signature mediatype=\"%s\">sig</signature>"
  440. "</file>"
  441. "</metalink>";
  442. dw.setString(fmt(tmpl, "application/pgp-signature"));
  443. m = metalink::parseBinaryStream(&dw);
  444. // empty
  445. try {
  446. dw.setString(fmt(tmpl, ""));
  447. m = metalink::parseBinaryStream(&dw);
  448. CPPUNIT_FAIL("exception must be thrown.");
  449. } catch(RecoverableException& e) {}
  450. }
  451. }
  452. void MetalinkProcessorTest::testParseFile()
  453. {
  454. try {
  455. auto metalinker = metalink::parseFile(A2_TEST_DIR"/test.xml");
  456. auto entryItr = std::begin(metalinker->getEntries());
  457. auto& entry1 = *entryItr;
  458. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2"), entry1->getPath());
  459. CPPUNIT_ASSERT_EQUAL((int64_t)0LL, entry1->getLength());
  460. CPPUNIT_ASSERT_EQUAL(std::string("0.5.2"), entry1->version);
  461. CPPUNIT_ASSERT_EQUAL(std::string("en-US"), entry1->languages[0]);
  462. CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), entry1->oses[0]);
  463. CPPUNIT_ASSERT_EQUAL(1, entry1->maxConnections);
  464. #ifdef ENABLE_MESSAGE_DIGEST
  465. CPPUNIT_ASSERT_EQUAL(std::string("a96cf3f0266b91d87d5124cf94326422800b627d"),
  466. util::toHex(entry1->checksum->getDigest()));
  467. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), entry1->checksum->getHashType());
  468. #endif // ENABLE_MESSAGE_DIGEST
  469. CPPUNIT_ASSERT(entry1->getSignature());
  470. CPPUNIT_ASSERT_EQUAL(std::string("pgp"), entry1->getSignature()->getType());
  471. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2.sig"),
  472. entry1->getSignature()->getFile());
  473. // Note that we don't strip anything
  474. CPPUNIT_ASSERT_EQUAL
  475. (std::string
  476. ("\n-----BEGIN PGP SIGNATURE-----\n"
  477. "Version: GnuPG v1.4.9 (GNU/Linux)\n"
  478. "\n"
  479. "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
  480. "ffffffffffffffffffffffff\n"
  481. "fffff\n"
  482. "-----END PGP SIGNATURE-----\n"
  483. "\t"),
  484. entry1->getSignature()->getBody());
  485. auto resourceItr1 = std::begin(entry1->resources);
  486. auto& resource1 = *resourceItr1;
  487. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, resource1->type);
  488. CPPUNIT_ASSERT_EQUAL(std::string("jp"), resource1->location);
  489. CPPUNIT_ASSERT_EQUAL(1, resource1->priority);
  490. CPPUNIT_ASSERT_EQUAL(std::string("ftp://ftphost/aria2-0.5.2.tar.bz2"),
  491. resource1->url);
  492. CPPUNIT_ASSERT_EQUAL(1, resource1->maxConnections);
  493. ++resourceItr1;
  494. auto& resource2 = *resourceItr1;
  495. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, resource2->type);
  496. CPPUNIT_ASSERT_EQUAL(std::string("us"), resource2->location);
  497. CPPUNIT_ASSERT_EQUAL(1, resource2->priority);
  498. CPPUNIT_ASSERT_EQUAL(std::string("http://httphost/aria2-0.5.2.tar.bz2"),
  499. resource2->url);
  500. CPPUNIT_ASSERT_EQUAL(-1, resource2->maxConnections);
  501. ++entryItr;
  502. auto& entry2 = *entryItr;
  503. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.1.tar.bz2"), entry2->getPath());
  504. CPPUNIT_ASSERT_EQUAL((int64_t)345689LL, entry2->getLength());
  505. CPPUNIT_ASSERT_EQUAL(std::string("0.5.1"), entry2->version);
  506. CPPUNIT_ASSERT_EQUAL(std::string("ja-JP"), entry2->languages[0]);
  507. CPPUNIT_ASSERT_EQUAL(std::string("Linux-m68k"), entry2->oses[0]);
  508. CPPUNIT_ASSERT_EQUAL(-1, entry2->maxConnections);
  509. #ifdef ENABLE_MESSAGE_DIGEST
  510. CPPUNIT_ASSERT_EQUAL(std::string("4c255b0ed130f5ea880f0aa061c3da0487e251cc"),
  511. util::toHex(entry2->checksum->getDigest()));
  512. CPPUNIT_ASSERT_EQUAL((size_t)2, entry2->chunkChecksum->countPieceHash());
  513. CPPUNIT_ASSERT_EQUAL(262144, entry2->chunkChecksum->getPieceLength());
  514. CPPUNIT_ASSERT_EQUAL(std::string("179463a88d79cbf0b1923991708aead914f26142"),
  515. util::toHex(entry2->chunkChecksum->getPieceHash(0)));
  516. CPPUNIT_ASSERT_EQUAL(std::string("fecf8bc9a1647505fe16746f94e97a477597dbf3"),
  517. util::toHex(entry2->chunkChecksum->getPieceHash(1)));
  518. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), entry2->checksum->getHashType());
  519. #endif // ENABLE_MESSAGE_DIGEST
  520. // See that signature is null
  521. CPPUNIT_ASSERT(!entry2->getSignature());
  522. ++entryItr;
  523. // test case: verification hash is not provided
  524. auto& entry3 = *entryItr;
  525. CPPUNIT_ASSERT_EQUAL(std::string("NoVerificationHash"), entry3->getPath());
  526. #ifdef ENABLE_MESSAGE_DIGEST
  527. CPPUNIT_ASSERT(!entry3->checksum);
  528. CPPUNIT_ASSERT(!entry3->chunkChecksum);
  529. #endif // ENABLE_MESSAGE_DIGEST
  530. ++entryItr;
  531. // test case: unsupported verification hash is included
  532. auto& entry4 = *entryItr;
  533. CPPUNIT_ASSERT_EQUAL(std::string("UnsupportedVerificationHashTypeIncluded"), entry4->getPath());
  534. #ifdef ENABLE_MESSAGE_DIGEST
  535. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), entry4->checksum->getHashType());
  536. CPPUNIT_ASSERT_EQUAL(std::string("4c255b0ed130f5ea880f0aa061c3da0487e251cc"),
  537. util::toHex(entry4->checksum->getDigest()));
  538. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"),entry4->chunkChecksum->getHashType());
  539. #endif // ENABLE_MESSAGE_DIGEST
  540. } catch(Exception& e) {
  541. CPPUNIT_FAIL(e.stackTrace());
  542. }
  543. }
  544. void MetalinkProcessorTest::testParseFile_dirtraversal()
  545. {
  546. auto metalinker =
  547. metalink::parseFile(A2_TEST_DIR"/metalink3-dirtraversal.xml");
  548. CPPUNIT_ASSERT_EQUAL((size_t)1, metalinker->getEntries().size());
  549. auto& e = metalinker->getEntries()[0];
  550. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.3.tar.bz2"), e->getPath());
  551. CPPUNIT_ASSERT(e->getSignature());
  552. CPPUNIT_ASSERT_EQUAL(std::string(""), e->getSignature()->getFile());
  553. }
  554. void MetalinkProcessorTest::testParseBinaryStream()
  555. {
  556. DefaultDiskWriter dw(A2_TEST_DIR"/test.xml");
  557. dw.enableReadOnly();
  558. dw.openExistingFile();
  559. try {
  560. auto m = metalink::parseBinaryStream(&dw);
  561. auto& entry1 = m->getEntries()[0];
  562. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2"), entry1->getPath());
  563. } catch(Exception& e) {
  564. CPPUNIT_FAIL(e.stackTrace());
  565. }
  566. }
  567. void MetalinkProcessorTest::testMalformedXML()
  568. {
  569. ByteArrayDiskWriter dw;
  570. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></file></metalink>");
  571. try {
  572. metalink::parseBinaryStream(&dw);
  573. CPPUNIT_FAIL("exception must be thrown.");
  574. } catch(Exception& e) {
  575. std::cerr << e.stackTrace() << std::endl;
  576. }
  577. }
  578. void MetalinkProcessorTest::testMalformedXML2()
  579. {
  580. ByteArrayDiskWriter dw;
  581. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></files>");
  582. try {
  583. metalink::parseBinaryStream(&dw);
  584. CPPUNIT_FAIL("exception must be thrown.");
  585. } catch(Exception& e) {
  586. std::cerr << e.stackTrace() << std::endl;
  587. }
  588. }
  589. void MetalinkProcessorTest::testBadSizeV4()
  590. {
  591. ByteArrayDiskWriter dw;
  592. const char* tmpl =
  593. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  594. "<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
  595. "<file name=\"foo\">"
  596. "<size>%s</size>"
  597. "<url>http://example.org</url>"
  598. "</file>"
  599. "</metalink>";
  600. dw.setString(fmt(tmpl, "9223372036854775807"));
  601. metalink::parseBinaryStream(&dw);
  602. dw.setString(fmt(tmpl, "-1"));
  603. try {
  604. metalink::parseBinaryStream(&dw);
  605. CPPUNIT_FAIL("exception must be thrown.");
  606. } catch(RecoverableException& e) {}
  607. }
  608. void MetalinkProcessorTest::testBadSize()
  609. {
  610. ByteArrayDiskWriter dw;
  611. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  612. "<files>"
  613. "<file name=\"aria2-0.5.2.tar.bz2\">"
  614. " <size>abc</size>"
  615. " <version>0.5.2</version>"
  616. " <language>en-US</language>"
  617. " <os>Linux-x86</os>"
  618. "</file>"
  619. "</files>"
  620. "</metalink>");
  621. try {
  622. auto m = metalink::parseBinaryStream(&dw);
  623. auto& e = m->getEntries()[0];
  624. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2"), e->getPath());
  625. CPPUNIT_ASSERT_EQUAL((int64_t)0LL, e->getLength());
  626. CPPUNIT_ASSERT_EQUAL(std::string("0.5.2"), e->version);
  627. CPPUNIT_ASSERT_EQUAL(std::string("en-US"), e->languages[0]);
  628. CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), e->oses[0]);
  629. } catch(Exception& e) {
  630. CPPUNIT_FAIL(e.stackTrace());
  631. }
  632. }
  633. void MetalinkProcessorTest::testBadMaxConn()
  634. {
  635. ByteArrayDiskWriter dw;
  636. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  637. "<files>"
  638. "<file name=\"aria2-0.5.2.tar.bz2\">"
  639. " <size>43743838</size>"
  640. " <version>0.5.2</version>"
  641. " <language>en-US</language>"
  642. " <os>Linux-x86</os>"
  643. " <resources maxconnections=\"abc\"/>"
  644. "</file>"
  645. "</files>"
  646. "</metalink>");
  647. try {
  648. auto m = metalink::parseBinaryStream(&dw);
  649. auto& e = m->getEntries()[0];
  650. CPPUNIT_ASSERT_EQUAL((int64_t)43743838LL, e->getLength());
  651. } catch(Exception& e) {
  652. CPPUNIT_FAIL(e.stackTrace());
  653. }
  654. }
  655. void MetalinkProcessorTest::testNoName()
  656. {
  657. ByteArrayDiskWriter dw;
  658. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  659. "<files>"
  660. "<file>"
  661. " <size>1024</size>"
  662. " <version>0.0.1</version>"
  663. " <language>GB</language>"
  664. " <os>Linux-x64</os>"
  665. "</file>"
  666. "<file name=\"aria2-0.5.2.tar.bz2\">"
  667. " <size>43743838</size>"
  668. " <version>0.5.2</version>"
  669. " <language>en-US</language>"
  670. " <os>Linux-x86</os>"
  671. "</file>"
  672. "</files>"
  673. "</metalink>");
  674. try {
  675. auto m = metalink::parseBinaryStream(&dw);
  676. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  677. auto& e = m->getEntries()[0];
  678. CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2"), e->getPath());
  679. } catch(Exception& e) {
  680. CPPUNIT_FAIL(e.stackTrace());
  681. }
  682. }
  683. void MetalinkProcessorTest::testBadURLPrefs()
  684. {
  685. ByteArrayDiskWriter dw;
  686. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  687. "<files>"
  688. "<file name=\"aria2-0.5.2.tar.bz2\">"
  689. " <size>43743838</size>"
  690. " <version>0.5.2</version>"
  691. " <language>en-US</language>"
  692. " <os>Linux-x86</os>"
  693. " <resources>"
  694. " <url type=\"ftp\" maxconnections=\"1\" preference=\"xyz\""
  695. " location=\"jp\">ftp://mirror/</url>"
  696. " </resources>"
  697. "</file>"
  698. "</files>"
  699. "</metalink>");
  700. try {
  701. auto m = metalink::parseBinaryStream(&dw);
  702. auto& e = m->getEntries()[0];
  703. auto& r = e->resources[0];
  704. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
  705. CPPUNIT_ASSERT_EQUAL(MetalinkResource::getLowestPriority(), r->priority);
  706. CPPUNIT_ASSERT_EQUAL(1, r->maxConnections);
  707. CPPUNIT_ASSERT_EQUAL(std::string("jp"), r->location);
  708. } catch(Exception& e) {
  709. CPPUNIT_FAIL(e.stackTrace());
  710. }
  711. }
  712. void MetalinkProcessorTest::testBadURLMaxConn()
  713. {
  714. ByteArrayDiskWriter dw;
  715. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  716. "<files>"
  717. "<file name=\"aria2-0.5.2.tar.bz2\">"
  718. " <size>43743838</size>"
  719. " <version>0.5.2</version>"
  720. " <language>en-US</language>"
  721. " <os>Linux-x86</os>"
  722. " <resources>"
  723. " <url maxconnections=\"xyz\" type=\"ftp\""
  724. " preference=\"100\""
  725. " location=\"jp\">ftp://mirror/</url>"
  726. " </resources>"
  727. "</file>"
  728. "</files>"
  729. "</metalink>");
  730. try {
  731. auto m = metalink::parseBinaryStream(&dw);
  732. auto& e = m->getEntries()[0];
  733. auto& r = e->resources[0];
  734. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
  735. CPPUNIT_ASSERT_EQUAL(1, r->priority);
  736. CPPUNIT_ASSERT_EQUAL(-1, r->maxConnections);
  737. CPPUNIT_ASSERT_EQUAL(std::string("jp"), r->location);
  738. } catch(Exception& e) {
  739. CPPUNIT_FAIL(e.stackTrace());
  740. }
  741. }
  742. #ifdef ENABLE_MESSAGE_DIGEST
  743. void MetalinkProcessorTest::testUnsupportedType()
  744. {
  745. ByteArrayDiskWriter dw;
  746. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  747. "<files>"
  748. "<file name=\"aria2-0.5.2.tar.bz2\">"
  749. " <size>43743838</size>"
  750. " <version>0.5.2</version>"
  751. " <language>en-US</language>"
  752. " <os>Linux-x86</os>"
  753. " <resources>"
  754. " <url type=\"ftp\">ftp://mirror/</url>"
  755. " <url type=\"magnet\">magnet:xt=XYZ</url>"
  756. " <url type=\"http\">http://mirror/</url>"
  757. " </resources>"
  758. "</file>"
  759. "</files>"
  760. "</metalink>");
  761. try {
  762. auto m = metalink::parseBinaryStream(&dw);
  763. auto& e = m->getEntries()[0];
  764. CPPUNIT_ASSERT_EQUAL((size_t)3, e->resources.size());
  765. auto& r1 = e->resources[0];
  766. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r1->type);
  767. auto& r2 = e->resources[1];
  768. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_NOT_SUPPORTED, r2->type);
  769. auto& r3 = e->resources[2];
  770. CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, r3->type);
  771. } catch(Exception& e) {
  772. CPPUNIT_FAIL(e.stackTrace());
  773. }
  774. }
  775. void MetalinkProcessorTest::testMultiplePieces()
  776. {
  777. ByteArrayDiskWriter dw;
  778. dw.setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  779. "<files>"
  780. "<file name=\"aria2.tar.bz2\">"
  781. " <verification>"
  782. " <pieces length=\"1024\" type=\"sha1\">"
  783. " </pieces>"
  784. " <pieces length=\"512\" type=\"md5\">"
  785. " </pieces>"
  786. " </verification>"
  787. "</file>"
  788. "</files>"
  789. "</metalink>");
  790. try {
  791. // aria2 prefers sha1
  792. auto m = metalink::parseBinaryStream(&dw);
  793. auto& e = m->getEntries()[0];
  794. auto& c = e->chunkChecksum;
  795. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), c->getHashType());
  796. CPPUNIT_ASSERT_EQUAL(1024, c->getPieceLength());
  797. } catch(Exception& e) {
  798. CPPUNIT_FAIL(e.stackTrace());
  799. }
  800. }
  801. void MetalinkProcessorTest::testBadPieceNo()
  802. {
  803. ByteArrayDiskWriter dw;
  804. dw.setString
  805. ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  806. "<files>"
  807. "<file name=\"aria2.tar.bz2\">"
  808. " <verification>"
  809. " <pieces length=\"512\" type=\"sha1\">"
  810. " <hash piece=\"0\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  811. " <hash piece=\"xyz\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  812. " </pieces>"
  813. " <pieces length=\"1024\" type=\"sha1\">"
  814. " <hash piece=\"0\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  815. " </pieces>"
  816. " </verification>"
  817. "</file>"
  818. "</files>"
  819. "</metalink>");
  820. try {
  821. auto m = metalink::parseBinaryStream(&dw);
  822. auto& e = m->getEntries()[0];
  823. auto& c = e->chunkChecksum;
  824. CPPUNIT_ASSERT(c);
  825. CPPUNIT_ASSERT_EQUAL(1024, c->getPieceLength());
  826. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), c->getHashType());
  827. } catch(Exception& e) {
  828. CPPUNIT_FAIL(e.stackTrace());
  829. }
  830. }
  831. void MetalinkProcessorTest::testBadPieceLength()
  832. {
  833. ByteArrayDiskWriter dw;
  834. dw.setString
  835. ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  836. "<files>"
  837. "<file name=\"aria2.tar.bz2\">"
  838. " <verification>"
  839. " <pieces length=\"xyz\" type=\"sha1\">"
  840. " <hash piece=\"0\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  841. " </pieces>"
  842. " <pieces length=\"1024\" type=\"sha1\">"
  843. " <hash piece=\"0\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  844. " </pieces>"
  845. " </verification>"
  846. "</file>"
  847. "</files>"
  848. "</metalink>");
  849. try {
  850. auto m = metalink::parseBinaryStream(&dw);
  851. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  852. auto& e = m->getEntries()[0];
  853. auto& c = e->chunkChecksum;
  854. CPPUNIT_ASSERT(c);
  855. CPPUNIT_ASSERT_EQUAL(1024, c->getPieceLength());
  856. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), c->getHashType());
  857. } catch(Exception& e) {
  858. CPPUNIT_FAIL(e.stackTrace());
  859. }
  860. }
  861. void MetalinkProcessorTest::testUnsupportedType_piece()
  862. {
  863. ByteArrayDiskWriter dw;
  864. dw.setString
  865. ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  866. "<files>"
  867. "<file name=\"aria2.tar.bz2\">"
  868. " <verification>"
  869. " <pieces length=\"512\" type=\"ARIA2\">"
  870. " <hash piece=\"0\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  871. " </pieces>"
  872. " <pieces length=\"1024\" type=\"sha1\">"
  873. " <hash piece=\"0\">44213f9f4d59b557314fadcd233232eebcac8012</hash>"
  874. " </pieces>"
  875. " </verification>"
  876. "</file>"
  877. "</files>"
  878. "</metalink>");
  879. try {
  880. auto m = metalink::parseBinaryStream(&dw);
  881. auto& e = m->getEntries()[0];
  882. auto& c = e->chunkChecksum;
  883. CPPUNIT_ASSERT(c);
  884. CPPUNIT_ASSERT_EQUAL(1024, c->getPieceLength());
  885. CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), c->getHashType());
  886. } catch(Exception& e) {
  887. CPPUNIT_FAIL(e.stackTrace());
  888. }
  889. }
  890. #endif // ENABLE_MESSAGE_DIGEST
  891. void MetalinkProcessorTest::testLargeFileSize()
  892. {
  893. ByteArrayDiskWriter dw;
  894. dw.setString
  895. ("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
  896. "<files>"
  897. "<file name=\"dvd.iso\">"
  898. " <size>9223372036854775807</size>"
  899. " <resources>"
  900. " <url type=\"http\">ftp://mirror/</url>"
  901. " </resources>"
  902. "</file>"
  903. "</files>"
  904. "</metalink>");
  905. try {
  906. auto m = metalink::parseBinaryStream(&dw);
  907. auto& e = m->getEntries()[0];
  908. CPPUNIT_ASSERT_EQUAL((int64_t)9223372036854775807LL, e->getLength());
  909. } catch(Exception& e) {
  910. CPPUNIT_FAIL(e.stackTrace());
  911. }
  912. }
  913. void MetalinkProcessorTest::testXmlPrefixV3()
  914. {
  915. ByteArrayDiskWriter dw;
  916. dw.setString("<m:metalink version=\"3.0\" xmlns:m=\"http://www.metalinker.org/\">"
  917. "<m:files>"
  918. "<m:file name=\"dvd.iso\">"
  919. " <m:size>9223372036854775807</m:size>"
  920. " <m:resources>"
  921. " <m:url type=\"http\">ftp://mirror/</m:url>"
  922. " </m:resources>"
  923. "</m:file>"
  924. "</m:files>"
  925. "</m:metalink>");
  926. try {
  927. auto m = metalink::parseBinaryStream(&dw);
  928. CPPUNIT_ASSERT_EQUAL((size_t)1, m->getEntries().size());
  929. auto& e = m->getEntries()[0];
  930. CPPUNIT_ASSERT_EQUAL((int64_t)9223372036854775807LL, e->getLength());
  931. } catch(Exception& e) {
  932. CPPUNIT_FAIL(e.stackTrace());
  933. }
  934. }
  935. } // namespace aria2