Bläddra i källkod

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
Tatsuhiro Tsujikawa 16 år sedan
förälder
incheckning
512be58217

+ 15 - 0
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>
 
 	Use hton64

+ 1 - 0
src/Makefile.am

@@ -355,6 +355,7 @@ SRCS += PeerAbstractCommand.cc PeerAbstractCommand.h\
 	UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\
 	UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\
 	UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\
+	magnet.cc magnet.h\
 	DHTNode.cc DHTNode.h\
 	DHTBucket.cc DHTBucket.h\
 	DHTRoutingTable.cc DHTRoutingTable.h\

+ 10 - 7
src/Makefile.in

@@ -153,6 +153,7 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_BITTORRENT_TRUE@	UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\
 @ENABLE_BITTORRENT_TRUE@	UTMetadataRequestFactory.cc UTMetadataRequestFactory.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@	DHTBucket.cc DHTBucket.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 \
 	UTMetadataRequestTracker.h UTMetadataRequestFactory.cc \
 	UTMetadataRequestFactory.h UTMetadataPostDownloadHandler.cc \
-	UTMetadataPostDownloadHandler.h DHTNode.cc DHTNode.h \
-	DHTBucket.cc DHTBucket.h DHTRoutingTable.cc DHTRoutingTable.h \
-	DHTMessageEntry.cc DHTMessageEntry.h DHTMessageDispatcher.h \
-	DHTMessageDispatcherImpl.cc DHTMessageDispatcherImpl.h \
-	DHTMessageReceiver.cc DHTMessageReceiver.h \
-	DHTMessageTracker.cc DHTMessageTracker.h \
+	UTMetadataPostDownloadHandler.h magnet.cc magnet.h DHTNode.cc \
+	DHTNode.h DHTBucket.cc DHTBucket.h DHTRoutingTable.cc \
+	DHTRoutingTable.h DHTMessageEntry.cc DHTMessageEntry.h \
+	DHTMessageDispatcher.h DHTMessageDispatcherImpl.cc \
+	DHTMessageDispatcherImpl.h DHTMessageReceiver.cc \
+	DHTMessageReceiver.h DHTMessageTracker.cc DHTMessageTracker.h \
 	DHTMessageTrackerEntry.cc DHTMessageTrackerEntry.h \
 	DHTMessage.cc DHTMessage.h DHTConnection.h \
 	DHTConnectionImpl.cc DHTConnectionImpl.h DHTAbstractMessage.cc \
@@ -670,7 +671,8 @@ am__objects_6 =
 @ENABLE_BITTORRENT_TRUE@	UTMetadataRequestTracker.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	UTMetadataRequestFactory.$(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@	DHTMessageEntry.$(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)/libgen.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)/messageDigest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/option_processing.Po@am__quote@

+ 13 - 2
src/ProtocolDetector.cc

@@ -41,6 +41,9 @@
 #include "Request.h"
 #include "File.h"
 #include "util.h"
+#ifdef ENABLE_BITTORRENT
+# include "bittorrent_helper.h"
+#endif // ENABLE_BITTORRENT
 
 namespace aria2 {
 
@@ -70,8 +73,16 @@ bool ProtocolDetector::guessTorrentFile(const std::string& uri) const
 
 bool ProtocolDetector::guessTorrentMagnet(const std::string& uri) const
 {
-  return util::startsWith(uri, "magnet:?") &&
-    uri.find("xt=urn:btih:") != std::string::npos;
+#ifdef ENABLE_BITTORRENT
+  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

+ 32 - 37
src/bittorrent_helper.cc

@@ -53,6 +53,7 @@
 #include "BtConstants.h"
 #include "bitfield.h"
 #include "base32.h"
+#include "magnet.h"
 
 namespace aria2 {
 
@@ -848,64 +849,58 @@ void generateRandomKey(unsigned char* key)
   MessageDigestHelper::digest(key, 20, MessageDigestContext::SHA1, bytes, sizeof(bytes));
 }
 
-void parseMagnetLink(const std::string& magnetLink,
-		     const SharedHandle<DownloadContext>& dctx)
+BDE parseMagnet(const std::string& magnet)
 {
-  // magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
-  // <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii info hash,
-  // or 32bytes Base32 encoded info hash.
-  if(!util::startsWith(magnetLink, "magnet:?")) {
-    throw DL_ABORT_EX("Invalid magnet link.");
+  BDE result;
+  BDE r = magnet::parse(magnet);
+  if(r.isNone()) {
+    throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
   }
-  std::deque<std::string> queries;
-  util::split(std::string(magnetLink.begin()+8, magnetLink.end()),
-	      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;
-    }
+  if(!r.containsKey("xt")) {
+    throw DL_ABORT_EX("Missing xt parameter in Magnet URI.");
+  }
+  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) {
     std::string rawhash = base32::decode(infoHash);
     if(rawhash.size() != 20) {
-      throw DL_ABORT_EX("Invalid info hash");
+      throw DL_ABORT_EX("Invalid BitTorrent Info Hash.");
     }
     infoHash = rawhash;
   } else if(infoHash.size() == 40) {
     std::string rawhash = util::fromHex(infoHash);
     if(rawhash.empty()) {
-      throw DL_ABORT_EX("Invalid info hash");
+      throw DL_ABORT_EX("Invalid BitTorrent Info Hash.");
     }
     infoHash = rawhash;
   } else {
-    throw DL_ABORT_EX("Invalid magnet link.");
+    throw DL_ABORT_EX("Invalid BitTorrent Info Hash.");
   }
-  if(name.empty()) {
-    name = util::toHex(infoHash);
+  BDE announceList = BDE::list();
+  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();
   attrs[INFO_HASH] = infoHash;
   attrs[NAME] = name;
   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);
 }
 

+ 14 - 3
src/bittorrent_helper.h

@@ -119,10 +119,21 @@ void loadFromMemory(const std::string& context,
 		    const std::string& defaultName,
 		    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>
-void parseMagnetLink(const std::string& magnetLink,
-		     const SharedHandle<DownloadContext>& ctx);
+// <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii string,
+// 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
 // length.  This function uses peerIdPrefix as a Peer ID and it is

+ 9 - 9
src/download_helper.cc

@@ -242,7 +242,7 @@ createBtMagnetRequestGroup(const std::string& magnetLink,
   dctx->markTotalLengthIsUnknown();
   rg->setFileAllocationEnabled(false);
   rg->setPreLocalFileCheckEnabled(false);
-  bittorrent::parseMagnetLink(magnetLink, dctx);
+  bittorrent::loadMagnet(magnetLink, dctx);
   dctx->getFirstFileEntry()->setPath
     (dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s());
   rg->setDownloadContext(dctx);
@@ -327,26 +327,26 @@ public:
       _requestGroups.push_back(rg);
     }
 #ifdef ENABLE_BITTORRENT
-    else if(_detector.guessTorrentFile(uri)) {
+    else if(_detector.guessTorrentMagnet(uri)) {
       try {
-	_requestGroups.push_back(createBtRequestGroup(uri, _option,
-						      std::deque<std::string>()));
+	SharedHandle<RequestGroup> group =
+	  createBtMagnetRequestGroup(uri, _option, std::deque<std::string>());
+	_requestGroups.push_back(group);
       } 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)) {
+    } else if(_detector.guessTorrentFile(uri)) {
       try {
-	SharedHandle<RequestGroup> group =
-	  createBtMagnetRequestGroup(uri, _option, std::deque<std::string>());
-	_requestGroups.push_back(group);
+	_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
 #ifdef ENABLE_METALINK
     else if(_detector.guessMetalinkFile(uri)) {

+ 70 - 0
src/magnet.cc

@@ -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

+ 56 - 0
src/magnet.h

@@ -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_

+ 23 - 19
test/BittorrentHelperTest.cc

@@ -59,8 +59,8 @@ class BittorrentHelperTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testCreatecompact);
   CPPUNIT_TEST(testCheckBitfield);
   CPPUNIT_TEST(testMetadata);
-  CPPUNIT_TEST(testParseMagnetLink);
-  CPPUNIT_TEST(testParseMagnetLink_base32);
+  CPPUNIT_TEST(testParseMagnet);
+  CPPUNIT_TEST(testParseMagnet_base32);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {
@@ -100,8 +100,8 @@ public:
   void testCreatecompact();
   void testCheckBitfield();
   void testMetadata();
-  void testParseMagnetLink();
-  void testParseMagnetLink_base32();
+  void testParseMagnet();
+  void testParseMagnet_base32();
 };
 
 
@@ -700,33 +700,37 @@ void BittorrentHelperTest::testMetadata() {
 		       (size_t)attrs[bittorrent::METADATA_SIZE].i());
 }
 
-void BittorrentHelperTest::testParseMagnetLink()
+void BittorrentHelperTest::testParseMagnet()
 {
-  SharedHandle<DownloadContext> dctx(new DownloadContext());
   std::string magnet =
-    "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2";
-  bittorrent::parseMagnetLink(magnet, dctx);
+    "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
+    "&tr=http://tracker1&tr=http://tracker2";
+  BDE attrs = bittorrent::parseMagnet(magnet);
   CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
-		       bittorrent::getInfoHashString(dctx));
-  BDE attrs = dctx->getAttribute(bittorrent::BITTORRENT);
+		       util::toHex(attrs[bittorrent::INFO_HASH].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";
-  bittorrent::parseMagnetLink(magnet, dctx);
-  attrs = dctx->getAttribute(bittorrent::BITTORRENT);
-  CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
-		       attrs[bittorrent::NAME].s());
+  attrs = bittorrent::parseMagnet(magnet);
+  CPPUNIT_ASSERT_EQUAL
+    (std::string("[METADATA]248d0a1cd08284299de78d5c1ed359bb46717d8c"),
+     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 base32InfoHash = base32::encode(util::fromHex(infoHash));
-  SharedHandle<DownloadContext> dctx(new DownloadContext());
   std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2";
-  bittorrent::parseMagnetLink(magnet, dctx);
-  CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
-		       bittorrent::getInfoHashString(dctx));
+  BDE attrs = bittorrent::parseMagnet(magnet);
+  CPPUNIT_ASSERT_EQUAL
+    (std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
+     util::toHex(attrs[bittorrent::INFO_HASH].s()));
 }
 
 } // namespace bittorrent

+ 40 - 0
test/MagnetTest.cc

@@ -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

+ 1 - 0
test/Makefile.am

@@ -143,6 +143,7 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\
 	UTMetadataRequestTrackerTest.cc\
 	UTMetadataRequestFactoryTest.cc\
 	UTMetadataPostDownloadHandlerTest.cc\
+	MagnetTest.cc\
 	DefaultBtMessageFactoryTest.cc\
 	DefaultExtensionMessageFactoryTest.cc\
 	DHTNodeTest.cc\

+ 4 - 1
test/Makefile.in

@@ -92,6 +92,7 @@ check_PROGRAMS = $(am__EXEEXT_1)
 @ENABLE_BITTORRENT_TRUE@	UTMetadataRequestTrackerTest.cc\
 @ENABLE_BITTORRENT_TRUE@	UTMetadataRequestFactoryTest.cc\
 @ENABLE_BITTORRENT_TRUE@	UTMetadataPostDownloadHandlerTest.cc\
+@ENABLE_BITTORRENT_TRUE@	MagnetTest.cc\
 @ENABLE_BITTORRENT_TRUE@	DefaultBtMessageFactoryTest.cc\
 @ENABLE_BITTORRENT_TRUE@	DefaultExtensionMessageFactoryTest.cc\
 @ENABLE_BITTORRENT_TRUE@	DHTNodeTest.cc\
@@ -236,7 +237,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
 	UTMetadataRejectExtensionMessageTest.cc \
 	UTMetadataRequestTrackerTest.cc \
 	UTMetadataRequestFactoryTest.cc \
-	UTMetadataPostDownloadHandlerTest.cc \
+	UTMetadataPostDownloadHandlerTest.cc MagnetTest.cc \
 	DefaultBtMessageFactoryTest.cc \
 	DefaultExtensionMessageFactoryTest.cc DHTNodeTest.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@	UTMetadataRequestFactoryTest.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	UTMetadataPostDownloadHandlerTest.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	MagnetTest.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	DefaultBtMessageFactoryTest.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	DefaultExtensionMessageFactoryTest.$(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)/LongestSequencePieceSelectorTest.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)/Metalink2RequestGroupTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntryTest.Po@am__quote@

+ 3 - 3
test/ProtocolDetectorTest.cc

@@ -47,9 +47,9 @@ void ProtocolDetectorTest::testGuessTorrentFile()
 void ProtocolDetectorTest::testGuessTorrentMagnet()
 {
   ProtocolDetector detector;
-  CPPUNIT_ASSERT(detector.guessTorrentMagnet("magnet:?xt=urn:btih:abcdef"));
-  CPPUNIT_ASSERT(detector.guessTorrentMagnet
-		 ("magnet:?dn=name&xt=urn:btih:abcdef"));
+  CPPUNIT_ASSERT
+    (detector.guessTorrentMagnet
+     ("magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"));
   CPPUNIT_ASSERT(!detector.guessTorrentMagnet("magnet:?"));
 }