diff --git a/ChangeLog b/ChangeLog index de70c0d2..863bf9ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2010-02-27 Tatsuhiro Tsujikawa + + Added MessageDigest::isStronger(). Now aria2 selects stronger hash + algorithm in Metalink properly + * src/MetalinkParserController.cc + * src/MetalinkParserController.h + * src/messageDigest.cc + * src/messageDigest.h + * test/MetalinkProcessorTest.cc + * test/metalink4.xml + 2010-02-27 Tatsuhiro Tsujikawa Replaced null or control characters in file path with '_'. For diff --git a/src/MetalinkParserController.cc b/src/MetalinkParserController.cc index f6d5ab81..ca47781f 100644 --- a/src/MetalinkParserController.cc +++ b/src/MetalinkParserController.cc @@ -54,8 +54,6 @@ namespace aria2 { -const std::string MetalinkParserController::SHA1("sha1");// Metalink3Spec - MetalinkParserController::MetalinkParserController(): _metalinker(new Metalinker()) {} @@ -293,10 +291,8 @@ void MetalinkParserController::commitChecksumTransaction() return; } if(_tEntry->checksum.isNull() || - // Metalink3Spec - (_tEntry->checksum->getAlgo() != MetalinkParserController::SHA1 && - // Metalink4Spec - _tEntry->checksum->getAlgo() != MessageDigestContext::SHA1)) { + MessageDigestContext::isStronger(_tChecksum->getAlgo(), + _tEntry->checksum->getAlgo())) { _tEntry->checksum = _tChecksum; } _tChecksum.reset(); @@ -366,7 +362,8 @@ void MetalinkParserController::commitChunkChecksumTransactionV4() return; } if(_tEntry->chunkChecksum.isNull() || - _tEntry->chunkChecksum->getAlgo() != MessageDigestContext::SHA1) { + MessageDigestContext::isStronger(_tChunkChecksumV4->getAlgo(), + _tEntry->chunkChecksum->getAlgo())) { std::deque checksums(_tempChunkChecksumsV4.begin(), _tempChunkChecksumsV4.end()); _tChunkChecksumV4->setChecksums(checksums); @@ -469,11 +466,14 @@ void MetalinkParserController::commitChunkChecksumTransaction() return; } if(_tEntry->chunkChecksum.isNull() || - _tEntry->chunkChecksum->getAlgo() != MetalinkParserController::SHA1) { - std::sort(_tempChunkChecksums.begin(), _tempChunkChecksums.end(), Ascend1st >()); + MessageDigestContext::isStronger(_tChunkChecksum->getAlgo(), + _tEntry->chunkChecksum->getAlgo())) { + std::sort(_tempChunkChecksums.begin(), _tempChunkChecksums.end(), + Ascend1st >()); std::deque checksums; std::transform(_tempChunkChecksums.begin(), _tempChunkChecksums.end(), - std::back_inserter(checksums), select2nd >()); + std::back_inserter(checksums), + select2nd >()); _tChunkChecksum->setChecksums(checksums); _tEntry->chunkChecksum = _tChunkChecksum; } diff --git a/src/MetalinkParserController.h b/src/MetalinkParserController.h index ca2eda09..93df8b8a 100644 --- a/src/MetalinkParserController.h +++ b/src/MetalinkParserController.h @@ -81,8 +81,6 @@ private: #endif // ENABLE_MESSAGE_DIGEST SharedHandle _tSignature; - - static const std::string SHA1; public: MetalinkParserController(); diff --git a/src/messageDigest.cc b/src/messageDigest.cc index fd522edc..ce928a49 100644 --- a/src/messageDigest.cc +++ b/src/messageDigest.cc @@ -34,6 +34,7 @@ /* copyright --> */ #include "messageDigest.h" #include "util.h" +#include "array_fun.h" namespace aria2 { @@ -43,27 +44,55 @@ const std::string MessageDigestContext::SHA256("sha-256"); const std::string MessageDigestContext::MD5("md-5"); -static MessageDigestContext::DigestAlgoMap::value_type digests[] = { +namespace { +struct DigestAlgoEntry { + MessageDigestContext::DigestAlgo algo; + int strength; + DigestAlgoEntry(const MessageDigestContext::DigestAlgo& algo, int strength): + algo(algo), strength(strength) {} +}; +} + +typedef std::map +DigestAlgoMap; + +static const DigestAlgoMap& getDigestAlgos() +{ + enum AlgoStrength { + STRENGTH_MD5 = 0, + STRENGTH_SHA_1 = 1, + STRENGTH_SHA_256 = 2 + }; + static const DigestAlgoMap::value_type digests[] = { #ifdef HAVE_LIBSSL - MessageDigestContext::DigestAlgoMap::value_type("md5", EVP_md5()), - MessageDigestContext::DigestAlgoMap::value_type("sha-1", EVP_sha1()), - MessageDigestContext::DigestAlgoMap::value_type("sha1", EVP_sha1()), + DigestAlgoMap::value_type("md5", DigestAlgoEntry(EVP_md5(), STRENGTH_MD5)), + DigestAlgoMap::value_type + ("sha-1", DigestAlgoEntry(EVP_sha1(), STRENGTH_SHA_1)), + DigestAlgoMap::value_type + ("sha1", DigestAlgoEntry(EVP_sha1(), STRENGTH_SHA_1)), # ifdef HAVE_EVP_SHA256 - MessageDigestContext::DigestAlgoMap::value_type("sha-256", EVP_sha256()), - MessageDigestContext::DigestAlgoMap::value_type("sha256", EVP_sha256()), + DigestAlgoMap::value_type + ("sha-256", DigestAlgoEntry(EVP_sha256(), STRENGTH_SHA_256)), + DigestAlgoMap::value_type + ("sha256", DigestAlgoEntry(EVP_sha256(), STRENGTH_SHA_256)), # endif // HAVE_EVP_SHA256 #elif HAVE_LIBGCRYPT - MessageDigestContext::DigestAlgoMap::value_type("md5", GCRY_MD_MD5), - MessageDigestContext::DigestAlgoMap::value_type("sha-1", GCRY_MD_SHA1), - MessageDigestContext::DigestAlgoMap::value_type("sha1", GCRY_MD_SHA1), - MessageDigestContext::DigestAlgoMap::value_type("sha-256", GCRY_MD_SHA256), - MessageDigestContext::DigestAlgoMap::value_type("sha256", GCRY_MD_SHA256), + DigestAlgoMap::value_type + ("md5", DigestAlgoEntry(GCRY_MD_MD5, STRENGTH_MD5)), + DigestAlgoMap::value_type + ("sha-1", DigestAlgoEntry(GCRY_MD_SHA1, STRENGTH_SHA_1)), + DigestAlgoMap::value_type + ("sha1", DigestAlgoEntry(GCRY_MD_SHA1, STRENGTH_SHA_1)), + DigestAlgoMap::value_type + ("sha-256", DigestAlgoEntry(GCRY_MD_SHA256, STRENGTH_SHA_256)), + DigestAlgoMap::value_type + ("sha256", DigestAlgoEntry(GCRY_MD_SHA256, STRENGTH_SHA_256)), #endif // HAVE_LIBGCRYPT -}; - -MessageDigestContext::DigestAlgoMap -MessageDigestContext::digestAlgos(&digests[0], - &digests[sizeof(digests)/sizeof(DigestAlgoMap::value_type)]); + }; + static const DigestAlgoMap algomap + (&digests[0], &digests[arrayLength(digests)]); + return algomap; +} std::string MessageDigestContext::digestFinal() { @@ -75,15 +104,52 @@ std::string MessageDigestContext::digestFinal() return rawMDString; } +bool MessageDigestContext::supports(const std::string& algostring) +{ + const DigestAlgoMap& allAlgos = getDigestAlgos(); + DigestAlgoMap::const_iterator itr = allAlgos.find(algostring); + if(itr == allAlgos.end()) { + return false; + } else { + return true; + } +} + +MessageDigestContext::DigestAlgo +MessageDigestContext::getDigestAlgo(const std::string& algostring) +{ + const DigestAlgoMap& allAlgos = getDigestAlgos(); + DigestAlgoMap::const_iterator itr = allAlgos.find(algostring); + if(itr == allAlgos.end()) { + throw DL_ABORT_EX + (StringFormat("Digest algorithm %s is not supported.", + algostring.c_str()).str()); + } + return (*itr).second.algo; +} + std::string MessageDigestContext::getSupportedAlgoString() { + const DigestAlgoMap& allAlgos = getDigestAlgos(); std::string algos; - for(DigestAlgoMap::const_iterator itr = digestAlgos.begin(); - itr != digestAlgos.end(); ++itr) { + for(DigestAlgoMap::const_iterator itr = allAlgos.begin(); + itr != allAlgos.end(); ++itr) { algos += (*itr).first; algos += ", "; } return util::trim(algos, ", "); } +bool MessageDigestContext::isStronger +(const std::string& lhs, const std::string& rhs) +{ + const DigestAlgoMap& allAlgos = getDigestAlgos(); + DigestAlgoMap::const_iterator lhsitr = allAlgos.find(lhs); + DigestAlgoMap::const_iterator rhsitr = allAlgos.find(rhs); + if(lhsitr == allAlgos.end() || rhsitr == allAlgos.end()) { + return false; + } + return (*lhsitr).second.strength > (*rhsitr).second.strength; +} + } // namespace aria2 diff --git a/src/messageDigest.h b/src/messageDigest.h index 3ff6ca69..789b3a03 100644 --- a/src/messageDigest.h +++ b/src/messageDigest.h @@ -62,7 +62,6 @@ public: #ifdef HAVE_LIBGCRYPT typedef int DigestAlgo; #endif // HAVE_LIBGCRYPT - typedef std::map DigestAlgoMap; static const std::string SHA1; @@ -77,8 +76,6 @@ private: gcry_md_hd_t ctx; #endif // HAVE_LIBGCRYPT DigestAlgo algo; - - static DigestAlgoMap digestAlgos; public: MessageDigestContext():algo(getDigestAlgo(MessageDigestContext::SHA1)) {} @@ -93,26 +90,9 @@ public: algo = getDigestAlgo(algostring); } - static bool supports(const std::string& algostring) - { - DigestAlgoMap::const_iterator itr = digestAlgos.find(algostring); - if(itr == digestAlgos.end()) { - return false; - } else { - return true; - } - } + static bool supports(const std::string& algostring); - static DigestAlgo getDigestAlgo(const std::string& algostring) - { - DigestAlgoMap::const_iterator itr = digestAlgos.find(algostring); - if(itr == digestAlgos.end()) { - throw DL_ABORT_EX - (StringFormat("Digest algorithm %s is not supported.", - algostring.c_str()).str()); - } - return (*itr).second; - } + static DigestAlgo getDigestAlgo(const std::string& algostring); static std::string getSupportedAlgoString(); @@ -121,6 +101,11 @@ public: return digestLength(getDigestAlgo(algostring)); } + // Returns true if hash algorithm specified by lhs is stronger than + // the one specified by rhs. If either lhs or rhs is not supported + // or both are not supported, returns false. + static bool isStronger(const std::string& lhs, const std::string& rhs); + std::string digestFinal(); #if defined(HAVE_OLD_LIBSSL) diff --git a/test/MetalinkProcessorTest.cc b/test/MetalinkProcessorTest.cc index 985361cc..9821bc80 100644 --- a/test/MetalinkProcessorTest.cc +++ b/test/MetalinkProcessorTest.cc @@ -96,7 +96,7 @@ void MetalinkProcessorTest::testParseFileV4() CPPUNIT_ASSERT(!e->checksum.isNull()); CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), e->checksum->getAlgo()); CPPUNIT_ASSERT(!e->chunkChecksum.isNull()); - CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), e->chunkChecksum->getAlgo()); + CPPUNIT_ASSERT_EQUAL(std::string("sha-256"), e->chunkChecksum->getAlgo()); CPPUNIT_ASSERT_EQUAL((size_t)262144, e->chunkChecksum->getChecksumLength()); CPPUNIT_ASSERT_EQUAL((size_t)3, e->chunkChecksum->countChecksum()); CPPUNIT_ASSERT_EQUAL(std::string("metalinkhash1"), diff --git a/test/metalink4.xml b/test/metalink4.xml index f44521f6..aa4c6609 100644 --- a/test/metalink4.xml +++ b/test/metalink4.xml @@ -7,12 +7,18 @@ 1.0 en A description of the example file for download. + 80bc95fd391772fa61c91ed68567f0980bb45fd9 80bc95fd391772fa61c91ed68567f0980bb45fd9 metalinkhash1 metalinkhash2 metalinkhash3 + + metalinkhash1 + metalinkhash2 + metalinkhash3 + ftp://ftp.example.com/example.ext http://example.com/example.ext http://example.com/example.ext.torrent