2007-10-27 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Added the ability to recognize url-list in a torrent file.
	The retrieved URLs are attached to the corresponding FileEntry.
	* src/DefaultBtContext.{h, cc}
	* src/FileEntry.{h, cc}
	* test/DefaultBtContextTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2007-10-27 12:32:14 +00:00
parent fdb2ee28cc
commit 368d53071a
7 changed files with 101 additions and 8 deletions

View File

@ -98,7 +98,8 @@ void DefaultBtContext::extractPieceHash(const unsigned char* hashData,
}
void DefaultBtContext::extractFileEntries(Dictionary* infoDic,
const string& defaultName) {
const string& defaultName,
const Strings& urlList) {
// TODO use dynamic_cast
Data* nameData = (Data*)infoDic->get("name");
if(nameData) {
@ -134,9 +135,13 @@ void DefaultBtContext::extractFileEntries(Dictionary* infoDic,
Data* lastPath = (Data*)paths.back();
path += lastPath->toString();
Strings uris;
transform(urlList.begin(), urlList.end(), back_inserter(uris),
bind2nd(plus<string>(), "/"+name+"/"+path));
FileEntryHandle fileEntry(new FileEntry(path,
lengthData->toLLInt(),
offset));
offset,
uris));
fileEntries.push_back(fileEntry);
offset += fileEntry->getLength();
}
@ -146,7 +151,7 @@ void DefaultBtContext::extractFileEntries(Dictionary* infoDic,
fileMode = BtContext::SINGLE;
Data* length = (Data*)infoDic->get("length");
totalLength = length->toLLInt();
FileEntryHandle fileEntry(new FileEntry(name, totalLength, 0));
FileEntryHandle fileEntry(new FileEntry(name, totalLength, 0, urlList));
fileEntries.push_back(fileEntry);
}
}
@ -174,6 +179,25 @@ void DefaultBtContext::extractAnnounceList(List* announceListData) {
}
}
Strings DefaultBtContext::extractUrlList(const MetaEntry* obj)
{
Strings uris;
if(dynamic_cast<const List*>(obj)) {
const List* urlList = (const List*)obj;
for(MetaList::const_iterator itr = urlList->getList().begin();
itr != urlList->getList().end(); ++itr) {
Data* data = dynamic_cast<Data*>(*itr);
if(data) {
uris.push_back(data->toString());
}
}
} else if(dynamic_cast<const Data*>(obj)) {
const Data* urlData = (const Data*)obj;
uris.push_back(urlData->toString());
}
return uris;
}
void DefaultBtContext::load(const string& torrentFile) {
clear();
MetaEntry* rootEntry = MetaFileUtil::parseMetaFile(torrentFile);
@ -199,8 +223,12 @@ void DefaultBtContext::load(const string& torrentFile) {
extractPieceHash((unsigned char*)pieceHashData->getData(),
pieceHashData->getLen(),
PIECE_HASH_LENGTH);
// retrieve uri-list.
// This implemantation obeys HTTP-Seeding specification:
// see http://www.getright.com/seedtorrent.html
Strings urlList = extractUrlList(rootDic->get("url-list"));
// retrieve file entries
extractFileEntries(infoDic, torrentFile);
extractFileEntries(infoDic, torrentFile, urlList);
// retrieve announce
Data* announceData = (Data*)rootDic->get("announce");
List* announceListData = (List*)rootDic->get("announce-list");

View File

@ -66,9 +66,13 @@ private:
int32_t hashDataLength,
int32_t hashLength);
void extractFileEntries(Dictionary* infoDic,
const string& defaultName);
const string& defaultName,
const Strings& urlList);
void extractAnnounce(Data* announceData);
void extractAnnounceList(List* announceListData);
Strings extractUrlList(const MetaEntry* obj);
public:
DefaultBtContext();
virtual ~DefaultBtContext();

View File

@ -39,8 +39,9 @@
FileEntry::FileEntry(const string& path,
int64_t length,
int64_t offset):
path(path), length(length), offset(offset),
int64_t offset,
const Strings& uris):
path(path), _uris(uris), length(length), offset(offset),
extracted(false), requested(true) {}
FileEntry::~FileEntry() {}

View File

@ -41,6 +41,7 @@
class FileEntry {
private:
string path;
Strings _uris;
int64_t length;
int64_t offset;
bool extracted;
@ -48,7 +49,7 @@ private:
public:
FileEntry():length(0), offset(0), extracted(false), requested(false) {}
FileEntry(const string& path, int64_t length, int64_t offset);
FileEntry(const string& path, int64_t length, int64_t offset, const Strings& uris = Strings());
~FileEntry();
@ -85,6 +86,11 @@ public:
void setRequested(bool flag) { this->requested = flag; }
void setupDir(const string& parentDir);
const Strings& getAssociatedUris() const
{
return _uris;
}
};
typedef SharedHandle<FileEntry> FileEntryHandle;

View File

@ -25,6 +25,8 @@ class DefaultBtContextTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testGetInfoHashAsString);
CPPUNIT_TEST(testGetPeerId);
CPPUNIT_TEST(testComputeFastSet);
CPPUNIT_TEST(testGetFileEntries_multiFileUrlList);
CPPUNIT_TEST(testGetFileEntries_singleFileUrlList);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
@ -46,6 +48,8 @@ public:
void testGetInfoHashAsString();
void testGetPeerId();
void testComputeFastSet();
void testGetFileEntries_multiFileUrlList();
void testGetFileEntries_singleFileUrlList();
};
@ -255,3 +259,51 @@ void DefaultBtContextTest::testComputeFastSet()
Integers ansSet2(&ans2[0], &ans2[10]);
CPPUNIT_ASSERT(equal(fastSet.begin(), fastSet.end(), ansSet2.begin()));
}
void DefaultBtContextTest::testGetFileEntries_multiFileUrlList() {
DefaultBtContext btContext;
btContext.load("url-list-multiFile.torrent");
// This is multi-file torrent.
FileEntries fileEntries = btContext.getFileEntries();
// There are 2 file entries.
CPPUNIT_ASSERT_EQUAL((size_t)2, fileEntries.size());
FileEntries::iterator itr = fileEntries.begin();
FileEntryHandle fileEntry1 = *itr;
CPPUNIT_ASSERT_EQUAL(string("aria2/src/aria2c"),
fileEntry1->getPath());
Strings uris1 = fileEntry1->getAssociatedUris();
CPPUNIT_ASSERT_EQUAL((size_t)2, uris1.size());
CPPUNIT_ASSERT_EQUAL(string("http://localhost/dist/aria2-test/aria2/src/aria2c"),
uris1[0]);
CPPUNIT_ASSERT_EQUAL(string("http://mirror/dist/aria2-test/aria2/src/aria2c"),
uris1[1]);
itr++;
FileEntryHandle fileEntry2 = *itr;
CPPUNIT_ASSERT_EQUAL(string("aria2-0.2.2.tar.bz2"),
fileEntry2->getPath());
Strings uris2 = fileEntry2->getAssociatedUris();
CPPUNIT_ASSERT_EQUAL((size_t)2, uris2.size());
CPPUNIT_ASSERT_EQUAL(string("http://localhost/dist/aria2-test/aria2-0.2.2.tar.bz2"),
uris2[0]);
CPPUNIT_ASSERT_EQUAL(string("http://mirror/dist/aria2-test/aria2-0.2.2.tar.bz2"),
uris2[1]);
}
void DefaultBtContextTest::testGetFileEntries_singleFileUrlList() {
DefaultBtContext btContext;
btContext.load("url-list-singleFile.torrent");
// This is multi-file torrent.
FileEntries fileEntries = btContext.getFileEntries();
// There are 1 file entries.
CPPUNIT_ASSERT_EQUAL((size_t)1, fileEntries.size());
FileEntryHandle fileEntry1 = fileEntries.front();
CPPUNIT_ASSERT_EQUAL(string("aria2.tar.bz2"),
fileEntry1->getPath());
Strings uris1 = fileEntry1->getAssociatedUris();
CPPUNIT_ASSERT_EQUAL((size_t)1, uris1.size());
CPPUNIT_ASSERT_EQUAL(string("http://localhost/dist/aria2.tar.bz2"),
uris1[0]);
}

View File

@ -0,0 +1 @@
d8:url-listl21:http://localhost/dist18:http://mirror/diste8:announce36:http://aria.rednoah.com/announce.php13:announce-listll15:http://tracker1el15:http://tracker2el15:http://tracker3ee7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod5:filesld6:lengthi284e4:pathl5:aria23:src6:aria2ceed6:lengthi100e4:pathl19:aria2-0.2.2.tar.bz2eee4:name10:aria2-test12:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee

View File

@ -0,0 +1 @@
d8:url-list35:http://localhost/dist/aria2.tar.bz28:announce36:http://aria.rednoah.com/announce.php13:announce-listll15:http://tracker1el15:http://tracker2el15:http://tracker3ee7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod6:lengthi7680e4:name13:aria2.tar.bz212:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee