diff --git a/ChangeLog b/ChangeLog index 78994bc6..4a4ed6af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-11-28 Tatsuhiro Tsujikawa + + Accept BitTorrent Magnet URI in Metalink resource type bittorrent. + Rewritten UTMetadataPostDownloadHandler. To create torrent data + from metadata, use new metadata2Torrent() function. + * src/BtDependency.cc + * src/UTMetadataPostDownloadHandler.cc + * src/bittorrent_helper.cc + * src/bittorrent_helper.h + * test/BittorrentHelperTest.cc + * test/BtDependencyTest.cc + 2009-11-28 Tatsuhiro Tsujikawa Use createRequestGroupForUri to create the download for torrent diff --git a/src/BtDependency.cc b/src/BtDependency.cc index 6041a9ef..270e27ca 100644 --- a/src/BtDependency.cc +++ b/src/BtDependency.cc @@ -71,8 +71,15 @@ bool BtDependency::resolve() dependee->getPieceStorage()->getDiskAdaptor(); diskAdaptor->openExistingFile(); std::string content = util::toString(diskAdaptor); - bittorrent::loadFromMemory - (content, context, File(dependee->getFirstFilePath()).getBasename()); + if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) { + const BDE& attrs = + dependee->getDownloadContext()->getAttribute(bittorrent::BITTORRENT); + bittorrent::loadFromMemory + (bittorrent::metadata2Torrent(content, attrs), context, "default"); + } else { + bittorrent::loadFromMemory + (content, context, File(dependee->getFirstFilePath()).getBasename()); + } if(context->getFileEntries().size() != _dependant->getDownloadContext()->getFileEntries().size()) { throw DL_ABORT_EX("The number of file in torrent doesn't match to" diff --git a/src/UTMetadataPostDownloadHandler.cc b/src/UTMetadataPostDownloadHandler.cc index 90ced69f..12e0f9dc 100644 --- a/src/UTMetadataPostDownloadHandler.cc +++ b/src/UTMetadataPostDownloadHandler.cc @@ -45,6 +45,7 @@ #include "a2functional.h" #include "DiskAdaptor.h" #include "PieceStorage.h" +#include "bencode.h" namespace aria2 { @@ -72,35 +73,13 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups { SharedHandle dctx = requestGroup->getDownloadContext(); const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT); - std::string torrent = - strconcat("d4:info", - util::toString(requestGroup->getPieceStorage()->getDiskAdaptor()), - "e"); + std::string metadata = + util::toString(requestGroup->getPieceStorage()->getDiskAdaptor()); + std::string torrent = bittorrent::metadata2Torrent(metadata, attrs); try { std::deque > newRgs; createRequestGroupForBitTorrent(newRgs, requestGroup->getOption(), std::deque(), torrent); - if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) { - for(std::deque >::const_iterator i = - newRgs.begin(); i != newRgs.end(); ++i) { - SharedHandle newDctx = (*i)->getDownloadContext(); - if(!newDctx->hasAttribute(bittorrent::BITTORRENT)) { - continue; - } - BDE& newAttrs = newDctx->getAttribute(bittorrent::BITTORRENT); - if(attrs[bittorrent::INFO_HASH].s() != - newAttrs[bittorrent::INFO_HASH].s()) { - continue; - } - assert(newAttrs[bittorrent::ANNOUNCE_LIST].isList()); - if(newAttrs[bittorrent::ANNOUNCE_LIST].size() == 0) { - newAttrs[bittorrent::ANNOUNCE_LIST] = - attrs[bittorrent::ANNOUNCE_LIST]; - } - break; - } - } - groups.insert(groups.end(), newRgs.begin(), newRgs.end()); } catch(RecoverableException& e) { _logger->error("Failed to parse BitTorrent metadata.", e); diff --git a/src/bittorrent_helper.cc b/src/bittorrent_helper.cc index d6685756..8945eebd 100644 --- a/src/bittorrent_helper.cc +++ b/src/bittorrent_helper.cc @@ -904,6 +904,21 @@ void loadMagnet dctx->setAttribute(BITTORRENT, attrs); } +std::string metadata2Torrent(const std::string& metadata, const BDE& attrs) +{ + std::string torrent = "d"; + if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) { + const BDE& announceList = attrs[bittorrent::ANNOUNCE_LIST]; + if(announceList.size() > 0) { + torrent += "13:announce-list"; + torrent += bencode::encode(announceList); + } + } + torrent += + strconcat("4:info", metadata, "e"); + return torrent; +} + } // namespace bittorrent } // namespace aria2 diff --git a/src/bittorrent_helper.h b/src/bittorrent_helper.h index 06d26058..6893cb6b 100644 --- a/src/bittorrent_helper.h +++ b/src/bittorrent_helper.h @@ -230,6 +230,11 @@ void assertID void generateRandomKey(unsigned char* key); +// Converts attrs into torrent data. attrs must be a BDE::dict. This +// function does not guarantee the returned string is valid torrent +// data. +std::string metadata2Torrent(const std::string& metadata, const BDE& attrs); + } // namespace bittorrent } // namespace aria2 diff --git a/test/BittorrentHelperTest.cc b/test/BittorrentHelperTest.cc index 684e802a..587b09e2 100644 --- a/test/BittorrentHelperTest.cc +++ b/test/BittorrentHelperTest.cc @@ -61,6 +61,7 @@ class BittorrentHelperTest:public CppUnit::TestFixture { CPPUNIT_TEST(testMetadata); CPPUNIT_TEST(testParseMagnet); CPPUNIT_TEST(testParseMagnet_base32); + CPPUNIT_TEST(testMetadata2Torrent); CPPUNIT_TEST_SUITE_END(); public: void setUp() { @@ -102,6 +103,7 @@ public: void testMetadata(); void testParseMagnet(); void testParseMagnet_base32(); + void testMetadata2Torrent(); }; @@ -734,6 +736,25 @@ void BittorrentHelperTest::testParseMagnet_base32() util::toHex(attrs[bittorrent::INFO_HASH].s())); } +void BittorrentHelperTest::testMetadata2Torrent() +{ + std::string metadata = "METADATA"; + BDE attrs = BDE::dict(); + BDE announceList = BDE::list(); + attrs[ANNOUNCE_LIST] = announceList; + CPPUNIT_ASSERT_EQUAL + (std::string("d4:infoMETADATAe"), metadata2Torrent(metadata, attrs)); + announceList << BDE::list(); + announceList[0] << std::string("http://localhost/announce"); + CPPUNIT_ASSERT_EQUAL + (std::string("d" + "13:announce-list" + "ll25:http://localhost/announceee" + "4:infoMETADATA" + "e"), + metadata2Torrent(metadata, attrs)); +} + } // namespace bittorrent } // namespace aria2 diff --git a/test/BtDependencyTest.cc b/test/BtDependencyTest.cc index c372321d..d1dc1f77 100644 --- a/test/BtDependencyTest.cc +++ b/test/BtDependencyTest.cc @@ -13,6 +13,9 @@ #include "FileEntry.h" #include "PieceSelector.h" #include "bittorrent_helper.h" +#include "DirectDiskAdaptor.h" +#include "ByteArrayDiskWriter.h" +#include "MockPieceStorage.h" namespace aria2 { @@ -20,6 +23,7 @@ class BtDependencyTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BtDependencyTest); CPPUNIT_TEST(testResolve); + CPPUNIT_TEST(testResolve_metadata); CPPUNIT_TEST(testResolve_loadError); CPPUNIT_TEST(testResolve_dependeeFailure); CPPUNIT_TEST(testResolve_dependeeInProgress); @@ -64,6 +68,7 @@ public: } void testResolve(); + void testResolve_metadata(); void testResolve_loadError(); void testResolve_dependeeFailure(); void testResolve_dependeeInProgress(); @@ -93,6 +98,34 @@ void BtDependencyTest::testResolve() CPPUNIT_ASSERT_EQUAL((size_t)1, firstFileEntry->getRemainingUris().size()); } +void BtDependencyTest::testResolve_metadata() +{ + SharedHandle dependant = createDependant(_option); + SharedHandle dependee = + createDependee(_option, "metadata", 0); + + SharedHandle diskAdaptor(new DirectDiskAdaptor()); + SharedHandle diskWriter(new ByteArrayDiskWriter()); + diskAdaptor->setDiskWriter(diskWriter); + diskWriter->setString + ("d4:name19:aria2-0.8.2.tar.bz26:lengthi384e12:piece lengthi128e" + "6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCC" + "e"); + SharedHandle pieceStorage(new MockPieceStorage()); + pieceStorage->setDiskAdaptor(diskAdaptor); + pieceStorage->setDownloadFinished(true); + dependee->setPieceStorage(pieceStorage); + BDE attrs = BDE::dict(); + dependee->getDownloadContext()->setAttribute(bittorrent::BITTORRENT, attrs); + + BtDependency dep(dependant, dependee); + CPPUNIT_ASSERT(dep.resolve()); + + CPPUNIT_ASSERT_EQUAL + (std::string("cd41c7fdddfd034a15a04d7ff881216e01c4ceaf"), + bittorrent::getInfoHashString(dependant->getDownloadContext())); +} + void BtDependencyTest::testResolve_loadError() { SharedHandle dependant = createDependant(_option);