mirror of https://github.com/aria2/aria2
2009-11-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Rewritten Magnet URI parser. * src/Makefile.am * src/ProtocolDetector.cc * src/bittorrent_helper.cc * src/bittorrent_helper.h * src/download_helper.cc * src/magnet.cc * src/magnet.h * test/BittorrentHelperTest.cc * test/MagnetTest.cc * test/Makefile.am * test/ProtocolDetectorTest.ccpull/1/head
parent
d2cefd8613
commit
512be58217
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
2009-11-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
|
Rewritten Magnet URI parser.
|
||||||
|
* src/Makefile.am
|
||||||
|
* src/ProtocolDetector.cc
|
||||||
|
* src/bittorrent_helper.cc
|
||||||
|
* src/bittorrent_helper.h
|
||||||
|
* src/download_helper.cc
|
||||||
|
* src/magnet.cc
|
||||||
|
* src/magnet.h
|
||||||
|
* test/BittorrentHelperTest.cc
|
||||||
|
* test/MagnetTest.cc
|
||||||
|
* test/Makefile.am
|
||||||
|
* test/ProtocolDetectorTest.cc
|
||||||
|
|
||||||
2009-11-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
2009-11-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
Use hton64
|
Use hton64
|
||||||
|
|
|
@ -355,6 +355,7 @@ SRCS += PeerAbstractCommand.cc PeerAbstractCommand.h\
|
||||||
UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\
|
UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\
|
||||||
UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\
|
UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\
|
||||||
UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\
|
UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\
|
||||||
|
magnet.cc magnet.h\
|
||||||
DHTNode.cc DHTNode.h\
|
DHTNode.cc DHTNode.h\
|
||||||
DHTBucket.cc DHTBucket.h\
|
DHTBucket.cc DHTBucket.h\
|
||||||
DHTRoutingTable.cc DHTRoutingTable.h\
|
DHTRoutingTable.cc DHTRoutingTable.h\
|
||||||
|
|
|
@ -153,6 +153,7 @@ bin_PROGRAMS = aria2c$(EXEEXT)
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\
|
||||||
|
@ENABLE_BITTORRENT_TRUE@ magnet.cc magnet.h\
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTNode.cc DHTNode.h\
|
@ENABLE_BITTORRENT_TRUE@ DHTNode.cc DHTNode.h\
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTBucket.cc DHTBucket.h\
|
@ENABLE_BITTORRENT_TRUE@ DHTBucket.cc DHTBucket.h\
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTRoutingTable.cc DHTRoutingTable.h\
|
@ENABLE_BITTORRENT_TRUE@ DHTRoutingTable.cc DHTRoutingTable.h\
|
||||||
|
@ -508,12 +509,12 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
|
||||||
UTMetadataDataExtensionMessage.h UTMetadataRequestTracker.cc \
|
UTMetadataDataExtensionMessage.h UTMetadataRequestTracker.cc \
|
||||||
UTMetadataRequestTracker.h UTMetadataRequestFactory.cc \
|
UTMetadataRequestTracker.h UTMetadataRequestFactory.cc \
|
||||||
UTMetadataRequestFactory.h UTMetadataPostDownloadHandler.cc \
|
UTMetadataRequestFactory.h UTMetadataPostDownloadHandler.cc \
|
||||||
UTMetadataPostDownloadHandler.h DHTNode.cc DHTNode.h \
|
UTMetadataPostDownloadHandler.h magnet.cc magnet.h DHTNode.cc \
|
||||||
DHTBucket.cc DHTBucket.h DHTRoutingTable.cc DHTRoutingTable.h \
|
DHTNode.h DHTBucket.cc DHTBucket.h DHTRoutingTable.cc \
|
||||||
DHTMessageEntry.cc DHTMessageEntry.h DHTMessageDispatcher.h \
|
DHTRoutingTable.h DHTMessageEntry.cc DHTMessageEntry.h \
|
||||||
DHTMessageDispatcherImpl.cc DHTMessageDispatcherImpl.h \
|
DHTMessageDispatcher.h DHTMessageDispatcherImpl.cc \
|
||||||
DHTMessageReceiver.cc DHTMessageReceiver.h \
|
DHTMessageDispatcherImpl.h DHTMessageReceiver.cc \
|
||||||
DHTMessageTracker.cc DHTMessageTracker.h \
|
DHTMessageReceiver.h DHTMessageTracker.cc DHTMessageTracker.h \
|
||||||
DHTMessageTrackerEntry.cc DHTMessageTrackerEntry.h \
|
DHTMessageTrackerEntry.cc DHTMessageTrackerEntry.h \
|
||||||
DHTMessage.cc DHTMessage.h DHTConnection.h \
|
DHTMessage.cc DHTMessage.h DHTConnection.h \
|
||||||
DHTConnectionImpl.cc DHTConnectionImpl.h DHTAbstractMessage.cc \
|
DHTConnectionImpl.cc DHTConnectionImpl.h DHTAbstractMessage.cc \
|
||||||
|
@ -670,7 +671,8 @@ am__objects_6 =
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTracker.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTracker.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactory.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactory.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandler.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandler.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTNode.$(OBJEXT) DHTBucket.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ magnet.$(OBJEXT) DHTNode.$(OBJEXT) \
|
||||||
|
@ENABLE_BITTORRENT_TRUE@ DHTBucket.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTRoutingTable.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ DHTRoutingTable.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTMessageEntry.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ DHTMessageEntry.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTMessageDispatcherImpl.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ DHTMessageDispatcherImpl.$(OBJEXT) \
|
||||||
|
@ -1573,6 +1575,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_aton.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_aton.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgen.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgen.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localtime_r.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localtime_r.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/magnet.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messageDigest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messageDigest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/option_processing.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/option_processing.Po@am__quote@
|
||||||
|
|
|
@ -41,6 +41,9 @@
|
||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#ifdef ENABLE_BITTORRENT
|
||||||
|
# include "bittorrent_helper.h"
|
||||||
|
#endif // ENABLE_BITTORRENT
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -70,8 +73,16 @@ bool ProtocolDetector::guessTorrentFile(const std::string& uri) const
|
||||||
|
|
||||||
bool ProtocolDetector::guessTorrentMagnet(const std::string& uri) const
|
bool ProtocolDetector::guessTorrentMagnet(const std::string& uri) const
|
||||||
{
|
{
|
||||||
return util::startsWith(uri, "magnet:?") &&
|
#ifdef ENABLE_BITTORRENT
|
||||||
uri.find("xt=urn:btih:") != std::string::npos;
|
try {
|
||||||
|
bittorrent::parseMagnet(uri);
|
||||||
|
return true;
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else // !ENABLE_BITTORRENT
|
||||||
|
return false;
|
||||||
|
#endif // !ENABLE_BITTORRENT
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtocolDetector::guessMetalinkFile(const std::string& uri) const
|
bool ProtocolDetector::guessMetalinkFile(const std::string& uri) const
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "BtConstants.h"
|
#include "BtConstants.h"
|
||||||
#include "bitfield.h"
|
#include "bitfield.h"
|
||||||
#include "base32.h"
|
#include "base32.h"
|
||||||
|
#include "magnet.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -848,64 +849,58 @@ void generateRandomKey(unsigned char* key)
|
||||||
MessageDigestHelper::digest(key, 20, MessageDigestContext::SHA1, bytes, sizeof(bytes));
|
MessageDigestHelper::digest(key, 20, MessageDigestContext::SHA1, bytes, sizeof(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseMagnetLink(const std::string& magnetLink,
|
BDE parseMagnet(const std::string& magnet)
|
||||||
const SharedHandle<DownloadContext>& dctx)
|
|
||||||
{
|
{
|
||||||
// magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
|
BDE result;
|
||||||
// <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii info hash,
|
BDE r = magnet::parse(magnet);
|
||||||
// or 32bytes Base32 encoded info hash.
|
if(r.isNone()) {
|
||||||
if(!util::startsWith(magnetLink, "magnet:?")) {
|
throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
|
||||||
throw DL_ABORT_EX("Invalid magnet link.");
|
|
||||||
}
|
}
|
||||||
std::deque<std::string> queries;
|
if(!r.containsKey("xt")) {
|
||||||
util::split(std::string(magnetLink.begin()+8, magnetLink.end()),
|
throw DL_ABORT_EX("Missing xt parameter in Magnet URI.");
|
||||||
std::back_inserter(queries), "&");
|
|
||||||
std::string infoHash;
|
|
||||||
std::string name;
|
|
||||||
BDE announceList = BDE::list();
|
|
||||||
announceList << BDE::list();
|
|
||||||
for(std::deque<std::string>::const_iterator i = queries.begin();
|
|
||||||
i != queries.end(); ++i) {
|
|
||||||
std::pair<std::string, std::string> kv;
|
|
||||||
util::split(kv, *i, '=');
|
|
||||||
if(kv.first == "xt") {
|
|
||||||
if(!util::startsWith(kv.second, "urn:btih:")) {
|
|
||||||
throw DL_ABORT_EX("Bad BitTorrent Magnet Link.");
|
|
||||||
}
|
|
||||||
if(infoHash.empty()) {
|
|
||||||
infoHash = kv.second.substr(9);
|
|
||||||
} else {
|
|
||||||
throw DL_ABORT_EX("More than 1 info hash in magnet link.");
|
|
||||||
}
|
|
||||||
} else if(kv.first == "dn") {
|
|
||||||
name = kv.second;
|
|
||||||
} else if(kv.first == "tr") {
|
|
||||||
announceList[0] << kv.second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const BDE& xts = r["xt"];
|
||||||
|
if(xts.size() == 0 || !util::startsWith(xts[0].s(), "urn:btih:")) {
|
||||||
|
throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
|
||||||
|
}
|
||||||
|
std::string infoHash = xts[0].s().substr(9);
|
||||||
if(infoHash.size() == 32) {
|
if(infoHash.size() == 32) {
|
||||||
std::string rawhash = base32::decode(infoHash);
|
std::string rawhash = base32::decode(infoHash);
|
||||||
if(rawhash.size() != 20) {
|
if(rawhash.size() != 20) {
|
||||||
throw DL_ABORT_EX("Invalid info hash");
|
throw DL_ABORT_EX("Invalid BitTorrent Info Hash.");
|
||||||
}
|
}
|
||||||
infoHash = rawhash;
|
infoHash = rawhash;
|
||||||
} else if(infoHash.size() == 40) {
|
} else if(infoHash.size() == 40) {
|
||||||
std::string rawhash = util::fromHex(infoHash);
|
std::string rawhash = util::fromHex(infoHash);
|
||||||
if(rawhash.empty()) {
|
if(rawhash.empty()) {
|
||||||
throw DL_ABORT_EX("Invalid info hash");
|
throw DL_ABORT_EX("Invalid BitTorrent Info Hash.");
|
||||||
}
|
}
|
||||||
infoHash = rawhash;
|
infoHash = rawhash;
|
||||||
} else {
|
} else {
|
||||||
throw DL_ABORT_EX("Invalid magnet link.");
|
throw DL_ABORT_EX("Invalid BitTorrent Info Hash.");
|
||||||
}
|
}
|
||||||
if(name.empty()) {
|
BDE announceList = BDE::list();
|
||||||
name = util::toHex(infoHash);
|
if(r.containsKey("tr")) {
|
||||||
|
announceList << r["tr"];
|
||||||
|
}
|
||||||
|
std::string name;
|
||||||
|
if(r.containsKey("dn") && r["dn"].size()) {
|
||||||
|
name = r["dn"][0].s();
|
||||||
|
} else {
|
||||||
|
name = strconcat("[METADATA]", util::toHex(infoHash));
|
||||||
}
|
}
|
||||||
BDE attrs = BDE::dict();
|
BDE attrs = BDE::dict();
|
||||||
attrs[INFO_HASH] = infoHash;
|
attrs[INFO_HASH] = infoHash;
|
||||||
attrs[NAME] = name;
|
attrs[NAME] = name;
|
||||||
attrs[ANNOUNCE_LIST] = announceList;
|
attrs[ANNOUNCE_LIST] = announceList;
|
||||||
|
result = attrs;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadMagnet
|
||||||
|
(const std::string& magnet, const SharedHandle<DownloadContext>& dctx)
|
||||||
|
{
|
||||||
|
BDE attrs = parseMagnet(magnet);
|
||||||
dctx->setAttribute(BITTORRENT, attrs);
|
dctx->setAttribute(BITTORRENT, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,10 +119,21 @@ void loadFromMemory(const std::string& context,
|
||||||
const std::string& defaultName,
|
const std::string& defaultName,
|
||||||
const std::string& overrideName = "");
|
const std::string& overrideName = "");
|
||||||
|
|
||||||
// Parses BitTorrent magnet link.
|
// Parses BitTorrent Magnet URI and returns BDE::dict() which includes
|
||||||
|
// infoHash, name and announceList. If parsing operation failed, an
|
||||||
|
// RecoverableException will be thrown. infoHash and name are string
|
||||||
|
// and announceList is a list of list of announce URI.
|
||||||
|
//
|
||||||
// magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
|
// magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
|
||||||
void parseMagnetLink(const std::string& magnetLink,
|
// <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii string,
|
||||||
const SharedHandle<DownloadContext>& ctx);
|
// or 32bytes Base32 encoded string.
|
||||||
|
BDE parseMagnet(const std::string& magnet);
|
||||||
|
|
||||||
|
// Parses BitTorrent Magnet URI and set them in ctx as a
|
||||||
|
// bittorrent::BITTORRENT attibute. If parsing operation failed, an
|
||||||
|
// RecoverableException will be thrown.
|
||||||
|
void loadMagnet
|
||||||
|
(const std::string& magnet, const SharedHandle<DownloadContext>& ctx);
|
||||||
|
|
||||||
// Generates Peer ID. BitTorrent specification says Peer ID is 20-byte
|
// Generates Peer ID. BitTorrent specification says Peer ID is 20-byte
|
||||||
// length. This function uses peerIdPrefix as a Peer ID and it is
|
// length. This function uses peerIdPrefix as a Peer ID and it is
|
||||||
|
|
|
@ -242,7 +242,7 @@ createBtMagnetRequestGroup(const std::string& magnetLink,
|
||||||
dctx->markTotalLengthIsUnknown();
|
dctx->markTotalLengthIsUnknown();
|
||||||
rg->setFileAllocationEnabled(false);
|
rg->setFileAllocationEnabled(false);
|
||||||
rg->setPreLocalFileCheckEnabled(false);
|
rg->setPreLocalFileCheckEnabled(false);
|
||||||
bittorrent::parseMagnetLink(magnetLink, dctx);
|
bittorrent::loadMagnet(magnetLink, dctx);
|
||||||
dctx->getFirstFileEntry()->setPath
|
dctx->getFirstFileEntry()->setPath
|
||||||
(dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s());
|
(dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s());
|
||||||
rg->setDownloadContext(dctx);
|
rg->setDownloadContext(dctx);
|
||||||
|
@ -327,16 +327,7 @@ public:
|
||||||
_requestGroups.push_back(rg);
|
_requestGroups.push_back(rg);
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
else if(_detector.guessTorrentFile(uri)) {
|
else if(_detector.guessTorrentMagnet(uri)) {
|
||||||
try {
|
|
||||||
_requestGroups.push_back(createBtRequestGroup(uri, _option,
|
|
||||||
std::deque<std::string>()));
|
|
||||||
} catch(RecoverableException& e) {
|
|
||||||
// error occurred while parsing torrent file.
|
|
||||||
// We simply ignore it.
|
|
||||||
LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e);
|
|
||||||
}
|
|
||||||
} else if(_detector.guessTorrentMagnet(uri)) {
|
|
||||||
try {
|
try {
|
||||||
SharedHandle<RequestGroup> group =
|
SharedHandle<RequestGroup> group =
|
||||||
createBtMagnetRequestGroup(uri, _option, std::deque<std::string>());
|
createBtMagnetRequestGroup(uri, _option, std::deque<std::string>());
|
||||||
|
@ -346,7 +337,16 @@ public:
|
||||||
// We simply ignore it.
|
// We simply ignore it.
|
||||||
LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e);
|
LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e);
|
||||||
}
|
}
|
||||||
}
|
} else if(_detector.guessTorrentFile(uri)) {
|
||||||
|
try {
|
||||||
|
_requestGroups.push_back(createBtRequestGroup(uri, _option,
|
||||||
|
std::deque<std::string>()));
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
// error occurred while parsing torrent file.
|
||||||
|
// We simply ignore it.
|
||||||
|
LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif // ENABLE_BITTORRENT
|
#endif // ENABLE_BITTORRENT
|
||||||
#ifdef ENABLE_METALINK
|
#ifdef ENABLE_METALINK
|
||||||
else if(_detector.guessMetalinkFile(uri)) {
|
else if(_detector.guessMetalinkFile(uri)) {
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#include "magnet.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
namespace magnet {
|
||||||
|
|
||||||
|
BDE parse(const std::string& magnet)
|
||||||
|
{
|
||||||
|
BDE result;
|
||||||
|
if(!util::startsWith(magnet, "magnet:?")) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
std::deque<std::string> queries;
|
||||||
|
util::split(std::string(magnet.begin()+8, magnet.end()),
|
||||||
|
std::back_inserter(queries), "&");
|
||||||
|
BDE dict = BDE::dict();
|
||||||
|
for(std::deque<std::string>::const_iterator i = queries.begin();
|
||||||
|
i != queries.end(); ++i) {
|
||||||
|
std::pair<std::string, std::string> kv;
|
||||||
|
util::split(kv, *i, '=');
|
||||||
|
if(dict.containsKey(kv.first)) {
|
||||||
|
dict[kv.first] << kv.second;
|
||||||
|
} else {
|
||||||
|
BDE list = BDE::list();
|
||||||
|
list << kv.second;
|
||||||
|
dict[kv.first] = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = dict;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace magnet
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#ifndef _D_MAGNET_H_
|
||||||
|
#define _D_MAGNET_H_
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "BDE.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
namespace magnet {
|
||||||
|
|
||||||
|
// Parses Magnet URI magnet and stores parameters in BDE::dict().
|
||||||
|
// Because same parameter name can appear more than once, the value
|
||||||
|
// associated with a key is BDE::list(). A parameter value is stored
|
||||||
|
// in a list. If parsing operation failed, BDE::none is returned.
|
||||||
|
BDE parse(const std::string& magnet);
|
||||||
|
|
||||||
|
} // namespace magnet
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _D_MAGNET_H_
|
|
@ -59,8 +59,8 @@ class BittorrentHelperTest:public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST(testCreatecompact);
|
CPPUNIT_TEST(testCreatecompact);
|
||||||
CPPUNIT_TEST(testCheckBitfield);
|
CPPUNIT_TEST(testCheckBitfield);
|
||||||
CPPUNIT_TEST(testMetadata);
|
CPPUNIT_TEST(testMetadata);
|
||||||
CPPUNIT_TEST(testParseMagnetLink);
|
CPPUNIT_TEST(testParseMagnet);
|
||||||
CPPUNIT_TEST(testParseMagnetLink_base32);
|
CPPUNIT_TEST(testParseMagnet_base32);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
public:
|
public:
|
||||||
void setUp() {
|
void setUp() {
|
||||||
|
@ -100,8 +100,8 @@ public:
|
||||||
void testCreatecompact();
|
void testCreatecompact();
|
||||||
void testCheckBitfield();
|
void testCheckBitfield();
|
||||||
void testMetadata();
|
void testMetadata();
|
||||||
void testParseMagnetLink();
|
void testParseMagnet();
|
||||||
void testParseMagnetLink_base32();
|
void testParseMagnet_base32();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -700,33 +700,37 @@ void BittorrentHelperTest::testMetadata() {
|
||||||
(size_t)attrs[bittorrent::METADATA_SIZE].i());
|
(size_t)attrs[bittorrent::METADATA_SIZE].i());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testParseMagnetLink()
|
void BittorrentHelperTest::testParseMagnet()
|
||||||
{
|
{
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
|
||||||
std::string magnet =
|
std::string magnet =
|
||||||
"magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2";
|
"magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
|
||||||
bittorrent::parseMagnetLink(magnet, dctx);
|
"&tr=http://tracker1&tr=http://tracker2";
|
||||||
|
BDE attrs = bittorrent::parseMagnet(magnet);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
bittorrent::getInfoHashString(dctx));
|
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
||||||
BDE attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), attrs[bittorrent::NAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), attrs[bittorrent::NAME].s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"),
|
||||||
|
attrs[bittorrent::ANNOUNCE_LIST][0][0].s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"),
|
||||||
|
attrs[bittorrent::ANNOUNCE_LIST][0][1].s());
|
||||||
|
|
||||||
magnet = "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
magnet = "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
||||||
bittorrent::parseMagnetLink(magnet, dctx);
|
attrs = bittorrent::parseMagnet(magnet);
|
||||||
attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
CPPUNIT_ASSERT_EQUAL
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
(std::string("[METADATA]248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
attrs[bittorrent::NAME].s());
|
attrs[bittorrent::NAME].s());
|
||||||
|
CPPUNIT_ASSERT(attrs[bittorrent::ANNOUNCE_LIST].size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testParseMagnetLink_base32()
|
void BittorrentHelperTest::testParseMagnet_base32()
|
||||||
{
|
{
|
||||||
std::string infoHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
std::string infoHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
||||||
std::string base32InfoHash = base32::encode(util::fromHex(infoHash));
|
std::string base32InfoHash = base32::encode(util::fromHex(infoHash));
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
|
||||||
std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2";
|
std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2";
|
||||||
bittorrent::parseMagnetLink(magnet, dctx);
|
BDE attrs = bittorrent::parseMagnet(magnet);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
CPPUNIT_ASSERT_EQUAL
|
||||||
bittorrent::getInfoHashString(dctx));
|
(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
|
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace bittorrent
|
} // namespace bittorrent
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include "magnet.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
namespace magnet {
|
||||||
|
|
||||||
|
class MagnetTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(MagnetTest);
|
||||||
|
CPPUNIT_TEST(testParse);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
public:
|
||||||
|
void testParse();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(MagnetTest);
|
||||||
|
|
||||||
|
void MagnetTest::testParse()
|
||||||
|
{
|
||||||
|
BDE r = parse
|
||||||
|
("magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
|
||||||
|
"&tr=http://tracker1&tr=http://tracker2");
|
||||||
|
CPPUNIT_ASSERT_EQUAL
|
||||||
|
(std::string("urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
|
r["xt"][0].s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), r["dn"][0].s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), r["tr"][0].s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), r["tr"][1].s());
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(parse("http://localhost").isNone());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace magnet
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -143,6 +143,7 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\
|
||||||
UTMetadataRequestTrackerTest.cc\
|
UTMetadataRequestTrackerTest.cc\
|
||||||
UTMetadataRequestFactoryTest.cc\
|
UTMetadataRequestFactoryTest.cc\
|
||||||
UTMetadataPostDownloadHandlerTest.cc\
|
UTMetadataPostDownloadHandlerTest.cc\
|
||||||
|
MagnetTest.cc\
|
||||||
DefaultBtMessageFactoryTest.cc\
|
DefaultBtMessageFactoryTest.cc\
|
||||||
DefaultExtensionMessageFactoryTest.cc\
|
DefaultExtensionMessageFactoryTest.cc\
|
||||||
DHTNodeTest.cc\
|
DHTNodeTest.cc\
|
||||||
|
|
|
@ -92,6 +92,7 @@ check_PROGRAMS = $(am__EXEEXT_1)
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTrackerTest.cc\
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTrackerTest.cc\
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactoryTest.cc\
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactoryTest.cc\
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandlerTest.cc\
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandlerTest.cc\
|
||||||
|
@ENABLE_BITTORRENT_TRUE@ MagnetTest.cc\
|
||||||
@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.cc\
|
@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.cc\
|
||||||
@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.cc\
|
@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.cc\
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTNodeTest.cc\
|
@ENABLE_BITTORRENT_TRUE@ DHTNodeTest.cc\
|
||||||
|
@ -236,7 +237,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
|
||||||
UTMetadataRejectExtensionMessageTest.cc \
|
UTMetadataRejectExtensionMessageTest.cc \
|
||||||
UTMetadataRequestTrackerTest.cc \
|
UTMetadataRequestTrackerTest.cc \
|
||||||
UTMetadataRequestFactoryTest.cc \
|
UTMetadataRequestFactoryTest.cc \
|
||||||
UTMetadataPostDownloadHandlerTest.cc \
|
UTMetadataPostDownloadHandlerTest.cc MagnetTest.cc \
|
||||||
DefaultBtMessageFactoryTest.cc \
|
DefaultBtMessageFactoryTest.cc \
|
||||||
DefaultExtensionMessageFactoryTest.cc DHTNodeTest.cc \
|
DefaultExtensionMessageFactoryTest.cc DHTNodeTest.cc \
|
||||||
DHTBucketTest.cc DHTRoutingTableTest.cc \
|
DHTBucketTest.cc DHTRoutingTableTest.cc \
|
||||||
|
@ -315,6 +316,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTrackerTest.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTrackerTest.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactoryTest.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactoryTest.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandlerTest.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandlerTest.$(OBJEXT) \
|
||||||
|
@ENABLE_BITTORRENT_TRUE@ MagnetTest.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.$(OBJEXT) \
|
||||||
@ENABLE_BITTORRENT_TRUE@ DHTNodeTest.$(OBJEXT) \
|
@ENABLE_BITTORRENT_TRUE@ DHTNodeTest.$(OBJEXT) \
|
||||||
|
@ -814,6 +816,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChunkChecksumValidatorTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChunkChecksumValidatorTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LongestSequencePieceSelectorTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LongestSequencePieceSelectorTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MSEHandshakeTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MSEHandshakeTest.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MagnetTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelperTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelperTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroupTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroupTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntryTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntryTest.Po@am__quote@
|
||||||
|
|
|
@ -47,9 +47,9 @@ void ProtocolDetectorTest::testGuessTorrentFile()
|
||||||
void ProtocolDetectorTest::testGuessTorrentMagnet()
|
void ProtocolDetectorTest::testGuessTorrentMagnet()
|
||||||
{
|
{
|
||||||
ProtocolDetector detector;
|
ProtocolDetector detector;
|
||||||
CPPUNIT_ASSERT(detector.guessTorrentMagnet("magnet:?xt=urn:btih:abcdef"));
|
CPPUNIT_ASSERT
|
||||||
CPPUNIT_ASSERT(detector.guessTorrentMagnet
|
(detector.guessTorrentMagnet
|
||||||
("magnet:?dn=name&xt=urn:btih:abcdef"));
|
("magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"));
|
||||||
CPPUNIT_ASSERT(!detector.guessTorrentMagnet("magnet:?"));
|
CPPUNIT_ASSERT(!detector.guessTorrentMagnet("magnet:?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue