diff --git a/ChangeLog b/ChangeLog index d4c9dd88..e4388aa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,69 @@ +2010-06-18 Tatsuhiro Tsujikawa + + Introduced ValueBase class, which is a replacement of BDE. In + this change ValueBase is used instead of BDE except DHT messages, + UTMetadata messages and XML-RPC. They'll be replaced in the later + commits. DownloadContext::_attrs is now ContextAttribute rather + than BDE. + * src/ActivePeerConnectionCommand.cc + * src/AnnounceList.cc + * src/AnnounceList.h + * src/BtDependency.cc + * src/BtRegistry.cc + * src/BtSetup.cc + * src/ConsoleStatCalc.cc + * src/ContextAttribute.h + * src/DefaultBtAnnounce.cc + * src/DefaultBtInteractive.cc + * src/DownloadContext.cc + * src/DownloadContext.h + * src/HandshakeExtensionMessage.cc + * src/InitiateConnectionCommand.cc + * src/LpdReceiveMessageCommand.cc + * src/MSEHandshake.cc + * src/Makefile.am + * src/Makefile.in + * src/PeerInteractionCommand.cc + * src/PeerListProcessor.h + * src/ProtocolDetector.cc + * src/RequestGroup.cc + * src/RequestGroupMan.cc + * src/TorrentAttribute.h + * src/TrackerWatcherCommand.cc + * src/UTMetadataDataExtensionMessage.cc + * src/UTMetadataPostDownloadHandler.cc + * src/UTMetadataRequestExtensionMessage.cc + * src/ValueBase.cc + * src/ValueBase.h + * src/XmlRpcMethodImpl.cc + * src/XmlRpcMethodImpl.h + * src/bencode2.cc + * src/bencode2.h + * src/bittorrent_helper.cc + * src/bittorrent_helper.h + * src/download_helper.cc + * src/magnet.cc + * src/magnet.h + * test/AnnounceListTest.cc + * test/Bencode2Test.cc + * test/BencodeTest.cc + * test/BittorrentHelperTest.cc + * test/BtDependencyTest.cc + * test/BtRegistryTest.cc + * test/DefaultBtAnnounceTest.cc + * test/DefaultBtProgressInfoFileTest.cc + * test/HandshakeExtensionMessageTest.cc + * test/MSEHandshakeTest.cc + * test/MagnetTest.cc + * test/Makefile.am + * test/Makefile.in + * test/RequestGroupManTest.cc + * test/UTMetadataDataExtensionMessageTest.cc + * test/UTMetadataPostDownloadHandlerTest.cc + * test/UTMetadataRequestExtensionMessageTest.cc + * test/ValueBaseTest.cc + * test/XmlRpcMethodTest.cc + 2010-06-15 Tatsuhiro Tsujikawa Fixed assertion error if updateTransferStatFor is called with peer diff --git a/src/ActivePeerConnectionCommand.cc b/src/ActivePeerConnectionCommand.cc index 7d17b447..f7bfc79b 100644 --- a/src/ActivePeerConnectionCommand.cc +++ b/src/ActivePeerConnectionCommand.cc @@ -89,8 +89,8 @@ bool ActivePeerConnectionCommand::execute() { _requestGroup->getMaxDownloadSpeedLimit(); const unsigned int maxUploadLimit = _requestGroup->getMaxUploadSpeedLimit(); unsigned int thresholdSpeed; - if(_requestGroup->getDownloadContext()-> - getAttribute(bittorrent::BITTORRENT).containsKey(bittorrent::METADATA)) { + if(!bittorrent::getTorrentAttrs + (_requestGroup->getDownloadContext())->metadata.empty()) { thresholdSpeed = _requestGroup->getOption()->getAsInt(PREF_BT_REQUEST_PEER_SPEED_LIMIT); } else { diff --git a/src/AnnounceList.cc b/src/AnnounceList.cc index d417a08a..c3ea52be 100644 --- a/src/AnnounceList.cc +++ b/src/AnnounceList.cc @@ -49,7 +49,8 @@ const std::string AnnounceList::STOPPED("stopped"); const std::string AnnounceList::COMPLETED("completed"); -AnnounceList::AnnounceList(const BDE& announceList): +AnnounceList::AnnounceList +(const std::vector >& announceList): _currentTrackerInitialized(false) { reconfigure(announceList); } @@ -60,30 +61,19 @@ AnnounceList::AnnounceList resetIterator(); } -void AnnounceList::reconfigure(const BDE& announceList) +void AnnounceList::reconfigure +(const std::vector >& announceList) { - if(announceList.isList()) { - for(BDE::List::const_iterator itr = announceList.listBegin(), - eoi = announceList.listEnd(); itr != eoi; ++itr) { - const BDE& elemList = *itr; - if(!elemList.isList()) { - continue; - } - std::deque urls; - for(BDE::List::const_iterator elemItr = elemList.listBegin(), - eoi2 = elemList.listEnd(); elemItr != eoi2; ++elemItr) { - const BDE& data = *elemItr; - if(data.isString()) { - urls.push_back(data.s()); - } - } - if(!urls.empty()) { - SharedHandle tier(new AnnounceTier(urls)); - _tiers.push_back(tier); - } + for(std::vector >::const_iterator itr = + announceList.begin(), eoi = announceList.end(); itr != eoi; ++itr) { + if((*itr).empty()) { + continue; } - resetIterator(); + std::deque urls((*itr).begin(), (*itr).end()); + SharedHandle tier(new AnnounceTier(urls)); + _tiers.push_back(tier); } + resetIterator(); } void AnnounceList::reconfigure(const std::string& url) { diff --git a/src/AnnounceList.h b/src/AnnounceList.h index 0349b580..394475c9 100644 --- a/src/AnnounceList.h +++ b/src/AnnounceList.h @@ -38,11 +38,10 @@ #include "common.h" #include "SharedHandle.h" #include "AnnounceTier.h" +#include "ValueBase.h" namespace aria2 { -class BDE; - class AnnounceList { public: private: @@ -56,10 +55,10 @@ private: (const std::deque >::iterator& itr); public: AnnounceList():_currentTrackerInitialized(false) {} - AnnounceList(const BDE& announceList); + AnnounceList(const std::vector >& announceList); AnnounceList(const std::deque >& tiers); - void reconfigure(const BDE& announceList); + void reconfigure(const std::vector >& announceList); void reconfigure(const std::string& url); size_t countTier() const { diff --git a/src/BtDependency.cc b/src/BtDependency.cc index 643b346d..54ac6125 100644 --- a/src/BtDependency.cc +++ b/src/BtDependency.cc @@ -85,8 +85,8 @@ bool BtDependency::resolve() diskAdaptor->openExistingFile(); std::string content = util::toString(diskAdaptor); if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) { - const BDE& attrs = - dependee->getDownloadContext()->getAttribute(bittorrent::BITTORRENT); + SharedHandle attrs = + bittorrent::getTorrentAttrs(dependee->getDownloadContext()); bittorrent::loadFromMemory (bittorrent::metadata2Torrent(content, attrs), context, "default"); } else { diff --git a/src/BtRegistry.cc b/src/BtRegistry.cc index 05838bdf..debfb0b1 100644 --- a/src/BtRegistry.cc +++ b/src/BtRegistry.cc @@ -56,13 +56,12 @@ BtRegistry::getDownloadContext(const std::string& infoHash) const SharedHandle dctx; for(std::map::const_iterator i = _pool.begin(), eoi = _pool.end(); i != eoi; ++i) { - const BDE& attrs = - (*i).second._downloadContext->getAttribute(bittorrent::BITTORRENT); - if(attrs[bittorrent::INFO_HASH].s() == infoHash) { + if(bittorrent::getTorrentAttrs((*i).second._downloadContext)->infoHash == + infoHash) { dctx = (*i).second._downloadContext; break; } - } + } return dctx; } diff --git a/src/BtSetup.cc b/src/BtSetup.cc index 3da46902..d3e0115f 100644 --- a/src/BtSetup.cc +++ b/src/BtSetup.cc @@ -73,6 +73,7 @@ #include "FileAllocationEntry.h" #include "CheckIntegrityEntry.h" #include "ServerStatMan.h" +#include "DlAbortEx.h" namespace aria2 { @@ -86,9 +87,9 @@ void BtSetup::setup(std::vector& commands, if(!requestGroup->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)){ return; } - const BDE& torrentAttrs = - requestGroup->getDownloadContext()->getAttribute(bittorrent::BITTORRENT); - bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA); + SharedHandle torrentAttrs = + bittorrent::getTorrentAttrs(requestGroup->getDownloadContext()); + bool metadataGetMode = torrentAttrs->metadata.empty(); BtObject btObject = e->getBtRegistry()->get(requestGroup->getGID()); SharedHandle pieceStorage = btObject._pieceStorage; SharedHandle peerStorage = btObject._peerStorage; @@ -125,7 +126,7 @@ void BtSetup::setup(std::vector& commands, commands.push_back(c); } - if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) && + if((metadataGetMode || !torrentAttrs->privateTorrent) && DHTSetup::initialized()) { DHTGetPeersCommand* command = new DHTGetPeersCommand(e->newCUID(), requestGroup, e); @@ -179,7 +180,7 @@ void BtSetup::setup(std::vector& commands, btRuntime->setListenPort(listenCommand->getPort()); } if(option->getAsBool(PREF_BT_ENABLE_LPD) && - (metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0)) { + (metadataGetMode || !torrentAttrs->privateTorrent)) { if(LpdReceiveMessageCommand::getNumInstance() == 0) { _logger->info("Initializing LpdMessageReceiver."); SharedHandle receiver diff --git a/src/ConsoleStatCalc.cc b/src/ConsoleStatCalc.cc index 53dc0560..29c55c40 100644 --- a/src/ConsoleStatCalc.cc +++ b/src/ConsoleStatCalc.cc @@ -89,8 +89,7 @@ static void printProgress #ifdef ENABLE_BITTORRENT if(rg->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT) && - rg->getDownloadContext()->getAttribute(bittorrent::BITTORRENT) - .containsKey(bittorrent::METADATA) && + !bittorrent::getTorrentAttrs(rg->getDownloadContext())->metadata.empty() && rg->downloadFinished()) { o << "SEEDING" << "(" << "ratio:"; if(rg->getCompletedLength() > 0) { diff --git a/src/ContextAttribute.h b/src/ContextAttribute.h new file mode 100644 index 00000000..9ca25b8d --- /dev/null +++ b/src/ContextAttribute.h @@ -0,0 +1,44 @@ +/* */ +#ifndef D_CONTEXT_ATTRIBUTE_H +#define D_CONTEXT_ATTRIBUTE_H + +#include "common.h" + +struct ContextAttribute { + virtual ~ContextAttribute() {} +}; + +#endif // D_CONTEXT_ATTRIBUTE_H diff --git a/src/DefaultBtAnnounce.cc b/src/DefaultBtAnnounce.cc index 2a59f769..416bb0c7 100644 --- a/src/DefaultBtAnnounce.cc +++ b/src/DefaultBtAnnounce.cc @@ -50,7 +50,7 @@ #include "StringFormat.h" #include "A2STR.h" #include "Request.h" -#include "bencode.h" +#include "bencode2.h" #include "bittorrent_helper.h" #include "wallclock.h" @@ -67,9 +67,7 @@ DefaultBtAnnounce::DefaultBtAnnounce _userDefinedInterval(0), _complete(0), _incomplete(0), - _announceList - (downloadContext->getAttribute - (bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST]), + _announceList(bittorrent::getTorrentAttrs(downloadContext)->announceList), _option(option), _logger(LogFactory::getInstance()), _randomizer(SimpleRandomizer::getInstance()) @@ -219,37 +217,38 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse, if(_logger->debug()) { _logger->debug("Now processing tracker response."); } - const BDE dict = - bencode::decode(trackerResponse, trackerResponseLength); - if(!dict.isDict()) { + SharedHandle decodedValue = + bencode2::decode(trackerResponse, trackerResponseLength); + const Dict* dict = asDict(decodedValue); + if(!dict) { throw DL_ABORT_EX(MSG_NULL_TRACKER_RESPONSE); } - const BDE& failure = dict[BtAnnounce::FAILURE_REASON]; - if(failure.isString()) { + const String* failure = asString(dict->get(BtAnnounce::FAILURE_REASON)); + if(failure) { throw DL_ABORT_EX - (StringFormat(EX_TRACKER_FAILURE, failure.s().c_str()).str()); + (StringFormat(EX_TRACKER_FAILURE, failure->s().c_str()).str()); } - const BDE& warn = dict[BtAnnounce::WARNING_MESSAGE]; - if(warn.isString()) { - _logger->warn(MSG_TRACKER_WARNING_MESSAGE, warn.s().c_str()); + const String* warn = asString(dict->get(BtAnnounce::WARNING_MESSAGE)); + if(warn) { + _logger->warn(MSG_TRACKER_WARNING_MESSAGE, warn->s().c_str()); } - const BDE& tid = dict[BtAnnounce::TRACKER_ID]; - if(tid.isString()) { - _trackerId = tid.s(); + const String* tid = asString(dict->get(BtAnnounce::TRACKER_ID)); + if(tid) { + _trackerId = tid->s(); if(_logger->debug()) { _logger->debug("Tracker ID:%s", _trackerId.c_str()); } } - const BDE& ival = dict[BtAnnounce::INTERVAL]; - if(ival.isInteger() && ival.i() > 0) { - _interval = ival.i(); + const Integer* ival = asInteger(dict->get(BtAnnounce::INTERVAL)); + if(ival && ival->i() > 0) { + _interval = ival->i(); if(_logger->debug()) { _logger->debug("Interval:%d", _interval); } } - const BDE& mival = dict[BtAnnounce::MIN_INTERVAL]; - if(mival.isInteger() && mival.i() > 0) { - _minInterval = mival.i(); + const Integer* mival = asInteger(dict->get(BtAnnounce::MIN_INTERVAL)); + if(mival && mival->i() > 0) { + _minInterval = mival->i(); if(_logger->debug()) { _logger->debug("Min interval:%d", _minInterval); } @@ -258,22 +257,22 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse, // Use interval as a minInterval if minInterval is not supplied. _minInterval = _interval; } - const BDE& comp = dict[BtAnnounce::COMPLETE]; - if(comp.isInteger()) { - _complete = comp.i(); + const Integer* comp = asInteger(dict->get(BtAnnounce::COMPLETE)); + if(comp) { + _complete = comp->i(); if(_logger->debug()) { _logger->debug("Complete:%d", _complete); } } - const BDE& incomp = dict[BtAnnounce::INCOMPLETE]; - if(incomp.isInteger()) { - _incomplete = incomp.i(); + const Integer* incomp = asInteger(dict->get(BtAnnounce::INCOMPLETE)); + if(incomp) { + _incomplete = incomp->i(); if(_logger->debug()) { _logger->debug("Incomplete:%d", _incomplete); } } - const BDE& peerData = dict[BtAnnounce::PEERS]; - if(peerData.isNone()) { + const SharedHandle& peerData = dict->get(BtAnnounce::PEERS); + if(peerData.isNull()) { _logger->info(MSG_NO_PEER_LIST_RECEIVED); } else { if(!_btRuntime->isHalt() && _btRuntime->lessThanMinPeers()) { diff --git a/src/DefaultBtInteractive.cc b/src/DefaultBtInteractive.cc index 6d21813b..8589ae63 100644 --- a/src/DefaultBtInteractive.cc +++ b/src/DefaultBtInteractive.cc @@ -202,9 +202,10 @@ void DefaultBtInteractive::addHandshakeExtendedMessageToQueue() m->setClientVersion(CLIENT_ARIA2); m->setTCPPort(_btRuntime->getListenPort()); m->setExtensions(_extensionMessageRegistry->getExtensions()); - const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT); - if(attrs.containsKey(bittorrent::METADATA)) { - m->setMetadataSize(attrs[bittorrent::METADATA_SIZE].i()); + SharedHandle attrs = + bittorrent::getTorrentAttrs(_downloadContext); + if(!attrs->metadata.empty()) { + m->setMetadataSize(attrs->metadataSize); } SharedHandle msg = _messageFactory->createBtExtendedMessage(m); _dispatcher->addMessageToQueue(msg); diff --git a/src/DownloadContext.cc b/src/DownloadContext.cc index 4a3dae52..30afcf18 100644 --- a/src/DownloadContext.cc +++ b/src/DownloadContext.cc @@ -40,6 +40,7 @@ #include "StringFormat.h" #include "util.h" #include "wallclock.h" +#include "DlAbortEx.h" namespace aria2 { @@ -138,36 +139,33 @@ void DownloadContext::setFileFilter(IntSequence seq) } } -void DownloadContext::ensureAttrs() +void DownloadContext::setAttribute +(const std::string& key, const SharedHandle& value) { - if(_attrs.isNone()) { - _attrs = BDE::dict(); + std::map >::value_type p = + std::make_pair(key, value); + std::pair >::iterator, + bool> r = _attrs.insert(p); + if(!r.second) { + (*r.first).second = value; } } -void DownloadContext::setAttribute(const std::string& key, const BDE& value) +const SharedHandle& DownloadContext::getAttribute +(const std::string& key) { - ensureAttrs(); - _attrs[key] = value; -} - -BDE& DownloadContext::getAttribute(const std::string& key) -{ - ensureAttrs(); - if(_attrs.containsKey(key)) { - return _attrs[key]; - } else { + std::map >::const_iterator itr = + _attrs.find(key); + if(itr == _attrs.end()) { throw DL_ABORT_EX(StringFormat("No attribute named %s", key.c_str()).str()); + } else { + return (*itr).second; } } bool DownloadContext::hasAttribute(const std::string& key) const { - if(_attrs.isNone()) { - return false; - } else { - return _attrs.containsKey(key); - } + return _attrs.count(key) == 1; } void DownloadContext::releaseRuntimeResource() diff --git a/src/DownloadContext.h b/src/DownloadContext.h index 563a601d..e94efd93 100644 --- a/src/DownloadContext.h +++ b/src/DownloadContext.h @@ -45,9 +45,10 @@ #include "Signature.h" #include "TimerA2.h" #include "A2STR.h" -#include "BDE.h" +#include "ValueBase.h" #include "IntSequence.h" #include "FileEntry.h" +#include "TorrentAttribute.h" namespace aria2 { @@ -76,15 +77,13 @@ private: RequestGroup* _ownerRequestGroup; - BDE _attrs; + std::map > _attrs; Timer _downloadStartTime; Timer _downloadStopTime; SharedHandle _signature; - - void ensureAttrs(); public: DownloadContext(); @@ -224,9 +223,10 @@ public: // this function. void setFilePathWithIndex(size_t index, const std::string& path); - void setAttribute(const std::string& key, const BDE& value); + void setAttribute + (const std::string& key, const SharedHandle& value); - BDE& getAttribute(const std::string& key); + const SharedHandle& getAttribute(const std::string& key); bool hasAttribute(const std::string& key) const; diff --git a/src/HandshakeExtensionMessage.cc b/src/HandshakeExtensionMessage.cc index 00763c65..20a3e2fb 100644 --- a/src/HandshakeExtensionMessage.cc +++ b/src/HandshakeExtensionMessage.cc @@ -110,21 +110,21 @@ void HandshakeExtensionMessage::doReceivedAction() const std::map::value_type& vt = *itr; _peer->setExtension(vt.first, vt.second); } - BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); - if(!attrs.containsKey(bittorrent::METADATA) && - !_peer->getExtensionMessageID("ut_metadata")) { + SharedHandle attrs = + bittorrent::getTorrentAttrs(_dctx); + if(attrs->metadata.empty() && !_peer->getExtensionMessageID("ut_metadata")) { // TODO In metadataGetMode, if peer don't support metadata // transfer, should we drop connection? There is a possibility // that peer can still tell us peers using PEX. throw DL_ABORT_EX("Peer doesn't support ut_metadata extension. Goodbye."); } if(_metadataSize > 0) { - if(attrs.containsKey(bittorrent::METADATA_SIZE)) { - if(_metadataSize != (size_t)attrs[bittorrent::METADATA_SIZE].i()) { + if(attrs->metadataSize) { + if(_metadataSize != attrs->metadataSize) { throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?"); } } else { - attrs[bittorrent::METADATA_SIZE] = _metadataSize; + attrs->metadataSize = _metadataSize; _dctx->getFirstFileEntry()->setLength(_metadataSize); _dctx->markTotalLengthIsKnown(); _dctx->getOwnerRequestGroup()->initPieceStorage(); @@ -133,7 +133,7 @@ void HandshakeExtensionMessage::doReceivedAction() _dctx->getOwnerRequestGroup()->getPieceStorage(); pieceStorage->setEndGamePieceNum(0); } - } else if(!attrs.containsKey(bittorrent::METADATA)) { + } else if(attrs->metadata.empty()) { throw DL_ABORT_EX("Peer didn't provide metadata_size." " It seems that it doesn't have whole metadata."); } diff --git a/src/InitiateConnectionCommand.cc b/src/InitiateConnectionCommand.cc index 8b57e18e..53454e56 100644 --- a/src/InitiateConnectionCommand.cc +++ b/src/InitiateConnectionCommand.cc @@ -52,6 +52,7 @@ #include "ServerStatMan.h" #include "FileAllocationEntry.h" #include "CheckIntegrityEntry.h" +#include "RecoverableException.h" namespace aria2 { diff --git a/src/LpdReceiveMessageCommand.cc b/src/LpdReceiveMessageCommand.cc index 7f106803..2208b41e 100644 --- a/src/LpdReceiveMessageCommand.cc +++ b/src/LpdReceiveMessageCommand.cc @@ -100,15 +100,12 @@ bool LpdReceiveMessageCommand::execute() } continue; } - const BDE& torrentAttrs = dctx->getAttribute(bittorrent::BITTORRENT); - if(torrentAttrs.containsKey(bittorrent::PRIVATE)) { - if(torrentAttrs[bittorrent::PRIVATE].i() == 1) { - if(getLogger()->debug()) { - getLogger()->debug - ("Ignore LPD message because the torrent is private."); - } - continue; + if(bittorrent::getTorrentAttrs(dctx)->privateTorrent) { + if(getLogger()->debug()) { + getLogger()->debug + ("Ignore LPD message because the torrent is private."); } + continue; } RequestGroup* group = dctx->getOwnerRequestGroup(); assert(group); diff --git a/src/MSEHandshake.cc b/src/MSEHandshake.cc index 704fc816..20706cd0 100644 --- a/src/MSEHandshake.cc +++ b/src/MSEHandshake.cc @@ -476,14 +476,13 @@ bool MSEHandshake::receiveReceiverHashAndPadCLength downloadContexts.begin(), eoi = downloadContexts.end(); i != eoi; ++i) { unsigned char md[20]; - const BDE& torrentAttrs = (*i)->getAttribute(bittorrent::BITTORRENT); - createReq23Hash(md, torrentAttrs[bittorrent::INFO_HASH].uc()); + const unsigned char* infohash = bittorrent::getInfoHash(*i); + createReq23Hash(md, infohash); if(memcmp(md, rbufptr, sizeof(md)) == 0) { if(_logger->debug()) { _logger->debug("CUID#%s - info hash found: %s", util::itos(_cuid).c_str(), - util::toHex - (torrentAttrs[bittorrent::INFO_HASH].s()).c_str()); + util::toHex(infohash, INFO_HASH_LENGTH).c_str()); } downloadContext = *i; break; diff --git a/src/Makefile.am b/src/Makefile.am index 193838e5..485b604b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -202,7 +202,11 @@ SRCS = Socket.h\ MetadataInfo.cc MetadataInfo.h\ SessionSerializer.cc SessionSerializer.h\ Event.h\ - timespec.h + timespec.h\ + ValueBase.cc ValueBase.h\ + bencode2.cc bencode2.h\ + ContextAttribute.h\ + TorrentAttribute.h if ENABLE_XML_RPC SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\ diff --git a/src/Makefile.in b/src/Makefile.in index 8764c069..8f5b23a3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -437,7 +437,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ CreateRequestCommand.h DownloadResultCode.h wallclock.h \ download_helper.cc download_helper.h MetadataInfo.cc \ MetadataInfo.h SessionSerializer.cc SessionSerializer.h \ - Event.h timespec.h XmlRpcRequestParserController.cc \ + Event.h timespec.h ValueBase.cc ValueBase.h bencode2.cc \ + bencode2.h ContextAttribute.h TorrentAttribute.h \ + XmlRpcRequestParserController.cc \ XmlRpcRequestParserController.h \ XmlRpcRequestParserStateMachine.cc \ XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \ @@ -873,7 +875,8 @@ am__objects_32 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ LongestSequencePieceSelector.$(OBJEXT) bitfield.$(OBJEXT) \ BDE.$(OBJEXT) CreateRequestCommand.$(OBJEXT) \ download_helper.$(OBJEXT) MetadataInfo.$(OBJEXT) \ - SessionSerializer.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + SessionSerializer.$(OBJEXT) ValueBase.$(OBJEXT) \ + bencode2.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) $(am__objects_7) $(am__objects_8) \ $(am__objects_9) $(am__objects_10) $(am__objects_11) \ @@ -1213,17 +1216,19 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \ CreateRequestCommand.h DownloadResultCode.h wallclock.h \ download_helper.cc download_helper.h MetadataInfo.cc \ MetadataInfo.h SessionSerializer.cc SessionSerializer.h \ - Event.h timespec.h $(am__append_1) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_5) \ - $(am__append_6) $(am__append_7) $(am__append_8) \ - $(am__append_9) $(am__append_10) $(am__append_11) \ - $(am__append_12) $(am__append_13) $(am__append_14) \ - $(am__append_15) $(am__append_16) $(am__append_17) \ - $(am__append_18) $(am__append_19) $(am__append_20) \ - $(am__append_21) $(am__append_22) $(am__append_23) \ - $(am__append_24) $(am__append_25) $(am__append_26) \ - $(am__append_27) $(am__append_28) $(am__append_29) \ - $(am__append_30) $(am__append_31) + Event.h timespec.h ValueBase.cc ValueBase.h bencode2.cc \ + bencode2.h ContextAttribute.h TorrentAttribute.h \ + $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) $(am__append_6) \ + $(am__append_7) $(am__append_8) $(am__append_9) \ + $(am__append_10) $(am__append_11) $(am__append_12) \ + $(am__append_13) $(am__append_14) $(am__append_15) \ + $(am__append_16) $(am__append_17) $(am__append_18) \ + $(am__append_19) $(am__append_20) $(am__append_21) \ + $(am__append_22) $(am__append_23) $(am__append_24) \ + $(am__append_25) $(am__append_26) $(am__append_27) \ + $(am__append_28) $(am__append_29) $(am__append_30) \ + $(am__append_31) noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ @@ -1612,6 +1617,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ValueBase.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2XmlRpcRequestProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcElements.Po@am__quote@ @@ -1626,6 +1632,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asctime_r.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitfield.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittorrent_helper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_gettime_mingw.Po@am__quote@ diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index ffbe74f5..8fa666f6 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -102,11 +102,9 @@ PeerInteractionCommand::PeerInteractionCommand setWriteCheckSocket(getSocket()); setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)); } - - const BDE& torrentAttrs = - _requestGroup->getDownloadContext()->getAttribute(bittorrent::BITTORRENT); - - bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA); + SharedHandle torrentAttrs = + bittorrent::getTorrentAttrs(_requestGroup->getDownloadContext()); + bool metadataGetMode = torrentAttrs->metadata.empty(); SharedHandle exMsgRegistry (new ExtensionMessageRegistry()); @@ -189,7 +187,7 @@ PeerInteractionCommand::PeerInteractionCommand (getOption()->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL)); btInteractive->setRequestGroupMan(getDownloadEngine()->getRequestGroupMan()); btInteractive->setBtMessageFactory(factory); - if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) && + if((metadataGetMode || !torrentAttrs->privateTorrent) && !getPeer()->isLocalPeer()) { if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) { btInteractive->setUTPexEnabled(true); diff --git a/src/PeerListProcessor.h b/src/PeerListProcessor.h index 9aff5b88..6210fcf7 100644 --- a/src/PeerListProcessor.h +++ b/src/PeerListProcessor.h @@ -42,11 +42,70 @@ #include "a2netcompat.h" #include "bencode.h" #include "Peer.h" +#include "ValueBase.h" namespace aria2 { class PeerListProcessor { +private: + template + class PeerListValueBaseVisitor:public ValueBaseVisitor { + OutputIterator dest_; + public: + PeerListValueBaseVisitor(OutputIterator dest):dest_(dest) {} + + virtual void visit(const String& peerData) + { + size_t length = peerData.s().size(); + if(length%6 == 0) { + const char* base = peerData.s().data(); + for(size_t i = 0; i < length; i += 6) { + struct in_addr in; + memcpy(&in.s_addr, base+i, sizeof(uint32_t)); + std::string ipaddr = inet_ntoa(in); + uint16_t port_nworder; + memcpy(&port_nworder, base+i+4, sizeof(uint16_t)); + uint16_t port = ntohs(port_nworder); + *dest_ = SharedHandle(new Peer(ipaddr, port)); + ++dest_; + } + } + } + + virtual void visit(const Integer& v) {} + + virtual void visit(const List& peerData) + { + for(List::ValueType::const_iterator itr = peerData.begin(), + eoi = peerData.end(); itr != eoi; ++itr) { + const Dict* peerDict = asDict(*itr); + if(!peerDict) { + continue; + } + static const std::string IP = "ip"; + static const std::string PORT = "port"; + const String* ip = asString(peerDict->get(IP)); + const Integer* port = asInteger(peerDict->get(PORT)); + if(!ip || !port || !(0 < port->i() && port->i() < 65536)) { + continue; + } + *dest_ = SharedHandle(new Peer(ip->s(), port->i())); + ++dest_; + } + } + + virtual void visit(const Dict& v) {} + }; public: + template + void extractPeer(const SharedHandle& peerData, OutputIterator dest) + { + if(!peerData.isNull()) { + PeerListValueBaseVisitor visitor(dest); + peerData->accept(visitor); + } + } + template void extractPeer(const BDE& peerData, OutputIterator dest) { diff --git a/src/ProtocolDetector.cc b/src/ProtocolDetector.cc index 99c71161..c90cc1ac 100644 --- a/src/ProtocolDetector.cc +++ b/src/ProtocolDetector.cc @@ -41,6 +41,7 @@ #include "Request.h" #include "File.h" #include "util.h" +#include "RecoverableException.h" #ifdef ENABLE_BITTORRENT # include "bittorrent_helper.h" #endif // ENABLE_BITTORRENT diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 9d45b645..5774da48 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -202,16 +202,15 @@ void RequestGroup::createInitialCommand #ifdef ENABLE_BITTORRENT { if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) { - const BDE& torrentAttrs = - _downloadContext->getAttribute(bittorrent::BITTORRENT); - bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA); + SharedHandle torrentAttrs = + bittorrent::getTorrentAttrs(_downloadContext); + bool metadataGetMode = torrentAttrs->metadata.empty(); if(_option->getAsBool(PREF_DRY_RUN)) { throw DOWNLOAD_FAILURE_EXCEPTION ("Cancel BitTorrent download in dry-run context."); } SharedHandle btRegistry = e->getBtRegistry(); - if(!btRegistry->getDownloadContext - (torrentAttrs[bittorrent::INFO_HASH].s()).isNull()) { + if(!btRegistry->getDownloadContext(torrentAttrs->infoHash).isNull()) { // TODO If metadataGetMode == false and each FileEntry has // URI, then go without BT. throw DOWNLOAD_FAILURE_EXCEPTION @@ -337,20 +336,14 @@ void RequestGroup::createInitialCommand } _progressInfoFile = progressInfoFile; - if(torrentAttrs[bittorrent::PRIVATE].i() == 0 && - _option->getAsBool(PREF_ENABLE_DHT)) { + if(!torrentAttrs->privateTorrent && _option->getAsBool(PREF_ENABLE_DHT)) { std::vector dhtCommands; DHTSetup().setup(dhtCommands, e); e->addCommand(dhtCommands); - if(!torrentAttrs[bittorrent::NODES].empty() && DHTSetup::initialized()) { - std::vector > entryPoints; - const BDE& nodes = torrentAttrs[bittorrent::NODES]; - for(BDE::List::const_iterator i = nodes.listBegin(), - eoi = nodes.listEnd(); i != eoi; ++i) { - std::pair addr - ((*i)[bittorrent::HOSTNAME].s(), (*i)[bittorrent::PORT].i()); - entryPoints.push_back(addr); - } + const std::vector >& nodes = + torrentAttrs->nodes; + if(!nodes.empty() && DHTSetup::initialized()) { + std::vector > entryPoints(nodes); DHTEntryPointNameResolveCommand* command = new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints); command->setTaskQueue(DHTRegistry::getData().taskQueue); @@ -1094,8 +1087,9 @@ void RequestGroup::reportDownloadFinished() TransferStat stat = calculateStat(); double shareRatio = ((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0; - const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT); - if(attrs.containsKey(bittorrent::METADATA)) { + SharedHandle attrs = + bittorrent::getTorrentAttrs(_downloadContext); + if(!attrs->metadata.empty()) { _logger->notice(MSG_SHARE_RATIO_REPORT, shareRatio, util::abbrevSize(stat.getAllTimeUploadLength()).c_str(), diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index b622c2ec..6adf2dda 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -70,6 +70,7 @@ #include "FileAllocationEntry.h" #include "CheckIntegrityEntry.h" #include "Segment.h" +#include "DlAbortEx.h" namespace aria2 { diff --git a/src/TorrentAttribute.h b/src/TorrentAttribute.h new file mode 100644 index 00000000..f977a4f2 --- /dev/null +++ b/src/TorrentAttribute.h @@ -0,0 +1,66 @@ +/* */ +#ifndef D_TORRENT_ATTRIBUTE_H +#define D_TORRENT_ATTRIBUTE_H + +#include "ContextAttribute.h" + +#include +#include + +#include "a2time.h" + +struct TorrentAttribute:public ContextAttribute { + std::string name; + std::string mode; + std::vector > announceList; + std::vector > nodes; + // raw hash value 20 bytes. + std::string infoHash; + std::string metadata; + size_t metadataSize; + bool privateTorrent; + time_t creationDate; + std::string comment; + std::string createdBy; + std::vector urlList; + + TorrentAttribute():metadataSize(0), + privateTorrent(false), + creationDate(0) {} +}; + +#endif // D_TORRENT_ATTRIBUTE_H + diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index 682d0af1..09a29bf0 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -200,15 +200,15 @@ SharedHandle TrackerWatcherCommand::createAnnounce() { static bool backupTrackerIsAvailable (const SharedHandle& context) { - const BDE& announceList = - context->getAttribute(bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST]; - if(announceList.size() >= 2) { + SharedHandle torrentAttrs = + bittorrent::getTorrentAttrs(context); + if(torrentAttrs->announceList.size() >= 2) { return true; } - if(announceList.empty()) { + if(torrentAttrs->announceList.empty()) { return false; } - if(announceList[0].size() >= 2) { + if(torrentAttrs->announceList[0].size() >= 2) { return true; } else { return false; diff --git a/src/UTMetadataDataExtensionMessage.cc b/src/UTMetadataDataExtensionMessage.cc index 85b0efe0..2b97a1e2 100644 --- a/src/UTMetadataDataExtensionMessage.cc +++ b/src/UTMetadataDataExtensionMessage.cc @@ -85,9 +85,8 @@ void UTMetadataDataExtensionMessage::doReceivedAction() MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH, MessageDigestContext::SHA1, metadata.data(), metadata.size()); - const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); - if(std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]) == - attrs[bittorrent::INFO_HASH].s()){ + if(memcmp(infoHash, bittorrent::getInfoHash(_dctx), + INFO_HASH_LENGTH) == 0) { _logger->info("Got ut_metadata"); } else { _logger->info("Got wrong ut_metadata"); diff --git a/src/UTMetadataPostDownloadHandler.cc b/src/UTMetadataPostDownloadHandler.cc index 8f5ae4df..5127fd57 100644 --- a/src/UTMetadataPostDownloadHandler.cc +++ b/src/UTMetadataPostDownloadHandler.cc @@ -59,8 +59,8 @@ bool UTMetadataPostDownloadHandler::Criteria::match const SharedHandle& dctx = requestGroup->getDownloadContext(); if(dctx->hasAttribute(bittorrent::BITTORRENT)) { - const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT); - if(!attrs.containsKey(bittorrent::METADATA)) { + SharedHandle attrs = bittorrent::getTorrentAttrs(dctx); + if(attrs->metadata.empty()) { return true; } } @@ -77,7 +77,7 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups (std::vector >& groups, RequestGroup* requestGroup) { const SharedHandle& dctx =requestGroup->getDownloadContext(); - const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT); + SharedHandle attrs = bittorrent::getTorrentAttrs(dctx); std::string metadata = util::toString(requestGroup->getPieceStorage()->getDiskAdaptor()); std::string torrent = bittorrent::metadata2Torrent(metadata, attrs); @@ -85,7 +85,7 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups if(requestGroup->getOption()->getAsBool(PREF_BT_SAVE_METADATA)) { std::string filename = util::applyDir(requestGroup->getOption()->get(PREF_DIR), - util::toHex(attrs[bittorrent::INFO_HASH].s())+".torrent"); + util::toHex(attrs->infoHash)+".torrent"); if(util::saveAs(filename, torrent)) { _logger->notice(MSG_METADATA_SAVED, filename.c_str()); } else { diff --git a/src/UTMetadataRequestExtensionMessage.cc b/src/UTMetadataRequestExtensionMessage.cc index e9e2e1f8..3bbaf4ac 100644 --- a/src/UTMetadataRequestExtensionMessage.cc +++ b/src/UTMetadataRequestExtensionMessage.cc @@ -70,27 +70,25 @@ std::string UTMetadataRequestExtensionMessage::toString() const void UTMetadataRequestExtensionMessage::doReceivedAction() { - const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); + SharedHandle attrs = bittorrent::getTorrentAttrs(_dctx); uint8_t id = _peer->getExtensionMessageID("ut_metadata"); - if(!attrs.containsKey(bittorrent::METADATA)) { + if(attrs->metadata.empty()) { SharedHandle m (new UTMetadataRejectExtensionMessage(id)); m->setIndex(getIndex()); SharedHandle msg = _messageFactory->createBtExtendedMessage(m); _dispatcher->addMessageToQueue(msg); - }else if(getIndex()*METADATA_PIECE_SIZE < - (size_t)attrs[bittorrent::METADATA_SIZE].i()){ + }else if(getIndex()*METADATA_PIECE_SIZE < attrs->metadataSize) { SharedHandle m (new UTMetadataDataExtensionMessage(id)); m->setIndex(getIndex()); - m->setTotalSize(attrs[bittorrent::METADATA_SIZE].i()); - const BDE& metadata = attrs[bittorrent::METADATA]; + m->setTotalSize(attrs->metadataSize); std::string::const_iterator begin = - metadata.s().begin()+getIndex()*METADATA_PIECE_SIZE; + attrs->metadata.begin()+getIndex()*METADATA_PIECE_SIZE; std::string::const_iterator end = - (getIndex()+1)*METADATA_PIECE_SIZE <= metadata.s().size()? - metadata.s().begin()+(getIndex()+1)*METADATA_PIECE_SIZE: - metadata.s().end(); + (getIndex()+1)*METADATA_PIECE_SIZE <= attrs->metadata.size()? + attrs->metadata.begin()+(getIndex()+1)*METADATA_PIECE_SIZE: + attrs->metadata.end(); m->setData(std::string(begin, end)); SharedHandle msg = _messageFactory->createBtExtendedMessage(m); _dispatcher->addMessageToQueue(msg); diff --git a/src/ValueBase.cc b/src/ValueBase.cc new file mode 100644 index 00000000..1e318f01 --- /dev/null +++ b/src/ValueBase.cc @@ -0,0 +1,347 @@ +/* */ +#include "ValueBase.h" + +namespace aria2 { + +const SharedHandle ValueBase::none; + +String::String(const ValueType& string):str_(string) {} + +String::String(const char* cstring):str_(cstring) {} + +String::String(const char* data, size_t length):str_(&data[0], &data[length]) {} + +String::String(const unsigned char* data, size_t length): + str_(&data[0], &data[length]) {} + +String::String() {} + +const String::ValueType& String::s() const +{ + return str_; +} + +const unsigned char* String::uc() const +{ + return reinterpret_cast(str_.data()); +} + +SharedHandle String::g(const ValueType& string) +{ + return SharedHandle(new String(string)); +} + +void String::accept(ValueBaseVisitor& v) const +{ + v.visit(*this); +} + +Integer::Integer(ValueType integer):integer_(integer) {} + +Integer::Integer():integer_(0) {} + +Integer::ValueType Integer::i() const +{ + return integer_; +} + +SharedHandle Integer::g(ValueType integer) +{ + return SharedHandle(new Integer(integer)); +} + +void Integer::accept(ValueBaseVisitor& v) const +{ + v.visit(*this); +} + +List::List() {} + +const SharedHandle& List::get(size_t index) const +{ + return list_[index]; +} + +void List::append(const SharedHandle& v) +{ + list_.push_back(v); +} + +List& List::operator<<(const SharedHandle& v) +{ + list_.push_back(v); + return *this; +} + +const SharedHandle& List::operator[](size_t index) const +{ + return list_[index]; +} + +List::ValueType::iterator List::begin() +{ + return list_.begin(); +} + +List::ValueType::iterator List::end() +{ + return list_.end(); +} + +List::ValueType::const_iterator List::begin() const +{ + return list_.begin(); +} + +List::ValueType::const_iterator List::end() const +{ + return list_.end(); +} + +size_t List::size() const +{ + return list_.size(); +} + +bool List::empty() const +{ + return list_.empty(); +} + +SharedHandle List::g() +{ + return SharedHandle(new List()); +} + +void List::accept(ValueBaseVisitor& v) const +{ + v.visit(*this); +} + +Dict::Dict() {} + +void Dict::put(const std::string& key, const SharedHandle& vlb) +{ + ValueType::value_type p = std::make_pair(key, vlb); + std::pair r = dict_.insert(p); + if(!r.second) { + (*r.first).second = vlb; + } +} + +void Dict::put(const std::string& key, const String::ValueType& string) +{ + put(key, String::g(string)); +} + +const SharedHandle& Dict::get(const std::string& key) const +{ + ValueType::const_iterator itr = dict_.find(key); + if(itr == dict_.end()) { + return ValueBase::none; + } else { + return (*itr).second; + } +} + +SharedHandle& Dict::operator[](const std::string& key) +{ + return dict_[key]; +} + +const SharedHandle& Dict::operator[](const std::string& key) const +{ + return get(key); +} + +bool Dict::containsKey(const std::string& key) const +{ + return dict_.count(key) == 1; +} + +void Dict::removeKey(const std::string& key) +{ + dict_.erase(key); +} + +Dict::ValueType::iterator Dict::begin() +{ + return dict_.begin(); +} + +Dict::ValueType::iterator Dict::end() +{ + return dict_.end(); +} + +Dict::ValueType::const_iterator Dict::begin() const +{ + return dict_.begin(); +} + +Dict::ValueType::const_iterator Dict::end() const +{ + return dict_.end(); +} + +size_t Dict::size() const +{ + return dict_.size(); +} + +bool Dict::empty() const +{ + return dict_.empty(); +} + +SharedHandle Dict::g() +{ + return SharedHandle(new Dict()); +} +void Dict::accept(ValueBaseVisitor& v) const +{ + v.visit(*this); +} + +const String* asString(const ValueBase* v) +{ + if(v) { + return downcast(v); + } else { + return 0; + } +} + +String* asString(ValueBase* v) +{ + if(v) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +String* asString(const SharedHandle& v) +{ + if(v.get()) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +const Integer* asInteger(const ValueBase* v) +{ + if(v) { + return downcast(v); + } else { + return 0; + } +} + +Integer* asInteger(ValueBase* v) +{ + if(v) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +Integer* asInteger(const SharedHandle& v) +{ + if(v.get()) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +const List* asList(const ValueBase* v) +{ + if(v) { + return downcast(v); + } else { + return 0; + } +} + +List* asList(ValueBase* v) +{ + if(v) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +List* asList(const SharedHandle& v) +{ + if(v.get()) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +const Dict* asDict(const ValueBase* v) +{ + if(v) { + return downcast(v); + } else { + return 0; + } +} + +Dict* asDict(ValueBase* v) +{ + if(v) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +Dict* asDict(const SharedHandle& v) +{ + if(v.get()) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +} // namespace aria2 diff --git a/src/ValueBase.h b/src/ValueBase.h new file mode 100644 index 00000000..9dbbcf51 --- /dev/null +++ b/src/ValueBase.h @@ -0,0 +1,288 @@ +/* */ +#ifndef D_VALUE_BASE_H +#define D_VALUE_BASE_H + +#include "common.h" + +#include +#include +#include + +#include "SharedHandle.h" + +namespace aria2 { + +class ValueBaseVisitor; + +class ValueBase { +public: + virtual ~ValueBase() {} + + virtual void accept(ValueBaseVisitor& visitor) const = 0; + + static const SharedHandle none; +}; + +class String; +class Integer; +class List; +class Dict; + +class ValueBaseVisitor { +public: + virtual ~ValueBaseVisitor() {} + + virtual void visit(const String& string) = 0; + + virtual void visit(const Integer& integer) = 0; + + virtual void visit(const List& list) = 0; + + virtual void visit(const Dict& dict) = 0; +}; + +class String:public ValueBase { +public: + typedef std::string ValueType; + + String(const ValueType& string); + + explicit String(const char* cstring); + + String(const char* data, size_t length); + + String(const unsigned char* data, size_t length); + + String(); + + const ValueType& s() const; + + // Returns std::string.data() casted to unsigned char*. + // Use s().size() to get length. + const unsigned char* uc() const; + + static SharedHandle g(const ValueType& string); + + virtual void accept(ValueBaseVisitor& visitor) const; +private: + ValueType str_; +}; + +class Integer:public ValueBase { +public: + typedef int64_t ValueType; + + Integer(ValueType integer); + + Integer(); + + // Returns Integer. + ValueType i() const; + + static SharedHandle g(ValueType integer); + + virtual void accept(ValueBaseVisitor& visitor) const; +private: + ValueType integer_; +}; + +class List:public ValueBase { +public: + typedef std::vector > ValueType; + + List(); + + // Appends given v to list. + void append(const SharedHandle& v); + + // Alias for append() + List& operator<<(const SharedHandle& v); + + // Returns the object at given index. + const SharedHandle& get(size_t index) const; + + // Returns the const reference of the object at the given index. + const SharedHandle& operator[](size_t index) const; + + // Returns a read/write iterator that points to the first object in + // list. + ValueType::iterator begin(); + + // Returns a read/write iterator that points to the one past the + // last object in list. + ValueType::iterator end(); + + // Returns a read/write read-only iterator that points to the first + // object in list. + ValueType::const_iterator begin() const; + + // Returns a read/write read-only iterator that points to the one + // past the last object in list. + ValueType::const_iterator end() const; + + // Returns size of list. + size_t size() const; + + // Returns true if size of list is 0. + bool empty() const; + + static SharedHandle g(); + + virtual void accept(ValueBaseVisitor& visitor) const; +private: + ValueType list_; +}; + +class Dict:public ValueBase { +public: + typedef std::map > ValueType; + + Dict(); + + void put(const std::string& key, const SharedHandle& vlb); + + // Putting string is so common that we provide shortcut function. + void put(const std::string& key, const String::ValueType& string); + + const SharedHandle& get(const std::string& key) const; + + // Returns the reference to object associated with given key. If + // the key is not found, new pair with that key is created using + // default values, which is then returned. In other words, this is + // the same behavior of std::map's operator[]. + SharedHandle& operator[](const std::string& key); + + // Returns the const reference to ojbect associated with given key. + // If the key is not found, ValueBase::none is returned. + const SharedHandle& operator[](const std::string& key) const; + + // Returns true if the given key is found in dict. + bool containsKey(const std::string& key) const; + + // Removes specified key from dict. + void removeKey(const std::string& key); + + // Returns a read/write iterator that points to the first pair in + // the dict. + ValueType::iterator begin(); + + // Returns a read/write read-only iterator that points to one past + // the last pair in the dict. + ValueType::iterator end(); + + // Returns a read/write read-only iterator that points to the first + // pair in the dict. + ValueType::const_iterator begin() const; + + // Returns a read/write read-only iterator that points to one past + // the last pair in the dict. + ValueType::const_iterator end() const; + + // Returns size of Dict. + size_t size() const; + + // Returns true if size of Dict is 0. + bool empty() const; + + static SharedHandle g(); + + virtual void accept(ValueBaseVisitor& visitor) const; +private: + ValueType dict_; +}; + +template +class DowncastValueBaseVisitor:public ValueBaseVisitor { +private: + const T* result_; +public: + DowncastValueBaseVisitor():result_(0) {} + + virtual void visit(const T& t) + { + result_ = &t; + } + + virtual void visit(const T1& t1) {} + virtual void visit(const T2& t2) {} + virtual void visit(const T3& t3) {} + + const T* getResult() const + { + return result_; + } + + void setResult(const T* r) + { + result_ = r; + } +}; + +template +const T* downcast(const VPtr& v) +{ + DowncastValueBaseVisitor visitor; + v->accept(visitor); + return visitor.getResult(); +} + +const String* asString(const ValueBase* v); + +String* asString(ValueBase* v); + +String* asString(const SharedHandle& v); + +const Integer* asInteger(const ValueBase* v); + +Integer* asInteger(ValueBase* v); + +Integer* asInteger(const SharedHandle& v); + +const List* asList(const ValueBase* v); + +List* asList(ValueBase* v); + +List* asList(const SharedHandle& v); + +const Dict* asDict(const ValueBase* v); + +Dict* asDict(ValueBase* v); + +Dict* asDict(const SharedHandle& v); + +} // namespace aria2 + +#endif // D_VALUE_BASE_H diff --git a/src/XmlRpcMethodImpl.cc b/src/XmlRpcMethodImpl.cc index 6e447f13..f1db44e4 100644 --- a/src/XmlRpcMethodImpl.cc +++ b/src/XmlRpcMethodImpl.cc @@ -563,44 +563,43 @@ void gatherProgressCommon } #ifdef ENABLE_BITTORRENT -void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs) +void gatherBitTorrentMetadata +(BDE& btDict, const SharedHandle& torrentAttrs) { - if(torrentAttrs.containsKey(bittorrent::COMMENT)) { - btDict[KEY_COMMENT] = torrentAttrs[bittorrent::COMMENT]; + if(!torrentAttrs->comment.empty()) { + btDict[KEY_COMMENT] = torrentAttrs->comment; } - if(torrentAttrs.containsKey(bittorrent::CREATION_DATE)) { - btDict[KEY_CREATION_DATE] = torrentAttrs[bittorrent::CREATION_DATE]; + if(torrentAttrs->creationDate) { + btDict[KEY_CREATION_DATE] = torrentAttrs->creationDate; } - if(torrentAttrs.containsKey(bittorrent::MODE)) { - btDict[KEY_MODE] = torrentAttrs[bittorrent::MODE]; + if(!torrentAttrs->mode.empty()) { + btDict[KEY_MODE] = torrentAttrs->mode; } - // Copy announceList to avoid modification on entyDict to be - // affected original announceList. - // TODO Would it be good to add copy() method in BDE? - const BDE& announceList = torrentAttrs[bittorrent::ANNOUNCE_LIST]; BDE destAnnounceList = BDE::list(); - for(BDE::List::const_iterator l = announceList.listBegin(), - eoi = announceList.listEnd(); l != eoi; ++l) { + for(std::vector >::const_iterator l = + torrentAttrs->announceList.begin(), + eoi = torrentAttrs->announceList.end(); l != eoi; ++l) { BDE destAnnounceTier = BDE::list(); - for(BDE::List::const_iterator t = (*l).listBegin(), - eoi2 = (*l).listEnd(); t != eoi2; ++t) { - destAnnounceTier << (*t); + for(std::vector::const_iterator t = (*l).begin(), + eoi2 = (*l).end(); t != eoi2; ++t) { + destAnnounceTier << *t; } destAnnounceList << destAnnounceTier; } btDict[KEY_ANNOUNCE_LIST] = destAnnounceList; - if(torrentAttrs.containsKey(bittorrent::METADATA)) { + if(!torrentAttrs->metadata.empty()) { BDE infoDict = BDE::dict(); - infoDict[KEY_NAME] = torrentAttrs[bittorrent::NAME]; + infoDict[KEY_NAME] = torrentAttrs->name; btDict[KEY_INFO] = infoDict; } } static void gatherProgressBitTorrent -(BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject) +(BDE& entryDict, + const SharedHandle& torrentAttrs, + const BtObject& btObject) { - const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s(); - entryDict[KEY_INFO_HASH] = util::toHex(infoHash); + entryDict[KEY_INFO_HASH] = util::toHex(torrentAttrs->infoHash); BDE btDict = BDE::dict(); gatherBitTorrentMetadata(btDict, torrentAttrs); entryDict[KEY_BITTORRENT] = btDict; @@ -651,8 +650,8 @@ static void gatherProgress gatherProgressCommon(entryDict, group); #ifdef ENABLE_BITTORRENT if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) { - const BDE& torrentAttrs = - group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT); + SharedHandle torrentAttrs = + bittorrent::getTorrentAttrs(group->getDownloadContext()); BtObject btObject = e->getBtRegistry()->get(group->getGID()); gatherProgressBitTorrent(entryDict, torrentAttrs, btObject); } diff --git a/src/XmlRpcMethodImpl.h b/src/XmlRpcMethodImpl.h index 66e81792..0b7abbae 100644 --- a/src/XmlRpcMethodImpl.h +++ b/src/XmlRpcMethodImpl.h @@ -43,6 +43,8 @@ #include "BDE.h" #include "XmlRpcRequest.h" +#include "ValueBase.h" +#include "TorrentAttribute.h" namespace aria2 { @@ -500,9 +502,9 @@ void gatherProgressCommon (BDE& entryDict, const SharedHandle& group); #ifdef ENABLE_BITTORRENT -// Helper function to store BitTorrent metadata from torrentAttrs in -// btDict. btDict must be an BDE::Dict. -void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs); +// Helper function to store BitTorrent metadata from torrentAttrs. +void gatherBitTorrentMetadata +(BDE& btDict, const SharedHandle& torrentAttrs); #endif // ENABLE_BITTORRENT } // namespace xmlrpc diff --git a/src/bencode2.cc b/src/bencode2.cc new file mode 100644 index 00000000..6e2d3b8c --- /dev/null +++ b/src/bencode2.cc @@ -0,0 +1,263 @@ +/* */ +#include "bencode2.h" + +#include +#include + +#include "StringFormat.h" +#include "DlAbortEx.h" + +namespace aria2 { + +namespace bencode2 { + +static SharedHandle decodeiter(std::istream& ss, size_t depth); + +static void checkdelim(std::istream& ss, const char delim = ':') +{ + char d; + if(!(ss.get(d) && d == delim)) { + throw DL_ABORT_EX + (StringFormat("Bencode decoding failed: Delimiter '%c' not found.", + delim).str()); + } +} + +static std::string decoderawstring(std::istream& ss) +{ + int length; + ss >> length; + if(!ss || length < 0) { + throw DL_ABORT_EX("Bencode decoding failed:" + " A positive integer expected but none found."); + } + // TODO check length, it must be less than or equal to INT_MAX + checkdelim(ss); + char* buf = new char[length]; + ss.read(buf, length); + std::string str(&buf[0], &buf[length]); + delete [] buf; + if(ss.gcount() != static_cast(length)) { + throw DL_ABORT_EX + (StringFormat("Bencode decoding failed:" + " Expected %lu bytes of data, but only %d read.", + static_cast(length), ss.gcount()).str()); + } + return str; +} + +static SharedHandle decodestring(std::istream& ss) +{ + return String::g(decoderawstring(ss)); +} + +static SharedHandle decodeinteger(std::istream& ss) +{ + Integer::ValueType iv; + ss >> iv; + if(!ss) { + throw DL_ABORT_EX("Bencode decoding failed:" + " Integer expected but none found"); + } + checkdelim(ss, 'e'); + return Integer::g(iv); +} + +static SharedHandle decodedict(std::istream& ss, size_t depth) +{ + SharedHandle dict = Dict::g(); + char c; + while(ss.get(c)) { + if(c == 'e') { + return dict; + } else { + ss.unget(); + std::string key = decoderawstring(ss); + dict->put(key, decodeiter(ss, depth)); + } + } + throw DL_ABORT_EX("Bencode decoding failed:" + " Unexpected EOF in dict context. 'e' expected."); +} + +static SharedHandle decodelist(std::istream& ss, size_t depth) +{ + SharedHandle list = List::g(); + char c; + while(ss.get(c)) { + if(c == 'e') { + return list; + } else { + ss.unget(); + list->append(decodeiter(ss, depth)); + } + } + throw DL_ABORT_EX("Bencode decoding failed:" + " Unexpected EOF in list context. 'e' expected."); +} + +static void checkDepth(size_t depth) +{ + if(depth >= MAX_STRUCTURE_DEPTH) { + throw DL_ABORT_EX("Bencode decoding failed: Structure is too deep."); + } +} + +static SharedHandle decodeiter(std::istream& ss, size_t depth) +{ + checkDepth(depth); + char c; + if(!ss.get(c)) { + throw DL_ABORT_EX("Bencode decoding failed:" + " Unexpected EOF in term context." + " 'd', 'l', 'i' or digit is expected."); + } + if(c == 'd') { + return decodedict(ss, depth+1); + } else if(c == 'l') { + return decodelist(ss, depth+1); + } else if(c == 'i') { + return decodeinteger(ss); + } else { + ss.unget(); + return decodestring(ss); + } +} + +SharedHandle decode(std::istream& in) +{ + return decodeiter(in, 0); +} + +SharedHandle decode(const std::string& s) +{ + size_t end; + return decode(s, end); +} + +SharedHandle decode(const std::string& s, size_t& end) +{ + if(s.empty()) { + return SharedHandle(); + } + std::istringstream ss(s); + + SharedHandle vlb = decodeiter(ss, 0); + end = ss.tellg(); + return vlb; +} + +SharedHandle decode(const unsigned char* data, size_t length) +{ + return decode(std::string(&data[0], &data[length])); +} + +SharedHandle decode(const unsigned char* data, size_t length, size_t& end) +{ + return decode(std::string(&data[0], &data[length]), end); +} + +SharedHandle decodeFromFile(const std::string& filename) +{ + std::ifstream f(filename.c_str(), std::ios::binary); + if(f) { + return decode(f); + } else { + throw DL_ABORT_EX + (StringFormat("Bencode decoding failed:" + " Cannot open file '%s'.", filename.c_str()).str()); + } +} + +std::string encode(const ValueBase* vlb) +{ + class BencodeValueBaseVisitor:public ValueBaseVisitor { + private: + std::ostringstream out_; + public: + virtual void visit(const String& string) + { + const std::string& s = string.s(); + out_ << s.size() << ":"; + out_.write(s.data(), s.size()); + } + + virtual void visit(const Integer& integer) + { + out_ << "i" << integer.i() << "e"; + } + + virtual void visit(const List& list) + { + out_ << "l"; + for(List::ValueType::const_iterator i = list.begin(), eoi = list.end(); + i != eoi; ++i){ + (*i)->accept(*this); + } + out_ << "e"; + } + + virtual void visit(const Dict& dict) + { + out_ << "d"; + for(Dict::ValueType::const_iterator i = dict.begin(), eoi = dict.end(); + i != eoi; ++i){ + const std::string& key = (*i).first; + out_ << key.size() << ":"; + out_.write(key.data(), key.size()); + (*i).second->accept(*this); + } + out_ << "e"; + } + + std::string getResult() const + { + return out_.str(); + } + }; + BencodeValueBaseVisitor visitor; + vlb->accept(visitor); + return visitor.getResult(); +} + +std::string encode(const SharedHandle& vlb) +{ + return encode(vlb.get()); +} + +} // namespace bencode2 + +} // namespace aria2 diff --git a/src/bencode2.h b/src/bencode2.h new file mode 100644 index 00000000..27f2896b --- /dev/null +++ b/src/bencode2.h @@ -0,0 +1,75 @@ +/* */ +#ifndef _D_BENCODE2_H_ +#define _D_BENCODE2_H_ + +#include "common.h" + +#include +#include + +#include "ValueBase.h" + +namespace aria2 { + +namespace bencode2 { + +const size_t MAX_STRUCTURE_DEPTH = 100; + +SharedHandle decode(std::istream& in); + +// Decode the data in s. +SharedHandle decode(const std::string& s); + +// Decode the data in s. After decode is done successfully, return the +// bencoded string length in end. +SharedHandle decode(const std::string& s, size_t& end); + +SharedHandle decode(const unsigned char* data, size_t length); + +SharedHandle decode +(const unsigned char* data, size_t length, size_t& end); + +SharedHandle decodeFromFile(const std::string& filename); + +std::string encode(const ValueBase* vlb); + +std::string encode(const SharedHandle& vlb); + +} // namespace bencode2 + +} // namespace aria2 + +#endif // _D_BENCODE2_H_ diff --git a/src/bittorrent_helper.cc b/src/bittorrent_helper.cc index 42b1c4a8..cbac20c7 100644 --- a/src/bittorrent_helper.cc +++ b/src/bittorrent_helper.cc @@ -54,6 +54,9 @@ #include "bitfield.h" #include "base32.h" #include "magnet.h" +#include "ValueBase.h" +#include "bencode2.h" +#include "TorrentAttribute.h" namespace aria2 { @@ -147,23 +150,44 @@ static void extractPieceHash(const SharedHandle& ctx, } static void extractUrlList -(BDE& torrent, std::vector& uris, const BDE& bde) +(const SharedHandle& torrent, std::vector& uris, + const ValueBase* v) { - if(bde.isList()) { - for(BDE::List::const_iterator itr = bde.listBegin(), eoi = bde.listEnd(); - itr != eoi; ++itr) { - if((*itr).isString()) { - uris.push_back((*itr).s()); + class UrlListVisitor:public ValueBaseVisitor { + private: + std::vector& uris_; + const SharedHandle& torrent_; + public: + UrlListVisitor + (std::vector& uris, + const SharedHandle& torrent): + uris_(uris), torrent_(torrent) {} + + virtual void visit(const String& v) + { + uris_.push_back(v.s()); + torrent_->urlList.push_back(v.s()); + } + + virtual void visit(const Integer& v) {} + + virtual void visit(const List& v) + { + for(List::ValueType::const_iterator itr = v.begin(), eoi = v.end(); + itr != eoi; ++itr) { + const String* uri = asString(*itr); + if(uri) { + uris_.push_back(uri->s()); + torrent_->urlList.push_back(uri->s()); + } } } - torrent[URL_LIST] = bde; - } else if(bde.isString()) { - uris.push_back(bde.s()); - BDE urlList = BDE::list(); - urlList << bde; - torrent[URL_LIST] = urlList; - } else { - torrent[URL_LIST] = BDE::list(); + virtual void visit(const Dict& v) {} + }; + + if(v) { + UrlListVisitor visitor(uris, torrent); + v->accept(visitor); } } @@ -184,8 +208,8 @@ static OutputIterator createUri static void extractFileEntries (const SharedHandle& ctx, - BDE& torrent, - const BDE& infoDict, + const SharedHandle& torrent, + const Dict* infoDict, const std::string& defaultName, const std::string& overrideName, const std::vector& urlList) @@ -193,62 +217,71 @@ static void extractFileEntries std::string name; if(overrideName.empty()) { std::string nameKey; - if(infoDict.containsKey(C_NAME_UTF8)) { + if(infoDict->containsKey(C_NAME_UTF8)) { nameKey = C_NAME_UTF8; } else { nameKey = C_NAME; } - const BDE& nameData = infoDict[nameKey]; - if(nameData.isString()) { - if(util::detectDirTraversal(nameData.s())) { + const String* nameData = asString(infoDict->get(nameKey)); + if(nameData) { + if(util::detectDirTraversal(nameData->s())) { throw DL_ABORT_EX - (StringFormat(MSG_DIR_TRAVERSAL_DETECTED,nameData.s().c_str()).str()); + (StringFormat + (MSG_DIR_TRAVERSAL_DETECTED,nameData->s().c_str()).str()); } - name = nameData.s(); + name = nameData->s(); } else { name = strconcat(File(defaultName).getBasename(), ".file"); } } else { name = overrideName; } - torrent[NAME] = name; - - const BDE& filesList = infoDict[C_FILES]; + torrent->name = name; std::vector > fileEntries; - if(filesList.isList()) { - fileEntries.reserve(filesList.size()); + const List* filesList = asList(infoDict->get(C_FILES)); + if(filesList) { + fileEntries.reserve(filesList->size()); uint64_t length = 0; off_t offset = 0; // multi-file mode - torrent[MODE] = MULTI; - for(BDE::List::const_iterator itr = filesList.listBegin(), - eoi = filesList.listEnd(); itr != eoi; ++itr) { - const BDE& fileDict = *itr; - if(!fileDict.isDict()) { + torrent->mode = MULTI; + for(List::ValueType::const_iterator itr = filesList->begin(), + eoi = filesList->end(); itr != eoi; ++itr) { + const Dict* fileDict = asDict(*itr); + if(!fileDict) { continue; } - const BDE& fileLengthData = fileDict[C_LENGTH]; - if(!fileLengthData.isInteger()) { + const Integer* fileLengthData = asInteger(fileDict->get(C_LENGTH)); + if(!fileLengthData) { throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO, C_LENGTH.c_str()).str()); } - length += fileLengthData.i(); + length += fileLengthData->i(); std::string pathKey; - if(fileDict.containsKey(C_PATH_UTF8)) { + if(fileDict->containsKey(C_PATH_UTF8)) { pathKey = C_PATH_UTF8; } else { pathKey = C_PATH; } - const BDE& pathList = fileDict[pathKey]; - if(!pathList.isList() || pathList.empty()) { + const List* pathList = asList(fileDict->get(pathKey)); + if(!pathList || pathList->empty()) { throw DL_ABORT_EX("Path is empty."); } - std::vector pathelem(pathList.size()+1); + std::vector pathelem(pathList->size()+1); pathelem[0] = name; - std::transform(pathList.listBegin(), pathList.listEnd(), - pathelem.begin()+1, std::mem_fun_ref(&BDE::s)); + std::vector::iterator pathelemOutItr = pathelem.begin(); + ++pathelemOutItr; + for(List::ValueType::const_iterator itr = pathList->begin(), + eoi = pathList->end(); itr != eoi; ++itr) { + const String* elem = asString(*itr); + if(elem) { + (*pathelemOutItr++) = elem->s(); + } else { + throw DL_ABORT_EX("Path element is not string."); + } + } std::string path = strjoin(pathelem.begin(), pathelem.end(), '/'); if(util::detectDirTraversal(path)) { throw DL_ABORT_EX @@ -262,7 +295,7 @@ static void extractFileEntries createUri(urlList.begin(), urlList.end(),std::back_inserter(uris),pePath); SharedHandle fileEntry (new FileEntry(util::applyDir(ctx->getDir(), util::escapePath(path)), - fileLengthData.i(), + fileLengthData->i(), offset, uris)); fileEntry->setOriginalName(path); fileEntries.push_back(fileEntry); @@ -270,13 +303,13 @@ static void extractFileEntries } } else { // single-file mode; - torrent[MODE] = SINGLE; - const BDE& lengthData = infoDict[C_LENGTH]; - if(!lengthData.isInteger()) { + torrent->mode = SINGLE; + const Integer* lengthData = asInteger(infoDict->get(C_LENGTH)); + if(!lengthData) { throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO, C_LENGTH.c_str()).str()); } - uint64_t totalLength = lengthData.i(); + uint64_t totalLength = lengthData->i(); // For each uri in urlList, if it ends with '/', then // concatenate name to it. Specification just says so. @@ -298,98 +331,103 @@ static void extractFileEntries fileEntries.push_back(fileEntry); } ctx->setFileEntries(fileEntries.begin(), fileEntries.end()); - if(torrent[MODE].s() == MULTI) { + if(torrent->mode == MULTI) { ctx->setBasePath(util::applyDir(ctx->getDir(), name)); } } -static void extractAnnounce(BDE& torrent, const BDE& rootDict) +static void extractAnnounce +(const SharedHandle& torrent, const Dict* rootDict) { - const BDE& announceList = rootDict[C_ANNOUNCE_LIST]; - if(announceList.isList()) { - torrent[ANNOUNCE_LIST] = announceList; - BDE& tiers = torrent[ANNOUNCE_LIST]; - for(BDE::List::iterator tieriter = tiers.listBegin(), - eoi = tiers.listEnd(); tieriter != eoi; ++tieriter) { - for(BDE::List::iterator uriiter = (*tieriter).listBegin(), - eoi2 = (*tieriter).listEnd(); uriiter != eoi2; ++uriiter) { - if((*uriiter).isString()) { - *uriiter = util::trim((*uriiter).s()); + const List* announceList = asList(rootDict->get(C_ANNOUNCE_LIST)); + if(announceList) { + for(List::ValueType::const_iterator tierIter = announceList->begin(), + eoi = announceList->end(); tierIter != eoi; ++tierIter) { + const List* tier = asList(*tierIter); + if(!tier) { + continue; + } + std::vector ntier; + for(List::ValueType::const_iterator uriIter = tier->begin(), + eoi2 = tier->end(); uriIter != eoi2; ++uriIter) { + const String* uri = asString(*uriIter); + if(uri) { + ntier.push_back(util::trim(uri->s())); } } + if(!ntier.empty()) { + torrent->announceList.push_back(ntier); + } } } else { - const BDE& announce = rootDict[C_ANNOUNCE]; - BDE announceList = BDE::list(); - if(announce.isString()) { - announceList << BDE::list(); - announceList[0] << util::trim(announce.s()); + const String* announce = asString(rootDict->get(C_ANNOUNCE)); + if(announce) { + std::vector tier; + tier.push_back(util::trim(announce->s())); + torrent->announceList.push_back(tier); } - torrent[ANNOUNCE_LIST] = announceList; } } -static void extractNodes(BDE& torrent, const BDE& nodesList) +static void extractNodes +(const SharedHandle& torrent, const ValueBase* nodesListSrc) { - BDE nodes = BDE::list(); - if(nodesList.isList()) { - for(BDE::List::const_iterator i = nodesList.listBegin(), - eoi = nodesList.listEnd(); i != eoi; ++i) { - const BDE& addrPairList = (*i); - if(!addrPairList.isList() || addrPairList.size() != 2) { + const List* nodesList = asList(nodesListSrc); + if(nodesList) { + for(List::ValueType::const_iterator i = nodesList->begin(), + eoi = nodesList->end(); i != eoi; ++i) { + const List* addrPairList = asList(*i); + if(!addrPairList || addrPairList->size() != 2) { continue; } - const BDE& hostname = addrPairList[0]; - if(!hostname.isString()) { + const String* hostname = asString(addrPairList->get(0)); + if(!hostname) { continue; } - if(util::trim(hostname.s()).empty()) { + if(util::trim(hostname->s()).empty()) { continue; } - const BDE& port = addrPairList[1]; - if(!port.isInteger() || !(0 < port.i() && port.i() < 65536)) { + const Integer* port = asInteger(addrPairList->get(1)); + if(!port || !(0 < port->i() && port->i() < 65536)) { continue; } - BDE node = BDE::dict(); - node[HOSTNAME] = hostname; - node[PORT] = port; - nodes << node; + torrent->nodes.push_back(std::make_pair(hostname->s(), port->i())); } } - torrent[NODES] = nodes; } static void processRootDictionary (const SharedHandle& ctx, - const BDE& rootDict, + const SharedHandle& root, const std::string& defaultName, const std::string& overrideName, const std::vector& uris) { - if(!rootDict.isDict()) { + const Dict* rootDict = asDict(root); + if(!rootDict) { throw DL_ABORT_EX("torrent file does not contain a root dictionary."); } - const BDE& infoDict = rootDict[C_INFO]; - if(!infoDict.isDict()) { + const Dict* infoDict = asDict(rootDict->get(C_INFO)); + if(!infoDict) { throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO, C_INFO.c_str()).str()); } - BDE torrent = BDE::dict(); + SharedHandle torrent(new TorrentAttribute()); // retrieve infoHash - std::string encodedInfoDict = bencode::encode(infoDict); + std::string encodedInfoDict = bencode2::encode(infoDict); unsigned char infoHash[INFO_HASH_LENGTH]; MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH, MessageDigestContext::SHA1, encodedInfoDict.data(), encodedInfoDict.size()); - torrent[INFO_HASH] = std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]); - torrent[METADATA] = encodedInfoDict; - torrent[METADATA_SIZE] = encodedInfoDict.size(); + torrent->infoHash = std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]); + torrent->metadata = encodedInfoDict; + torrent->metadataSize = encodedInfoDict.size(); // calculate the number of pieces - const BDE& piecesData = infoDict[C_PIECES]; - if(!piecesData.isString()) { + const String* piecesData = asString(infoDict->get(C_PIECES)); + if(!piecesData) { throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO, C_PIECES.c_str()).str()); } @@ -397,65 +435,68 @@ static void processRootDictionary // if(piecesData.s().empty()) { // throw DL_ABORT_EX("The length of piece hash is 0."); // } - size_t numPieces = piecesData.s().size()/PIECE_HASH_LENGTH; + size_t numPieces = piecesData->s().size()/PIECE_HASH_LENGTH; // Commented out to download 0 length torrent. // if(numPieces == 0) { // throw DL_ABORT_EX("The number of pieces is 0."); // } // retrieve piece length - const BDE& pieceLengthData = infoDict[C_PIECE_LENGTH]; - if(!pieceLengthData.isInteger()) { + const Integer* pieceLengthData = asInteger(infoDict->get(C_PIECE_LENGTH)); + if(!pieceLengthData) { throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO, C_PIECE_LENGTH.c_str()).str()); } - size_t pieceLength = pieceLengthData.i(); + size_t pieceLength = pieceLengthData->i(); ctx->setPieceLength(pieceLength); // retrieve piece hashes - extractPieceHash(ctx, piecesData.s(), PIECE_HASH_LENGTH, numPieces); + extractPieceHash(ctx, piecesData->s(), PIECE_HASH_LENGTH, numPieces); // private flag - const BDE& privateData = infoDict[C_PRIVATE]; + const Integer* privateData = asInteger(infoDict->get(C_PRIVATE)); int privatefg = 0; - if(privateData.isInteger()) { - if(privateData.i() == 1) { + if(privateData) { + if(privateData->i() == 1) { privatefg = 1; } } - torrent[PRIVATE] = BDE((int64_t)privatefg); + if(privatefg) { + torrent->privateTorrent = true; + } // retrieve uri-list. // This implemantation obeys HTTP-Seeding specification: // see http://www.getright.com/seedtorrent.html std::vector urlList; - extractUrlList(torrent, urlList, rootDict[C_URL_LIST]); + extractUrlList(torrent, urlList, rootDict->get(C_URL_LIST).get()); urlList.insert(urlList.end(), uris.begin(), uris.end()); std::sort(urlList.begin(), urlList.end()); urlList.erase(std::unique(urlList.begin(), urlList.end()), urlList.end()); // retrieve file entries - extractFileEntries(ctx, torrent, infoDict, defaultName, overrideName, urlList); + extractFileEntries + (ctx, torrent, infoDict, defaultName, overrideName, urlList); if((ctx->getTotalLength()+pieceLength-1)/pieceLength != numPieces) { throw DL_ABORT_EX("Too few/many piece hash."); } // retrieve announce extractAnnounce(torrent, rootDict); // retrieve nodes - extractNodes(torrent, rootDict[C_NODES]); + extractNodes(torrent, rootDict->get(C_NODES).get()); - const BDE& creationDate = rootDict[C_CREATION_DATE]; - if(creationDate.isInteger()) { - torrent[CREATION_DATE] = creationDate; + const Integer* creationDate = asInteger(rootDict->get(C_CREATION_DATE)); + if(creationDate) { + torrent->creationDate = creationDate->i(); } - const BDE& commentUtf8 = rootDict[C_COMMENT_UTF8]; - if(commentUtf8.isString()) { - torrent[COMMENT] = commentUtf8; + const String* commentUtf8 = asString(rootDict->get(C_COMMENT_UTF8)); + if(commentUtf8) { + torrent->comment = commentUtf8->s(); } else { - const BDE& comment = rootDict[C_COMMENT]; - if(comment.isString()) { - torrent[COMMENT] = comment; + const String* comment = asString(rootDict->get(C_COMMENT)); + if(comment) { + torrent->comment = comment->s(); } } - const BDE& createdBy = rootDict[C_CREATED_BY]; - if(createdBy.isString()) { - torrent[CREATED_BY] = createdBy; + const String* createdBy = asString(rootDict->get(C_CREATED_BY)); + if(createdBy) { + torrent->createdBy = createdBy->s(); } ctx->setAttribute(BITTORRENT, torrent); @@ -466,7 +507,7 @@ void load(const std::string& torrentFile, const std::string& overrideName) { processRootDictionary(ctx, - bencode::decodeFromFile(torrentFile), + bencode2::decodeFromFile(torrentFile), torrentFile, overrideName, std::vector()); @@ -478,7 +519,7 @@ void load(const std::string& torrentFile, const std::string& overrideName) { processRootDictionary(ctx, - bencode::decodeFromFile(torrentFile), + bencode2::decodeFromFile(torrentFile), torrentFile, overrideName, uris); @@ -491,7 +532,7 @@ void loadFromMemory(const unsigned char* content, const std::string& overrideName) { processRootDictionary(ctx, - bencode::decode(content, length), + bencode2::decode(content, length), defaultName, overrideName, std::vector()); @@ -505,7 +546,7 @@ void loadFromMemory(const unsigned char* content, const std::string& overrideName) { processRootDictionary(ctx, - bencode::decode(content, length), + bencode2::decode(content, length), defaultName, overrideName, uris); @@ -518,7 +559,7 @@ void loadFromMemory(const std::string& context, { processRootDictionary (ctx, - bencode::decode(context), + bencode2::decode(context), defaultName, overrideName, std::vector()); } @@ -531,73 +572,82 @@ void loadFromMemory(const std::string& context, { processRootDictionary (ctx, - bencode::decode(context), + bencode2::decode(context), defaultName, overrideName, uris); } -const unsigned char* -getInfoHash(const SharedHandle& downloadContext) +SharedHandle getTorrentAttrs +(const SharedHandle& dctx) { - return downloadContext->getAttribute(BITTORRENT)[INFO_HASH].uc(); + return static_pointer_cast(dctx->getAttribute(BITTORRENT)); +} + +const unsigned char* +getInfoHash(const SharedHandle& dctx) +{ + return reinterpret_cast + (getTorrentAttrs(dctx)->infoHash.data()); } std::string -getInfoHashString(const SharedHandle& downloadContext) +getInfoHashString(const SharedHandle& dctx) { - return util::toHex(downloadContext->getAttribute(BITTORRENT)[INFO_HASH].s()); + return util::toHex(getTorrentAttrs(dctx)->infoHash); } void print(std::ostream& o, const SharedHandle& dctx) { - const BDE& torrentAttrs = dctx->getAttribute(BITTORRENT); + SharedHandle torrentAttrs = getTorrentAttrs(dctx); o << "*** BitTorrent File Information ***" << "\n"; - if(torrentAttrs.containsKey(COMMENT)) { - o << "Comment: " << torrentAttrs[COMMENT].s() << "\n"; + if(!torrentAttrs->comment.empty()) { + o << "Comment: " << torrentAttrs->comment << "\n"; } - if(torrentAttrs.containsKey(CREATION_DATE)) { + if(torrentAttrs->creationDate) { struct tm* staticNowtmPtr; char buf[26]; - time_t t = torrentAttrs[CREATION_DATE].i(); + time_t t = torrentAttrs->creationDate; if((staticNowtmPtr = localtime(&t)) != 0 && asctime_r(staticNowtmPtr, buf) != 0) { // buf includes "\n" o << "Creation Date: " << buf; } } - if(torrentAttrs.containsKey(CREATED_BY)) { - o << "Created By: " << torrentAttrs[CREATED_BY].s() << "\n"; + if(!torrentAttrs->createdBy.empty()) { + o << "Created By: " << torrentAttrs->createdBy << "\n"; } - o << "Mode: " << torrentAttrs[MODE].s() << "\n"; + o << "Mode: " << torrentAttrs->mode << "\n"; o << "Announce:" << "\n"; - const BDE& announceList = torrentAttrs[ANNOUNCE_LIST]; - for(BDE::List::const_iterator tieritr = announceList.listBegin(), - eoi = announceList.listEnd(); tieritr != eoi; ++tieritr) { - if(!(*tieritr).isList()) { - continue; - } - for(BDE::List::const_iterator i = (*tieritr).listBegin(), - eoi2 = (*tieritr).listEnd(); i != eoi2; ++i) { - o << " " << (*i).s(); + for(std::vector >::const_iterator tierIter = + torrentAttrs->announceList.begin(), + eoi = torrentAttrs->announceList.end(); tierIter != eoi; ++tierIter) { + for(std::vector::const_iterator i = (*tierIter).begin(), + eoi2 = (*tierIter).end(); i != eoi2; ++i) { + o << " " << *i; } o << "\n"; } - o << "Info Hash: " << util::toHex(torrentAttrs[INFO_HASH].s()) << "\n"; - o << "Piece Length: " << util::abbrevSize(dctx->getPieceLength()) << "B\n"; - o << "The Number of Pieces: " << dctx->getNumPieces() << "\n"; - o << "Total Length: " << util::abbrevSize(dctx->getTotalLength()) << "B (" + o << "Info Hash: " + << util::toHex(torrentAttrs->infoHash) << "\n" + << "Piece Length: " + << util::abbrevSize(dctx->getPieceLength()) << "B\n" + << "The Number of Pieces: " + << dctx->getNumPieces() << "\n" + << "Total Length: " + << util::abbrevSize(dctx->getTotalLength()) << "B (" << util::uitos(dctx->getTotalLength(), true) << ")\n"; - if(!torrentAttrs[URL_LIST].empty()) { - const BDE& urlList = torrentAttrs[URL_LIST]; + if(!torrentAttrs->urlList.empty()) { o << "URL List: " << "\n"; - for(BDE::List::const_iterator i = urlList.listBegin(), - eoi = urlList.listEnd(); i != eoi; ++i) { - o << " " << (*i).s() << "\n"; + for(std::vector::const_iterator i = + torrentAttrs->urlList.begin(), + eoi = torrentAttrs->urlList.end(); i != eoi; ++i) { + o << " " << *i << "\n"; } } - o << "Name: " << torrentAttrs[NAME].s() << "\n"; - o << "Magnet URI: " << torrent2Magnet(torrentAttrs) << "\n"; - util::toStream(dctx->getFileEntries().begin(), dctx->getFileEntries().end(), o); + o << "Name: " << torrentAttrs->name << "\n" + << "Magnet URI: " << torrent2Magnet(torrentAttrs) << "\n"; + util::toStream + (dctx->getFileEntries().begin(), dctx->getFileEntries().end(), o); } void computeFastSet @@ -857,22 +907,23 @@ void assertID } } -BDE parseMagnet(const std::string& magnet) +SharedHandle parseMagnet(const std::string& magnet) { - BDE result; - BDE r = magnet::parse(magnet); - if(r.isNone()) { + SharedHandle r = magnet::parse(magnet); + if(r.isNull()) { throw DL_ABORT_EX("Bad BitTorrent Magnet URI."); } - if(!r.containsKey("xt")) { + const List* xts = asList(r->get("xt")); + if(!xts) { throw DL_ABORT_EX("Missing xt parameter in Magnet URI."); } + SharedHandle attrs(new TorrentAttribute()); std::string infoHash; - const BDE& xts = r["xt"]; - for(BDE::List::const_iterator xtiter = xts.listBegin(), - eoi = xts.listEnd(); xtiter != eoi && infoHash.empty(); ++xtiter) { - if(util::startsWith((*xtiter).s(), "urn:btih:")) { - std::string xtarg = (*xtiter).s().substr(9); + for(List::ValueType::const_iterator xtiter = xts->begin(), + eoi = xts->end(); xtiter != eoi && infoHash.empty(); ++xtiter) { + const String* xt = asString(*xtiter); + if(util::startsWith(xt->s(), "urn:btih:")) { + std::string xtarg = xt->s().substr(9); size_t size = xtarg.size(); if(size == 32) { std::string rawhash = base32::decode(xtarg); @@ -891,74 +942,82 @@ BDE parseMagnet(const std::string& magnet) throw DL_ABORT_EX("Bad BitTorrent Magnet URI. " "No valid BitTorrent Info Hash found."); } - BDE announceList = BDE::list(); - if(r.containsKey("tr")) { - const BDE& uris = r["tr"]; - for(BDE::List::const_iterator i = uris.listBegin(), eoi = uris.listEnd(); + const List* trs = asList(r->get("tr")); + if(trs) { + for(List::ValueType::const_iterator i = trs->begin(), eoi = trs->end(); i != eoi; ++i) { - BDE tier = BDE::list(); - tier << *i; - announceList << tier; + std::vector tier; + tier.push_back(asString(*i)->s()); + attrs->announceList.push_back(tier); } } std::string name = "[METADATA]"; - if(r.containsKey("dn") && r["dn"].size()) { - name += r["dn"][0].s(); + const List* dns = asList(r->get("dn")); + if(dns && !dns->empty()) { + const String* dn = asString(dns->get(0)); + name += dn->s(); } else { name += util::toHex(infoHash); } - BDE attrs = BDE::dict(); - attrs[INFO_HASH] = infoHash; - attrs[NAME] = name; - attrs[ANNOUNCE_LIST] = announceList; - result = attrs; - return result; + attrs->infoHash = infoHash; + attrs->name = name; + return attrs; } void loadMagnet (const std::string& magnet, const SharedHandle& dctx) { - BDE attrs = parseMagnet(magnet); + SharedHandle attrs = parseMagnet(magnet); dctx->setAttribute(BITTORRENT, attrs); } -std::string metadata2Torrent(const std::string& metadata, const BDE& attrs) +std::string metadata2Torrent +(const std::string& metadata, const SharedHandle& 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); + + List announceList; + for(std::vector >::const_iterator tierIter = + attrs->announceList.begin(), + eoi = attrs->announceList.end(); tierIter != eoi; ++tierIter) { + SharedHandle tier = List::g(); + for(std::vector::const_iterator uriIter = (*tierIter).begin(), + eoi2 = (*tierIter).end(); uriIter != eoi2; ++uriIter) { + tier->append(String::g(*uriIter)); } + if(!tier->empty()) { + announceList.append(tier); + } + } + if(!announceList.empty()) { + torrent += "13:announce-list"; + torrent += bencode2::encode(&announceList); } torrent += strconcat("4:info", metadata, "e"); return torrent; } -std::string torrent2Magnet(const BDE& attrs) +std::string torrent2Magnet(const SharedHandle& attrs) { std::string uri = "magnet:?"; - if(attrs.containsKey(INFO_HASH)) { + if(!attrs->infoHash.empty()) { uri += "xt=urn:btih:"; - uri += util::toUpper(util::toHex(attrs[INFO_HASH].s())); + uri += util::toUpper(util::toHex(attrs->infoHash)); } else { return A2STR::NIL; } - if(attrs.containsKey(NAME)) { + if(!attrs->name.empty()) { uri += "&dn="; - uri += util::percentEncode(attrs[NAME].s()); + uri += util::percentEncode(attrs->name); } - if(attrs.containsKey(ANNOUNCE_LIST)) { - const BDE& tiers = attrs[ANNOUNCE_LIST]; - for(BDE::List::const_iterator tieriter = tiers.listBegin(), - eoi = tiers.listEnd(); tieriter != eoi; ++tieriter) { - for(BDE::List::const_iterator uriiter = (*tieriter).listBegin(), - eoi2 = (*tieriter).listEnd(); uriiter != eoi2; ++uriiter) { - uri += "&tr="; - uri += util::percentEncode((*uriiter).s()); - } + for(std::vector >::const_iterator tierIter = + attrs->announceList.begin(), + eoi = attrs->announceList.end(); tierIter != eoi; ++tierIter) { + for(std::vector::const_iterator uriIter = (*tierIter).begin(), + eoi2 = (*tierIter).end(); uriIter != eoi2; ++uriIter) { + uri += "&tr="; + uri += util::percentEncode(*uriIter); } } return uri; diff --git a/src/bittorrent_helper.h b/src/bittorrent_helper.h index 0a7e4c19..3eacc438 100644 --- a/src/bittorrent_helper.h +++ b/src/bittorrent_helper.h @@ -43,8 +43,8 @@ #include "SharedHandle.h" #include "AnnounceTier.h" -#include "BDE.h" #include "util.h" +#include "TorrentAttribute.h" namespace aria2 { @@ -118,15 +118,16 @@ void loadFromMemory(const std::string& context, const std::string& defaultName, const std::string& overrideName = ""); -// 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. +// Parses BitTorrent Magnet URI and returns +// SharedHandle 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:&dn=&tr= // comes in 2 flavors: 40bytes hexadecimal ascii string, // or 32bytes Base32 encoded string. -BDE parseMagnet(const std::string& magnet); +SharedHandle parseMagnet(const std::string& magnet); // Parses BitTorrent Magnet URI and set them in ctx as a // bittorrent::BITTORRENT attibute. If parsing operation failed, an @@ -161,6 +162,9 @@ void computeFastSet // Writes the detailed information about torrent loaded in dctx. void print(std::ostream& o, const SharedHandle& dctx); +SharedHandle getTorrentAttrs +(const SharedHandle& dctx); + // Returns the value associated with INFO_HASH key in BITTORRENT // attribute. const unsigned char* @@ -227,14 +231,13 @@ void assertPayloadLengthEqual void assertID (uint8_t expected, const unsigned char* data, const std::string& msgName); -// 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); +// Converts attrs into torrent data. This function does not guarantee +// the returned string is valid torrent data. +std::string metadata2Torrent +(const std::string& metadata, const SharedHandle& attrs); -// Constructs BitTorrent Magnet URI using attrs. attrs must be a -// BDE::dict. -std::string torrent2Magnet(const BDE& attrs); +// Constructs BitTorrent Magnet URI using attrs. +std::string torrent2Magnet(const SharedHandle& attrs); } // namespace bittorrent diff --git a/src/download_helper.cc b/src/download_helper.cc index 571a317e..16a2de78 100644 --- a/src/download_helper.cc +++ b/src/download_helper.cc @@ -276,8 +276,9 @@ createBtMagnetRequestGroup(const std::string& magnetLink, rg->setFileAllocationEnabled(false); rg->setPreLocalFileCheckEnabled(false); bittorrent::loadMagnet(magnetLink, dctx); - dctx->getFirstFileEntry()->setPath - (dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s()); + SharedHandle torrentAttrs = + bittorrent::getTorrentAttrs(dctx); + dctx->getFirstFileEntry()->setPath(torrentAttrs->name); rg->setDownloadContext(dctx); rg->clearPostDownloadHandler(); rg->addPostDownloadHandler diff --git a/src/magnet.cc b/src/magnet.cc index 3118bf64..389a4c3f 100644 --- a/src/magnet.cc +++ b/src/magnet.cc @@ -39,31 +39,31 @@ namespace aria2 { namespace magnet { -BDE parse(const std::string& magnet) +SharedHandle parse(const std::string& magnet) { - BDE result; + SharedHandle dict; if(!util::startsWith(magnet, "magnet:?")) { - return result; + return dict; } + dict.reset(new Dict()); std::vector queries; util::split(std::string(magnet.begin()+8, magnet.end()), std::back_inserter(queries), "&"); - BDE dict = BDE::dict(); for(std::vector::const_iterator i = queries.begin(), eoi = queries.end(); i != eoi; ++i) { std::pair kv; util::split(kv, *i, '='); std::string value = util::percentDecode(kv.second); - if(dict.containsKey(kv.first)) { - dict[kv.first] << value; + List* l = asList(dict->get(kv.first)); + if(l) { + l->append(String::g(value)); } else { - BDE list = BDE::list(); - list << value; - dict[kv.first] = list; + SharedHandle l = List::g(); + l->append(String::g(value)); + dict->put(kv.first, l); } } - result = dict; - return result; + return dict; } } // namespace magnet diff --git a/src/magnet.h b/src/magnet.h index 4cf5d5e2..ea7cd2be 100644 --- a/src/magnet.h +++ b/src/magnet.h @@ -36,17 +36,18 @@ #define _D_MAGNET_H_ #include "common.h" -#include "BDE.h" +#include "ValueBase.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); +// Parses Magnet URI magnet and stores parameters in +// SharedHandle. Because same parameter name can appear more +// than once, the value associated with a key is SharedHandle. A +// parameter value is stored in a list. If parsing operation failed, +// SharedHandle() is returned. +SharedHandle parse(const std::string& magnet); } // namespace magnet diff --git a/test/AnnounceListTest.cc b/test/AnnounceListTest.cc index fd158f40..b0c76589 100644 --- a/test/AnnounceListTest.cc +++ b/test/AnnounceListTest.cc @@ -3,7 +3,7 @@ #include #include "Exception.h" -#include "bencode.h" +#include "bencode2.h" namespace aria2 { @@ -42,13 +42,31 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION( AnnounceListTest ); +static std::vector > toVector +(const List* announceList) +{ + std::vector > dest; + for(List::ValueType::const_iterator tierIter = announceList->begin(), + eoi = announceList->end(); tierIter != eoi; ++tierIter) { + std::vector ntier; + const List* tier = asList(*tierIter); + for(List::ValueType::const_iterator uriIter = tier->begin(), + eoi2 = tier->end(); uriIter != eoi2; ++uriIter) { + const String* uri = asString(*uriIter); + ntier.push_back(uri->s()); + } + dest.push_back(ntier); + } + return dest; +} + void AnnounceListTest::testSingleElementList() { std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); CPPUNIT_ASSERT(!announceList.allTiersFailed()); std::string url = announceList.getAnnounce(); @@ -90,11 +108,11 @@ void AnnounceListTest::testSingleElementList() { void AnnounceListTest::testMultiElementList() { std::string peersString = "ll8:tracker18:tracker28:tracker3ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1, tracker2, tracker3 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); CPPUNIT_ASSERT(!announceList.allTiersFailed()); std::string url = announceList.getAnnounce(); @@ -123,11 +141,11 @@ void AnnounceListTest::testMultiElementList() { void AnnounceListTest::testSingleAndMulti() { std::string peersString = "ll8:tracker18:tracker2el8:tracker3ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1, tracker2 ], [ tracker3 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); std::string url = announceList.getAnnounce(); CPPUNIT_ASSERT_EQUAL(std::string("tracker1"), url); @@ -149,20 +167,18 @@ void AnnounceListTest::testSingleAndMulti() { void AnnounceListTest::testNoGroup() { std::string peersString = "llee"; - const BDE announcesList = bencode::decode(peersString); - - AnnounceList announceList(announcesList); - + SharedHandle announcesList = bencode2::decode(peersString); + AnnounceList announceList(toVector(asList(announcesList))); CPPUNIT_ASSERT(announceList.countTier() == 0); } void AnnounceListTest::testNextEventIfAfterStarted() { std::string peersString = "ll8:tracker1ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); announceList.setEvent(AnnounceTier::STOPPED); announceList.announceFailure(); announceList.resetTier(); @@ -178,11 +194,11 @@ void AnnounceListTest::testNextEventIfAfterStarted() { void AnnounceListTest::testEvent() { std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); announceList.setEvent(AnnounceTier::STOPPED); announceList.announceSuccess(); @@ -202,11 +218,11 @@ void AnnounceListTest::testEvent() { void AnnounceListTest::testCountStoppedAllowedTier() { std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); CPPUNIT_ASSERT_EQUAL((size_t)0, announceList.countStoppedAllowedTier()); announceList.setEvent(AnnounceTier::STARTED); @@ -229,11 +245,11 @@ void AnnounceListTest::testCountStoppedAllowedTier() { void AnnounceListTest::testCountCompletedAllowedTier() { std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee"; - const BDE announcesList = bencode::decode(peersString); + SharedHandle announcesList = bencode2::decode(peersString); // ANNOUNCE_LIST // [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ] - AnnounceList announceList(announcesList); + AnnounceList announceList(toVector(asList(announcesList))); CPPUNIT_ASSERT_EQUAL((size_t)0, announceList.countCompletedAllowedTier()); announceList.setEvent(AnnounceTier::STARTED); diff --git a/test/Bencode2Test.cc b/test/Bencode2Test.cc new file mode 100644 index 00000000..9a4ee5b7 --- /dev/null +++ b/test/Bencode2Test.cc @@ -0,0 +1,206 @@ +#include "bencode2.h" + +#include + +#include "RecoverableException.h" + +namespace aria2 { + +class Bencode2Test:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(Bencode2Test); + CPPUNIT_TEST(testDecode); + CPPUNIT_TEST(testDecode_overflow); + CPPUNIT_TEST(testEncode); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void testDecode(); + void testDecode_overflow(); + void testEncode(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION( Bencode2Test ); + +void Bencode2Test::testDecode() +{ + { + // string, integer and list in dict + SharedHandle r = + bencode2::decode("d4:name5:aria24:sizei12345678900e5:filesl3:bin3:docee"); + const Dict* dict = asDict(r); + CPPUNIT_ASSERT(dict); + CPPUNIT_ASSERT_EQUAL(std::string("aria2"), + asString(dict->get("name"))->s()); + CPPUNIT_ASSERT_EQUAL(static_cast(12345678900LL), + asInteger(dict->get("size"))->i()); + const List* list = asList(dict->get("files")); + CPPUNIT_ASSERT(list); + CPPUNIT_ASSERT_EQUAL(static_cast(2), list->size()); + CPPUNIT_ASSERT_EQUAL(std::string("bin"), + asString(list->get(0))->s()); + CPPUNIT_ASSERT_EQUAL(std::string("doc"), + asString(list->get(1))->s()); + } + { + // dict in list + SharedHandle r = bencode2::decode("ld1:ki123eee"); + const List* list = asList(r); + CPPUNIT_ASSERT(list); + CPPUNIT_ASSERT_EQUAL(static_cast(1), list->size()); + const Dict* dict = asDict(list->get(0)); + CPPUNIT_ASSERT(dict); + CPPUNIT_ASSERT_EQUAL(static_cast(123), + asInteger(dict->get("k"))->i()); + } + { + // empty key is allowed + SharedHandle s = bencode2::decode("d0:1:ve"); + } + { + // empty string + SharedHandle s = bencode2::decode("0:"); + CPPUNIT_ASSERT_EQUAL(std::string(""), asString(s)->s()); + } + { + // empty dict + SharedHandle d = bencode2::decode("de"); + CPPUNIT_ASSERT(asDict(d)->empty()); + } + { + // empty list + SharedHandle l = bencode2::decode("le"); + CPPUNIT_ASSERT(asList(l)->empty()); + } + { + // integer, without ending 'e' + try { + bencode2::decode("i3"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:" + " Delimiter 'e' not found."), + std::string(e.what())); + } + } + { + // dict, without ending 'e' + try { + bencode2::decode("d"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:" + " Unexpected EOF in dict context." + " 'e' expected."), + std::string(e.what())); + } + } + { + // list, without ending 'e' + try { + bencode2::decode("l"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:" + " Unexpected EOF in list context." + " 'e' expected."), + std::string(e.what())); + } + } + { + // string, less than the specified length. + try { + bencode2::decode("3:ab"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:" + " Expected 3 bytes of data," + " but only 2 read."), + std::string(e.what())); + } + } + { + // string, but length is invalid + try { + bencode2::decode("x:abc"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:" + " A positive integer expected" + " but none found."), + std::string(e.what())); + } + } + { + // string with minus length + try { + bencode2::decode("-1:a"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:" + " A positive integer expected" + " but none found."), + std::string(e.what())); + } + } + { + // empty encoded data + CPPUNIT_ASSERT(bencode2::decode("").isNull()); + } + { + // ignore trailing garbage at the end of the input. + SharedHandle s = bencode2::decode("5:aria2trail"); + CPPUNIT_ASSERT_EQUAL(std::string("aria2"), asString(s)->s()); + } + { + // Get trailing garbage position + size_t end; + SharedHandle s = bencode2::decode("5:aria2trail", end); + CPPUNIT_ASSERT_EQUAL(std::string("aria2"), asString(s)->s()); + CPPUNIT_ASSERT_EQUAL((size_t)7, end); + } +} + +void Bencode2Test::testDecode_overflow() +{ + std::string s; + size_t depth = bencode2::MAX_STRUCTURE_DEPTH+1; + for(size_t i = 0; i < depth; ++i) { + s += "l"; + } + for(size_t i = 0; i < depth; ++i) { + s += "e"; + } + try { + bencode2::decode(s); + CPPUNIT_FAIL("exception must be thrown."); + } catch(RecoverableException& e) { + // success + } +} + +void Bencode2Test::testEncode() +{ + { + Dict dict; + dict["name"] = String::g("aria2"); + dict["loc"] = Integer::g(80000); + SharedHandle files = List::g(); + files->append(String::g("aria2c")); + dict["files"] = files; + SharedHandle attrs = Dict::g(); + attrs->put("license", String::g("GPL")); + dict["attrs"] = attrs; + + CPPUNIT_ASSERT_EQUAL(std::string("d" + "5:attrsd7:license3:GPLe" + "5:filesl6:aria2ce" + "3:loci80000e" + "4:name5:aria2" + "e"), + bencode2::encode(&dict)); + } +} + +} // namespace aria2 diff --git a/test/BencodeTest.cc b/test/BencodeTest.cc index e733498f..29a31b0e 100644 --- a/test/BencodeTest.cc +++ b/test/BencodeTest.cc @@ -1,8 +1,11 @@ #include "bencode.h" +#include + #include #include "RecoverableException.h" +#include "TimeA2.h" namespace aria2 { diff --git a/test/BittorrentHelperTest.cc b/test/BittorrentHelperTest.cc index 62b16259..4ed5430b 100644 --- a/test/BittorrentHelperTest.cc +++ b/test/BittorrentHelperTest.cc @@ -14,7 +14,7 @@ #include "array_fun.h" #include "messageDigest.h" #include "a2netcompat.h" -#include "bencode.h" +#include "bencode2.h" #include "TestUtil.h" #include "base32.h" @@ -111,26 +111,6 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION(BittorrentHelperTest); -static const BDE& getAnnounceList(const SharedHandle& dctx) -{ - return dctx->getAttribute(BITTORRENT)[ANNOUNCE_LIST]; -} - -static const std::string& getMode(const SharedHandle& dctx) -{ - return dctx->getAttribute(BITTORRENT)[MODE].s(); -} - -static const std::string& getName(const SharedHandle& dctx) -{ - return dctx->getAttribute(BITTORRENT)[NAME].s(); -} - -static const BDE& getNodes(const SharedHandle& dctx) -{ - return dctx->getAttribute(BITTORRENT)[NODES]; -} - void BittorrentHelperTest::testGetInfoHash() { SharedHandle dctx(new DownloadContext()); load("test.torrent", dctx); @@ -210,21 +190,21 @@ void BittorrentHelperTest::testGetFileModeMulti() { SharedHandle dctx(new DownloadContext()); load("test.torrent", dctx); - CPPUNIT_ASSERT_EQUAL(MULTI, getMode(dctx)); + CPPUNIT_ASSERT_EQUAL(MULTI, getTorrentAttrs(dctx)->mode); } void BittorrentHelperTest::testGetFileModeSingle() { SharedHandle dctx(new DownloadContext()); load("single.torrent", dctx); - CPPUNIT_ASSERT_EQUAL(SINGLE, getMode(dctx)); + CPPUNIT_ASSERT_EQUAL(SINGLE, getTorrentAttrs(dctx)->mode); } void BittorrentHelperTest::testGetNameMulti() { SharedHandle dctx(new DownloadContext()); load("test.torrent", dctx); - CPPUNIT_ASSERT_EQUAL(std::string("aria2-test"), getName(dctx)); + CPPUNIT_ASSERT_EQUAL(std::string("aria2-test"), getTorrentAttrs(dctx)->name); } void BittorrentHelperTest::testGetNameSingle() { @@ -233,7 +213,8 @@ void BittorrentHelperTest::testGetNameSingle() { CPPUNIT_ASSERT_EQUAL(std::string("./aria2-0.8.2.tar.bz2"), dctx->getBasePath()); - CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"), getName(dctx)); + CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"), + getTorrentAttrs(dctx)->name); } void BittorrentHelperTest::testOverrideName() @@ -242,46 +223,41 @@ void BittorrentHelperTest::testOverrideName() load("test.torrent", dctx, "aria2-override.name"); CPPUNIT_ASSERT_EQUAL(std::string("./aria2-override.name"), dctx->getBasePath()); - CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"), getName(dctx)); + CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"), + getTorrentAttrs(dctx)->name); } void BittorrentHelperTest::testGetAnnounceTier() { SharedHandle dctx(new DownloadContext()); load("single.torrent", dctx); - - const BDE& announceList = getAnnounceList(dctx); - + SharedHandle attrs = getTorrentAttrs(dctx); // There is 1 tier. - CPPUNIT_ASSERT_EQUAL((size_t)1, announceList.size()); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList.size()); - const BDE& tier = announceList[0]; - CPPUNIT_ASSERT_EQUAL((size_t)1, tier.size()); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[0].size()); CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.com/announce.php"), - tier[0].s()); - + attrs->announceList[0][0]); } void BittorrentHelperTest::testGetAnnounceTierAnnounceList() { SharedHandle dctx(new DownloadContext()); load("test.torrent", dctx); - - const BDE& announceList = getAnnounceList(dctx); - + SharedHandle attrs = getTorrentAttrs(dctx); // There are 3 tiers. - CPPUNIT_ASSERT_EQUAL((size_t)3, announceList.size()); + CPPUNIT_ASSERT_EQUAL((size_t)3, attrs->announceList.size()); - const BDE& tier1 = announceList[0]; - CPPUNIT_ASSERT_EQUAL((size_t)1, tier1.size()); - CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), tier1[0].s()); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[0].size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), + attrs->announceList[0][0]); - const BDE& tier2 = announceList[1]; - CPPUNIT_ASSERT_EQUAL((size_t)1, tier2.size()); - CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), tier2[0].s()); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[1].size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), + attrs->announceList[1][0]); - const BDE& tier3 = announceList[2]; - CPPUNIT_ASSERT_EQUAL((size_t)1, tier3.size()); - CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"), tier3[0].s()); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[2].size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"), + attrs->announceList[2][0]); } void BittorrentHelperTest::testGetPieceLength() { @@ -440,7 +416,8 @@ void BittorrentHelperTest::testLoadFromMemory_overrideName() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default", "aria2-override.name"); - CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"), getName(dctx)); + CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"), + getTorrentAttrs(dctx)->name); } void BittorrentHelperTest::testLoadFromMemory_multiFileDirTraversal() @@ -486,12 +463,12 @@ void BittorrentHelperTest::testGetNodes() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default"); - const BDE& nodes = getNodes(dctx); - CPPUNIT_ASSERT_EQUAL((size_t)2, nodes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), nodes[0][HOSTNAME].s()); - CPPUNIT_ASSERT_EQUAL((uint16_t)6881, (uint16_t)nodes[0][PORT].i()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[1][HOSTNAME].s()); - CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[1][PORT].i()); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT_EQUAL((size_t)2, attrs->nodes.size()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), attrs->nodes[0].first); + CPPUNIT_ASSERT_EQUAL((uint16_t)6881, attrs->nodes[0].second); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[1].first); + CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[1].second); } { // empty hostname @@ -506,10 +483,10 @@ void BittorrentHelperTest::testGetNodes() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default"); - const BDE& nodes = getNodes(dctx); - CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s()); - CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i()); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first); + CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second); } { // bad port @@ -524,10 +501,10 @@ void BittorrentHelperTest::testGetNodes() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default"); - const BDE& nodes = getNodes(dctx); - CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s()); - CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i()); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first); + CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second); } { // port missing @@ -542,10 +519,10 @@ void BittorrentHelperTest::testGetNodes() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default"); - const BDE& nodes = getNodes(dctx); - CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s()); - CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i()); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first); + CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second); } { // nodes is not a list @@ -559,7 +536,8 @@ void BittorrentHelperTest::testGetNodes() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default"); - CPPUNIT_ASSERT_EQUAL((size_t)0, getNodes(dctx).size()); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT_EQUAL((size_t)0, attrs->nodes.size()); } { // the element of node is not Data @@ -574,10 +552,10 @@ void BittorrentHelperTest::testGetNodes() SharedHandle dctx(new DownloadContext()); loadFromMemory(memory, dctx, "default"); - const BDE& nodes = getNodes(dctx); - CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s()); - CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i()); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first); + CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second); } } @@ -643,11 +621,12 @@ void BittorrentHelperTest::testUTF8Torrent() { SharedHandle dctx(new DownloadContext()); load("utf8.torrent", dctx); - CPPUNIT_ASSERT_EQUAL(std::string("name in utf-8"), getName(dctx)); + CPPUNIT_ASSERT_EQUAL(std::string("name in utf-8"), + getTorrentAttrs(dctx)->name); CPPUNIT_ASSERT_EQUAL(std::string("./name in utf-8/path in utf-8"), dctx->getFirstFileEntry()->getPath()); CPPUNIT_ASSERT_EQUAL(std::string("This is utf8 comment."), - dctx->getAttribute(BITTORRENT)[COMMENT].s()); + getTorrentAttrs(dctx)->comment); } void BittorrentHelperTest::testEtc() @@ -655,11 +634,11 @@ void BittorrentHelperTest::testEtc() SharedHandle dctx(new DownloadContext()); load("test.torrent", dctx); CPPUNIT_ASSERT_EQUAL(std::string("REDNOAH.COM RULES"), - dctx->getAttribute(BITTORRENT)[COMMENT].s()); + getTorrentAttrs(dctx)->comment); CPPUNIT_ASSERT_EQUAL(std::string("aria2"), - dctx->getAttribute(BITTORRENT)[CREATED_BY].s()); + getTorrentAttrs(dctx)->createdBy); CPPUNIT_ASSERT_EQUAL((int64_t)1123456789, - dctx->getAttribute(BITTORRENT)[CREATION_DATE].i()); + getTorrentAttrs(dctx)->creationDate); } void BittorrentHelperTest::testCreatecompact() @@ -698,13 +677,12 @@ void BittorrentHelperTest::testMetadata() { SharedHandle dctx(new DownloadContext()); load("test.torrent", dctx); std::string torrentData = readFile("test.torrent"); - BDE tr = bencode::decode(torrentData); - BDE infoDic = tr["info"]; - std::string metadata = bencode::encode(infoDic); - const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT); - CPPUNIT_ASSERT(metadata == attrs[bittorrent::METADATA].s()); - CPPUNIT_ASSERT_EQUAL(metadata.size(), - (size_t)attrs[bittorrent::METADATA_SIZE].i()); + SharedHandle tr = bencode2::decode(torrentData); + SharedHandle infoDic = asDict(tr)->get("info"); + std::string metadata = bencode2::encode(infoDic); + SharedHandle attrs = getTorrentAttrs(dctx); + CPPUNIT_ASSERT(metadata == attrs->metadata); + CPPUNIT_ASSERT_EQUAL(metadata.size(), attrs->metadataSize); } void BittorrentHelperTest::testParseMagnet() @@ -712,29 +690,28 @@ void BittorrentHelperTest::testParseMagnet() std::string magnet = "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2" "&tr=http://tracker1&tr=http://tracker2"; - BDE attrs = bittorrent::parseMagnet(magnet); + SharedHandle attrs = bittorrent::parseMagnet(magnet); CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"), - util::toHex(attrs[bittorrent::INFO_HASH].s())); - CPPUNIT_ASSERT_EQUAL(std::string("[METADATA]aria2"), - attrs[bittorrent::NAME].s()); - CPPUNIT_ASSERT_EQUAL((size_t)2, attrs[bittorrent::ANNOUNCE_LIST].size()); + util::toHex(attrs->infoHash)); + CPPUNIT_ASSERT_EQUAL(std::string("[METADATA]aria2"), attrs->name); + CPPUNIT_ASSERT_EQUAL((size_t)2, attrs->announceList.size()); CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), - attrs[bittorrent::ANNOUNCE_LIST][0][0].s()); + attrs->announceList[0][0]); CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), - attrs[bittorrent::ANNOUNCE_LIST][1][0].s()); + attrs->announceList[1][0]); magnet = "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"; attrs = bittorrent::parseMagnet(magnet); CPPUNIT_ASSERT_EQUAL (std::string("[METADATA]248d0a1cd08284299de78d5c1ed359bb46717d8c"), - attrs[bittorrent::NAME].s()); - CPPUNIT_ASSERT(attrs[bittorrent::ANNOUNCE_LIST].size() == 0); + attrs->name); + CPPUNIT_ASSERT(attrs->announceList.empty()); magnet = "magnet:?xt=urn:sha1:7899bdb90a026c746f3cbc10839dd9b2a2a3e985&" "xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"; attrs = bittorrent::parseMagnet(magnet); CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"), - util::toHex(attrs[bittorrent::INFO_HASH].s())); + util::toHex(attrs->infoHash)); } void BittorrentHelperTest::testParseMagnet_base32() @@ -742,22 +719,20 @@ void BittorrentHelperTest::testParseMagnet_base32() std::string infoHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c"; std::string base32InfoHash = base32::encode(util::fromHex(infoHash)); std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2"; - BDE attrs = bittorrent::parseMagnet(magnet); + SharedHandle attrs = bittorrent::parseMagnet(magnet); CPPUNIT_ASSERT_EQUAL (std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"), - util::toHex(attrs[bittorrent::INFO_HASH].s())); + util::toHex(attrs->infoHash)); } void BittorrentHelperTest::testMetadata2Torrent() { std::string metadata = "METADATA"; - BDE attrs = BDE::dict(); - BDE announceList = BDE::list(); - attrs[ANNOUNCE_LIST] = announceList; + SharedHandle attrs(new TorrentAttribute()); CPPUNIT_ASSERT_EQUAL (std::string("d4:infoMETADATAe"), metadata2Torrent(metadata, attrs)); - announceList << BDE::list(); - announceList[0] << std::string("http://localhost/announce"); + attrs->announceList.push_back(std::vector()); + attrs->announceList[0].push_back("http://localhost/announce"); CPPUNIT_ASSERT_EQUAL (std::string("d" "13:announce-list" @@ -778,7 +753,7 @@ void BittorrentHelperTest::testTorrent2Magnet() "&tr=http%3A%2F%2Ftracker1" "&tr=http%3A%2F%2Ftracker2" "&tr=http%3A%2F%2Ftracker3"), - torrent2Magnet(dctx->getAttribute(BITTORRENT))); + torrent2Magnet(getTorrentAttrs(dctx))); } } // namespace bittorrent diff --git a/test/BtDependencyTest.cc b/test/BtDependencyTest.cc index 22e8a823..35abb018 100644 --- a/test/BtDependencyTest.cc +++ b/test/BtDependencyTest.cc @@ -179,7 +179,7 @@ void BtDependencyTest::testResolve_metadata() pieceStorage->setDiskAdaptor(diskAdaptor); pieceStorage->setDownloadFinished(true); dependee->setPieceStorage(pieceStorage); - BDE attrs = BDE::dict(); + SharedHandle attrs(new TorrentAttribute()); dependee->getDownloadContext()->setAttribute(bittorrent::BITTORRENT, attrs); BtDependency dep(dependant, dependee); diff --git a/test/BtRegistryTest.cc b/test/BtRegistryTest.cc index 7ddfd63c..a2b7b392 100644 --- a/test/BtRegistryTest.cc +++ b/test/BtRegistryTest.cc @@ -63,10 +63,10 @@ void BtRegistryTest::testGetDownloadContext_infoHash() { BtRegistry btRegistry; addTwoDownloadContext(btRegistry); - BDE attrs1 = BDE::dict(); - attrs1[bittorrent::INFO_HASH] = std::string("hash1"); - BDE attrs2 = BDE::dict(); - attrs2[bittorrent::INFO_HASH] = std::string("hash2"); + SharedHandle attrs1(new TorrentAttribute()); + attrs1->infoHash = "hash1"; + SharedHandle attrs2(new TorrentAttribute()); + attrs2->infoHash = "hash2"; btRegistry.getDownloadContext(1)->setAttribute (bittorrent::BITTORRENT, attrs1); btRegistry.getDownloadContext(2)->setAttribute diff --git a/test/DefaultBtAnnounceTest.cc b/test/DefaultBtAnnounceTest.cc index ff712ce7..c39aa451 100644 --- a/test/DefaultBtAnnounceTest.cc +++ b/test/DefaultBtAnnounceTest.cc @@ -56,9 +56,8 @@ public: std::string peerId = "-aria2-ultrafastdltl"; _dctx.reset(new DownloadContext(pieceLength, totalLength)); - BDE torrentAttrs = BDE::dict(); - torrentAttrs[bittorrent::INFO_HASH] = - std::string(vbegin(infoHash), vend(infoHash)); + SharedHandle torrentAttrs(new TorrentAttribute()); + torrentAttrs->infoHash = std::string(vbegin(infoHash), vend(infoHash)); _dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs); bittorrent::setStaticPeerId(peerId); @@ -97,34 +96,46 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtAnnounceTest); template -static BDE createAnnounceTier(InputIterator first, InputIterator last) +static SharedHandle createAnnounceTier +(InputIterator first, InputIterator last) { - BDE announceTier = BDE::list(); + SharedHandle announceTier = List::g(); for(; first != last; ++first) { - announceTier << BDE(*first); + announceTier->append(String::g(*first)); } return announceTier; } -static BDE createAnnounceTier(const std::string& uri) +static SharedHandle createAnnounceTier(const std::string& uri) { - BDE announceTier = BDE::list(); - announceTier << uri; + SharedHandle announceTier = List::g(); + announceTier->append(String::g(uri)); return announceTier; } static void setAnnounceList(const SharedHandle& dctx, - const BDE& announceList) + const SharedHandle& announceList) { - dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST] = - announceList; + std::vector > dest; + for(List::ValueType::const_iterator tierIter = announceList->begin(), + eoi = announceList->end(); tierIter != eoi; ++tierIter) { + std::vector ntier; + const List* tier = asList(*tierIter); + for(List::ValueType::const_iterator uriIter = tier->begin(), + eoi2 = tier->end(); uriIter != eoi2; ++uriIter) { + const String* uri = asString(*uriIter); + ntier.push_back(uri->s()); + } + dest.push_back(ntier); + } + bittorrent::getTorrentAttrs(dctx)->announceList.swap(dest); } void DefaultBtAnnounceTest::testNoMoreAnnounce() { - BDE announceList = BDE::list(); - announceList << createAnnounceTier("http://localhost/announce"); - announceList << createAnnounceTier("http://backup/announce"); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier("http://localhost/announce")); + announceList->append(createAnnounceTier("http://backup/announce")); setAnnounceList(_dctx, announceList); @@ -172,8 +183,8 @@ void DefaultBtAnnounceTest::testNoMoreAnnounce() void DefaultBtAnnounceTest::testGetAnnounceUrl() { - BDE announceList = BDE::list(); - announceList << createAnnounceTier("http://localhost/announce"); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier("http://localhost/announce")); setAnnounceList(_dctx, announceList); DefaultBtAnnounce btAnnounce(_dctx, _option); @@ -203,8 +214,8 @@ void DefaultBtAnnounceTest::testGetAnnounceUrl() void DefaultBtAnnounceTest::testGetAnnounceUrl_withQuery() { - BDE announceList = BDE::list(); - announceList << createAnnounceTier("http://localhost/announce?k=v"); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier("http://localhost/announce?k=v")); setAnnounceList(_dctx, announceList); DefaultBtAnnounce btAnnounce(_dctx, _option); @@ -225,8 +236,8 @@ void DefaultBtAnnounceTest::testGetAnnounceUrl_withQuery() void DefaultBtAnnounceTest::testGetAnnounceUrl_externalIP() { - BDE announceList = BDE::list(); - announceList << createAnnounceTier("http://localhost/announce"); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier("http://localhost/announce")); setAnnounceList(_dctx, announceList); _option->put(PREF_BT_EXTERNAL_IP, "192.168.1.1"); @@ -248,9 +259,9 @@ void DefaultBtAnnounceTest::testGetAnnounceUrl_externalIP() void DefaultBtAnnounceTest::testIsAllAnnounceFailed() { - BDE announceList = BDE::list(); - announceList << createAnnounceTier("http://localhost/announce"); - announceList << createAnnounceTier("http://backup/announce"); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier("http://localhost/announce")); + announceList->append(createAnnounceTier("http://backup/announce")); setAnnounceList(_dctx, announceList); DefaultBtAnnounce btAnnounce(_dctx, _option); @@ -281,8 +292,8 @@ void DefaultBtAnnounceTest::testURLOrderInStoppedEvent() const char* urls[] = { "http://localhost1/announce", "http://localhost2/announce" }; - BDE announceList = BDE::list(); - announceList << createAnnounceTier(vbegin(urls), vend(urls)); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier(vbegin(urls), vend(urls))); setAnnounceList(_dctx, announceList); DefaultBtAnnounce btAnnounce(_dctx, _option); @@ -311,8 +322,8 @@ void DefaultBtAnnounceTest::testURLOrderInCompletedEvent() const char* urls[] = { "http://localhost1/announce", "http://localhost2/announce" }; - BDE announceList = BDE::list(); - announceList << createAnnounceTier(vbegin(urls), vend(urls)); + SharedHandle announceList = List::g(); + announceList->append(createAnnounceTier(vbegin(urls), vend(urls))); setAnnounceList(_dctx, announceList); DefaultBtAnnounce btAnnounce(_dctx, _option); diff --git a/test/DefaultBtProgressInfoFileTest.cc b/test/DefaultBtProgressInfoFileTest.cc index dcf49f32..85aafe12 100644 --- a/test/DefaultBtProgressInfoFileTest.cc +++ b/test/DefaultBtProgressInfoFileTest.cc @@ -70,9 +70,8 @@ public: }; _dctx.reset(new DownloadContext()); - BDE torrentAttrs = BDE::dict(); - torrentAttrs[bittorrent::INFO_HASH] = - std::string(vbegin(infoHash), vend(infoHash)); + SharedHandle torrentAttrs(new TorrentAttribute()); + torrentAttrs->infoHash = std::string(vbegin(infoHash), vend(infoHash)); _dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs); _dctx->setDir(_option->get(PREF_DIR)); const SharedHandle fileEntries[] = { diff --git a/test/HandshakeExtensionMessageTest.cc b/test/HandshakeExtensionMessageTest.cc index 26fb616e..d00d1964 100644 --- a/test/HandshakeExtensionMessageTest.cc +++ b/test/HandshakeExtensionMessageTest.cc @@ -96,7 +96,7 @@ void HandshakeExtensionMessageTest::testDoReceivedAction() RequestGroup rg(op); rg.setDownloadContext(dctx); - BDE attrs = BDE::dict(); + SharedHandle attrs(new TorrentAttribute()); dctx->setAttribute(bittorrent::BITTORRENT, attrs); dctx->markTotalLengthIsUnknown(); @@ -117,7 +117,7 @@ void HandshakeExtensionMessageTest::testDoReceivedAction() CPPUNIT_ASSERT_EQUAL((uint16_t)6889, peer->getPort()); CPPUNIT_ASSERT_EQUAL((uint8_t)1, peer->getExtensionMessageID("ut_pex")); CPPUNIT_ASSERT_EQUAL((uint8_t)2, peer->getExtensionMessageID("a2_dht")); - CPPUNIT_ASSERT_EQUAL((int64_t)1024, attrs[bittorrent::METADATA_SIZE].i()); + CPPUNIT_ASSERT_EQUAL((size_t)1024, attrs->metadataSize); CPPUNIT_ASSERT_EQUAL((uint64_t)1024, dctx->getTotalLength()); CPPUNIT_ASSERT(dctx->knowsTotalLength()); } diff --git a/test/MSEHandshakeTest.cc b/test/MSEHandshakeTest.cc index 3ec8ab51..82ec7cd1 100644 --- a/test/MSEHandshakeTest.cc +++ b/test/MSEHandshakeTest.cc @@ -33,9 +33,8 @@ public: _dctx.reset(new DownloadContext()); unsigned char infoHash[20]; memset(infoHash, 0, sizeof(infoHash)); - BDE torrentAttrs = BDE::dict(); - torrentAttrs[bittorrent::INFO_HASH] = - std::string(vbegin(infoHash), vend(infoHash)); + SharedHandle torrentAttrs(new TorrentAttribute()); + torrentAttrs->infoHash = std::string(vbegin(infoHash), vend(infoHash)); _dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs); } diff --git a/test/MagnetTest.cc b/test/MagnetTest.cc index 84bd7e0f..4e4eb093 100644 --- a/test/MagnetTest.cc +++ b/test/MagnetTest.cc @@ -20,19 +20,23 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION(MagnetTest); +static const std::string& nthStr(const SharedHandle& v, size_t index) +{ + return asString(asList(v)->get(index))->s(); +} + void MagnetTest::testParse() { - BDE r = parse + SharedHandle r = parse ("magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2" "&tr=http%3A%2F%2Ftracker1&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()); + nthStr(r->get("xt"), 0)); + CPPUNIT_ASSERT_EQUAL(std::string("aria2"), nthStr(r->get("dn"), 0)); + CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), nthStr(r->get("tr"), 0)); + CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), nthStr(r->get("tr"), 1)); + CPPUNIT_ASSERT(parse("http://localhost").isNull()); } } // namespace magnet diff --git a/test/Makefile.am b/test/Makefile.am index 93115835..f9f26271 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -72,7 +72,9 @@ aria2c_SOURCES = AllTest.cc\ bitfieldTest.cc\ BDETest.cc\ DownloadContextTest.cc\ - SessionSerializerTest.cc + SessionSerializerTest.cc\ + ValueBaseTest.cc\ + Bencode2Test.cc if ENABLE_XML_RPC aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index f7097c9c..e0d510f5 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -214,6 +214,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \ a2algoTest.cc bitfieldTest.cc BDETest.cc \ DownloadContextTest.cc SessionSerializerTest.cc \ + ValueBaseTest.cc Bencode2Test.cc \ XmlRpcRequestParserControllerTest.cc \ XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \ FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \ @@ -408,6 +409,7 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \ LongestSequencePieceSelectorTest.$(OBJEXT) \ a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) BDETest.$(OBJEXT) \ DownloadContextTest.$(OBJEXT) SessionSerializerTest.$(OBJEXT) \ + ValueBaseTest.$(OBJEXT) Bencode2Test.$(OBJEXT) \ $(am__objects_1) $(am__objects_2) $(am__objects_3) \ $(am__objects_4) $(am__objects_5) $(am__objects_6) \ $(am__objects_7) @@ -644,9 +646,9 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \ InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \ a2algoTest.cc bitfieldTest.cc BDETest.cc \ DownloadContextTest.cc SessionSerializerTest.cc \ - $(am__append_1) $(am__append_2) $(am__append_3) \ - $(am__append_4) $(am__append_5) $(am__append_6) \ - $(am__append_7) + ValueBaseTest.cc Bencode2Test.cc $(am__append_1) \ + $(am__append_2) $(am__append_3) $(am__append_4) \ + $(am__append_5) $(am__append_6) $(am__append_7) #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} @@ -752,6 +754,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BNodeTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base32Test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Bencode2Test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BencodeTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BittorrentHelperTest.Po@am__quote@ @@ -899,6 +902,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ValueBaseTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XORCloserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcMethodTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcRequestParserControllerTest.Po@am__quote@ diff --git a/test/RequestGroupManTest.cc b/test/RequestGroupManTest.cc index dff34341..f56db40f 100644 --- a/test/RequestGroupManTest.cc +++ b/test/RequestGroupManTest.cc @@ -14,6 +14,7 @@ #include "ServerStat.h" #include "File.h" #include "array_fun.h" +#include "RecoverableException.h" namespace aria2 { diff --git a/test/UTMetadataDataExtensionMessageTest.cc b/test/UTMetadataDataExtensionMessageTest.cc index 4e8ac012..51372102 100644 --- a/test/UTMetadataDataExtensionMessageTest.cc +++ b/test/UTMetadataDataExtensionMessageTest.cc @@ -73,7 +73,7 @@ void UTMetadataDataExtensionMessageTest::testDoReceivedAction() SharedHandle tracker (new UTMetadataRequestTracker()); SharedHandle dctx(new DownloadContext()); - BDE attrs = BDE::dict(); + SharedHandle attrs(new TorrentAttribute()); std::string piece0 = std::string(METADATA_PIECE_SIZE, '0'); std::string piece1 = std::string(METADATA_PIECE_SIZE, '1'); @@ -83,8 +83,7 @@ void UTMetadataDataExtensionMessageTest::testDoReceivedAction() MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH, MessageDigestContext::SHA1, metadata.data(), metadata.size()); - attrs[bittorrent::INFO_HASH] = std::string(&infoHash[0], &infoHash[20]); - + attrs->infoHash = std::string(&infoHash[0], &infoHash[20]); dctx->setAttribute(bittorrent::BITTORRENT, attrs); UTMetadataDataExtensionMessage m(1); diff --git a/test/UTMetadataPostDownloadHandlerTest.cc b/test/UTMetadataPostDownloadHandlerTest.cc index f5148efe..4775d02f 100644 --- a/test/UTMetadataPostDownloadHandlerTest.cc +++ b/test/UTMetadataPostDownloadHandlerTest.cc @@ -51,13 +51,13 @@ void UTMetadataPostDownloadHandlerTest::testCanHandle() CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get())); - BDE attrs = BDE::dict(); + SharedHandle attrs(new TorrentAttribute()); _dctx->setAttribute(bittorrent::BITTORRENT, attrs); CPPUNIT_ASSERT(handler.canHandle(_requestGroup.get())); - // Only checks existence of METADATA key - attrs[bittorrent::METADATA] = A2STR::NIL; + // Only checks whether metadata is empty or not + attrs->metadata = "metadata"; CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get())); } @@ -76,12 +76,13 @@ void UTMetadataPostDownloadHandlerTest::testGetNextRequestGroups() (infoHash, sizeof(infoHash), MessageDigestContext::SHA1, reinterpret_cast(metadata.data()), metadata.size()); _dctx->getFirstFileEntry()->setLength(metadata.size()); - BDE attrs = BDE::dict(); - attrs[bittorrent::INFO_HASH] = std::string(&infoHash[0], &infoHash[20]); - BDE announceList = BDE::list(); - announceList << BDE::list(); - announceList[0] << std::string("http://tracker"); - attrs[bittorrent::ANNOUNCE_LIST] = announceList; + SharedHandle attrs(new TorrentAttribute()); + attrs->infoHash = std::string(&infoHash[0], &infoHash[20]); + std::vector > announceList; + std::vector announceTier; + announceTier.push_back("http://tracker"); + announceList.push_back(announceTier); + attrs->announceList = announceList; _dctx->setAttribute(bittorrent::BITTORRENT, attrs); _requestGroup->setDiskWriterFactory (SharedHandle(new ByteArrayDiskWriterFactory())); @@ -97,13 +98,14 @@ void UTMetadataPostDownloadHandlerTest::testGetNextRequestGroups() CPPUNIT_ASSERT_EQUAL((size_t)1, results.size()); SharedHandle newRg = results.front(); SharedHandle newDctx = newRg->getDownloadContext(); - const BDE& newAttrs = newDctx->getAttribute(bittorrent::BITTORRENT); - CPPUNIT_ASSERT_EQUAL(util::toHex(attrs[bittorrent::INFO_HASH].s()), - util::toHex(newAttrs[bittorrent::INFO_HASH].s())); - CPPUNIT_ASSERT(newAttrs.containsKey(bittorrent::ANNOUNCE_LIST)); - CPPUNIT_ASSERT_EQUAL((size_t)1, newAttrs[bittorrent::ANNOUNCE_LIST].size()); - CPPUNIT_ASSERT_EQUAL(std::string("http://tracker"), - newAttrs[bittorrent::ANNOUNCE_LIST][0][0].s()); + SharedHandle newAttrs = + bittorrent::getTorrentAttrs(newDctx); + CPPUNIT_ASSERT_EQUAL(bittorrent::getInfoHashString(_dctx), + bittorrent::getInfoHashString(newDctx)); + const std::vector >& newAnnounceList = + newAttrs->announceList; + CPPUNIT_ASSERT_EQUAL((size_t)1, newAnnounceList.size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://tracker"), newAnnounceList[0][0]); CPPUNIT_ASSERT_EQUAL(_option->get("Hello"), newRg->getOption()->get("Hello")); CPPUNIT_ASSERT diff --git a/test/UTMetadataRequestExtensionMessageTest.cc b/test/UTMetadataRequestExtensionMessageTest.cc index be476229..31c2ec69 100644 --- a/test/UTMetadataRequestExtensionMessageTest.cc +++ b/test/UTMetadataRequestExtensionMessageTest.cc @@ -15,6 +15,7 @@ #include "UTMetadataDataExtensionMessage.h" #include "PieceStorage.h" #include "extension_message_test_helper.h" +#include "DlAbortEx.h" namespace aria2 { @@ -39,7 +40,7 @@ public: _messageFactory.reset(new WrapExtBtMessageFactory()); _dispatcher.reset(new MockBtMessageDispatcher()); _dctx.reset(new DownloadContext()); - BDE attrs = BDE::dict(); + SharedHandle attrs(new TorrentAttribute()); _dctx->setAttribute(bittorrent::BITTORRENT, attrs); _peer.reset(new Peer("host", 6880)); _peer->allocateSessionResource(0, 0); @@ -124,11 +125,11 @@ void UTMetadataRequestExtensionMessageTest::testDoReceivedAction_data() msg.setBtMessageDispatcher(_dispatcher); size_t metadataSize = METADATA_PIECE_SIZE*2; - BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); + SharedHandle attrs = bittorrent::getTorrentAttrs(_dctx); std::string first(METADATA_PIECE_SIZE, '0'); std::string second(METADATA_PIECE_SIZE, '1'); - attrs[bittorrent::METADATA] = first+second; - attrs[bittorrent::METADATA_SIZE] = metadataSize; + attrs->metadata = first+second; + attrs->metadataSize = metadataSize; msg.doReceivedAction(); @@ -147,8 +148,8 @@ void UTMetadataRequestExtensionMessageTest::testDoReceivedAction_data() metadataSize += 100; std::string third(100, '2'); - attrs[bittorrent::METADATA] = attrs[bittorrent::METADATA].s()+third; - attrs[bittorrent::METADATA_SIZE] = metadataSize; + attrs->metadata = first+second+third; + attrs->metadataSize = metadataSize; msg.doReceivedAction(); diff --git a/test/ValueBaseTest.cc b/test/ValueBaseTest.cc new file mode 100644 index 00000000..c55ce69d --- /dev/null +++ b/test/ValueBaseTest.cc @@ -0,0 +1,182 @@ +#include "ValueBase.h" + +#include +#include + +#include + +#include "Exception.h" +#include "util.h" + +namespace aria2 { + +class ValueBaseTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(ValueBaseTest); + CPPUNIT_TEST(testString); + CPPUNIT_TEST(testDict); + CPPUNIT_TEST(testDictIter); + CPPUNIT_TEST(testList); + CPPUNIT_TEST(testListIter); + CPPUNIT_TEST(testDowncast); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp() {} + + void tearDown() {} + + void testString(); + void testDict(); + void testDictIter(); + void testList(); + void testListIter(); + void testDowncast(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(ValueBaseTest); + +void ValueBaseTest::testString() +{ + String s(std::string("aria2")); + CPPUNIT_ASSERT_EQUAL(std::string("aria2"), s.s()); + + unsigned char dataWithNull[] = { 0xf0, '\0', 0x0f }; + String sWithNull(dataWithNull, sizeof(dataWithNull)); + CPPUNIT_ASSERT(memcmp(dataWithNull, sWithNull.s().c_str(), + sizeof(dataWithNull)) == 0); + + String zero(""); + CPPUNIT_ASSERT_EQUAL(std::string(""), zero.s()); + + String z; + CPPUNIT_ASSERT_EQUAL(std::string(""), z.s()); + + const unsigned char uc[] = { 0x08, 0x19, 0x2a, 0x3b }; + String data(uc, sizeof(uc)); + CPPUNIT_ASSERT_EQUAL(util::toHex(uc, sizeof(uc)), + util::toHex(data.uc(), data.s().size())); +} + +void ValueBaseTest::testDowncast() +{ + Integer integer(100); + const Integer* x = asInteger(&integer); + CPPUNIT_ASSERT(x); + CPPUNIT_ASSERT_EQUAL(static_cast(100), x->i()); + SharedHandle si(new Integer(101)); + const Integer* x2 = asInteger(si); + CPPUNIT_ASSERT_EQUAL(static_cast(101), x2->i()); + + String str("foo"); + const String* x3 = asString(&str); + CPPUNIT_ASSERT_EQUAL(static_cast("foo"), x3->s()); + + List list; + const List* x4 = asList(&list); + CPPUNIT_ASSERT(x4); + + Dict dict; + const Dict* x5 = asDict(&dict); + CPPUNIT_ASSERT(x5); +} + +void ValueBaseTest::testDict() +{ + Dict dict; + CPPUNIT_ASSERT(dict.empty()); + + dict["ki"] = Integer::g(7); + dict["ks"] = String::g("abc"); + + CPPUNIT_ASSERT_EQUAL(static_cast(2), dict.size()); + CPPUNIT_ASSERT(dict.containsKey("ki")); + CPPUNIT_ASSERT_EQUAL(static_cast(7), + asInteger(dict["ki"])->i()); + CPPUNIT_ASSERT(dict.containsKey("ks")); + CPPUNIT_ASSERT_EQUAL(std::string("abc"), + asString(dict["ks"])->s()); + + CPPUNIT_ASSERT(dict["kn"].isNull()); // This adds kn key with default value. + CPPUNIT_ASSERT_EQUAL(static_cast(3), dict.size()); + CPPUNIT_ASSERT(dict.containsKey("kn")); + + const Dict& ref = dict; + ref["kn2"]; // This doesn't add kn2 key. + CPPUNIT_ASSERT_EQUAL(static_cast(3), ref.size()); + CPPUNIT_ASSERT(!ref.containsKey("kn2")); + + dict.removeKey("kn"); + CPPUNIT_ASSERT_EQUAL(static_cast(2), dict.size()); + CPPUNIT_ASSERT(!dict.containsKey("kn")); +} + +void ValueBaseTest::testDictIter() +{ + Dict dict; + dict["alpha2"] = String::g("alpha2"); + dict["charlie"] = String::g("charlie"); + dict["bravo"] = String::g("bravo"); + dict["alpha"] = String::g("alpha"); + + Dict::ValueType::iterator i = dict.begin(); + CPPUNIT_ASSERT_EQUAL(std::string("alpha"), (*i++).first); + CPPUNIT_ASSERT_EQUAL(std::string("alpha2"), (*i++).first); + CPPUNIT_ASSERT_EQUAL(std::string("bravo"), (*i++).first); + CPPUNIT_ASSERT_EQUAL(std::string("charlie"), (*i++).first); + CPPUNIT_ASSERT(dict.end() == i); + + const Dict& ref = dict; + Dict::ValueType::const_iterator ci = ref.begin(); + CPPUNIT_ASSERT_EQUAL(std::string("alpha"), (*ci++).first); + std::advance(ci, 3); + CPPUNIT_ASSERT(ref.end() == ci); +} + +void ValueBaseTest::testList() +{ + List list; + CPPUNIT_ASSERT(list.empty()); + list << Integer::g(7) << String::g("aria2"); + + CPPUNIT_ASSERT_EQUAL(static_cast(2), list.size()); + CPPUNIT_ASSERT_EQUAL(static_cast(7), + asInteger(list[0])->i()); + CPPUNIT_ASSERT_EQUAL(static_cast("aria2"), + asString(list[1])->s()); + + const List& ref = list; + CPPUNIT_ASSERT_EQUAL(static_cast(7), + asInteger(ref[0])->i()); + CPPUNIT_ASSERT_EQUAL(static_cast("aria2"), + asString(ref[1])->s()); +} + +void ValueBaseTest::testListIter() +{ + List list; + list << String::g("alpha2") + << String::g("charlie") + << String::g("bravo") + << String::g("alpha"); + + List::ValueType::iterator i = list.begin(); + CPPUNIT_ASSERT_EQUAL(static_cast("alpha2"), + asString(*i++)->s()); + CPPUNIT_ASSERT_EQUAL(static_cast("charlie"), + asString(*i++)->s()); + CPPUNIT_ASSERT_EQUAL(static_cast("bravo"), + asString(*i++)->s()); + CPPUNIT_ASSERT_EQUAL(static_cast("alpha"), + asString(*i++)->s()); + CPPUNIT_ASSERT(list.end() == i); + + const List& ref = list; + List::ValueType::const_iterator ci = ref.begin(); + CPPUNIT_ASSERT_EQUAL(static_cast("alpha2"), + asString(*ci++)->s()); + std::advance(ci, 3); + CPPUNIT_ASSERT(ref.end() == ci); +} + +} // namespace aria2 diff --git a/test/XmlRpcMethodTest.cc b/test/XmlRpcMethodTest.cc index f7af3868..1ee7db01 100644 --- a/test/XmlRpcMethodTest.cc +++ b/test/XmlRpcMethodTest.cc @@ -745,7 +745,7 @@ void XmlRpcMethodTest::testGatherBitTorrentMetadata() SharedHandle dctx(new DownloadContext()); bittorrent::load("test.torrent", dctx); BDE btDict = BDE::dict(); - gatherBitTorrentMetadata(btDict, dctx->getAttribute(bittorrent::BITTORRENT)); + gatherBitTorrentMetadata(btDict, bittorrent::getTorrentAttrs(dctx)); CPPUNIT_ASSERT_EQUAL(std::string("REDNOAH.COM RULES"), btDict["comment"].s()); CPPUNIT_ASSERT_EQUAL((int64_t)1123456789, btDict["creationDate"].i()); CPPUNIT_ASSERT_EQUAL(std::string("multi"), btDict["mode"].s()); @@ -756,11 +756,11 @@ void XmlRpcMethodTest::testGatherBitTorrentMetadata() CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), announceList[1][0].s()); CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"), announceList[2][0].s()); // Remove some keys - BDE modBtAttrs = dctx->getAttribute(bittorrent::BITTORRENT); - modBtAttrs.removeKey(bittorrent::COMMENT); - modBtAttrs.removeKey(bittorrent::CREATION_DATE); - modBtAttrs.removeKey(bittorrent::MODE); - modBtAttrs.removeKey(bittorrent::METADATA); + SharedHandle modBtAttrs = bittorrent::getTorrentAttrs(dctx); + modBtAttrs->comment.clear(); + modBtAttrs->creationDate = 0; + modBtAttrs->mode.clear(); + modBtAttrs->metadata.clear(); btDict = BDE::dict(); gatherBitTorrentMetadata(btDict, modBtAttrs); CPPUNIT_ASSERT(!btDict.containsKey("comment"));