From fca7b9d7e42e8b85838512d41136af7702b52c9b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 12 Dec 2007 13:53:33 +0000 Subject: [PATCH] 2007-12-12 Tatsuhiro Tsujikawa If several protocols are available for a mirror, aria2 now use one of them. --metalink-preferred-protocol option was added to specify the preference of protocol. * src/AbstractCommand.cc * src/OptionHandlerFactory.cc * src/ServerHost.{h, cc} * src/Metalink2RequestGroup.cc * src/RequestGroup.{h, cc} * test/RequestGroupTest.cc * src/option_processing.cc * src/prefs.h * src/HttpResponseCommand.cc * src/MetalinkResource.{h, cc} * src/FtpNegotiationCommand.cc * src/MetalinkEntry.{h, cc} * src/MetalinkEntryTest.cc --- ChangeLog | 19 ++++++++ src/AbstractCommand.cc | 1 + src/FtpNegotiationCommand.cc | 4 ++ src/HttpResponseCommand.cc | 4 ++ src/Makefile.am | 3 +- src/Makefile.in | 15 +++--- src/Metalink2RequestGroup.cc | 5 ++ src/MetalinkEntry.cc | 23 +++++++++ src/MetalinkEntry.h | 1 + src/MetalinkResource.cc | 4 ++ src/MetalinkResource.h | 9 +++- src/OptionHandlerFactory.cc | 6 +++ src/RequestGroup.cc | 95 ++++++++++++++++++++++++++++++++++-- src/RequestGroup.h | 34 +++++++++++++ src/ServerHost.cc | 40 +++++++++++++++ src/ServerHost.h | 69 ++++++++++++++++++++++++++ src/option_processing.cc | 5 ++ src/prefs.h | 5 ++ src/version_usage.cc | 4 ++ test/MetalinkEntryTest.cc | 13 +++++ test/RequestGroupTest.cc | 54 +++++++++++++++++++- 21 files changed, 399 insertions(+), 14 deletions(-) create mode 100644 src/ServerHost.cc create mode 100644 src/ServerHost.h diff --git a/ChangeLog b/ChangeLog index b9251e61..b6be63f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2007-12-12 Tatsuhiro Tsujikawa + + If several protocols are available for a mirror, aria2 now use one of + them. --metalink-preferred-protocol option was added to specify the + preference of protocol. + * src/AbstractCommand.cc + * src/OptionHandlerFactory.cc + * src/ServerHost.{h, cc} + * src/Metalink2RequestGroup.cc + * src/RequestGroup.{h, cc} + * test/RequestGroupTest.cc + * src/option_processing.cc + * src/prefs.h + * src/HttpResponseCommand.cc + * src/MetalinkResource.{h, cc} + * src/FtpNegotiationCommand.cc + * src/MetalinkEntry.{h, cc} + * src/MetalinkEntryTest.cc + 2007-12-12 Tatsuhiro Tsujikawa Code cleanup and added debug log. diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index f7590182..321443f2 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -160,6 +160,7 @@ bool AbstractCommand::execute() { } void AbstractCommand::tryReserved() { + _requestGroup->removeServerHost(cuid); Commands commands = _requestGroup->createNextCommand(e, 1); e->addCommand(commands); } diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc index 9f36d44b..04d77292 100644 --- a/src/FtpNegotiationCommand.cc +++ b/src/FtpNegotiationCommand.cc @@ -46,6 +46,7 @@ #include "DefaultBtProgressInfoFile.h" #include "RequestGroupMan.h" #include "DownloadFailureException.h" +#include "ServerHost.h" FtpNegotiationCommand::FtpNegotiationCommand(int32_t cuid, const RequestHandle& req, @@ -73,6 +74,9 @@ bool FtpNegotiationCommand::executeInternal() { command->setMaxDownloadSpeedLimit(e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)); command->setStartupIdleTime(e->option->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setLowestDownloadSpeedLimit(e->option->getAsInt(PREF_LOWEST_SPEED_LIMIT)); + if(!_requestGroup->isSingleHostMultiConnectionEnabled()) { + _requestGroup->removeURIWhoseHostnameIs(_requestGroup->searchServerHost(cuid)->getHostname()); + } e->commands.push_back(command); return true; } else if(sequence == SEQ_HEAD_OK || sequence == SEQ_DOWNLOAD_ALREADY_COMPLETED) { diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index a11b8f8d..d21fcee4 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -50,6 +50,7 @@ #include "DefaultBtProgressInfoFile.h" #include "RequestGroupMan.h" #include "DownloadFailureException.h" +#include "ServerHost.h" #include #include @@ -85,6 +86,9 @@ bool HttpResponseCommand::executeInternal() e->noWait = true; return prepareForRetry(0); } + if(!_requestGroup->isSingleHostMultiConnectionEnabled()) { + _requestGroup->removeURIWhoseHostnameIs(_requestGroup->searchServerHost(cuid)->getHostname()); + } if(_requestGroup->getPieceStorage().isNull()) { int64_t totalLength = httpResponse->getEntityLength(); SingleFileDownloadContextHandle dctx = _requestGroup->getDownloadContext(); diff --git a/src/Makefile.am b/src/Makefile.am index e785abaa..6dac88f1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -146,7 +146,8 @@ SRCS = Socket.h\ BtRegistry.cc BtRegistry.h\ MultiFileAllocationIterator.cc MultiFileAllocationIterator.h\ PeerConnection.cc PeerConnection.h\ - ByteArrayDiskWriter.cc ByteArrayDiskWriter.h + ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\ + ServerHost.cc # debug_new.cpp if ENABLE_MESSAGE_DIGEST diff --git a/src/Makefile.in b/src/Makefile.in index c8327656..fab76850 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -291,7 +291,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ BtRegistry.cc BtRegistry.h MultiFileAllocationIterator.cc \ MultiFileAllocationIterator.h PeerConnection.cc \ PeerConnection.h ByteArrayDiskWriter.cc ByteArrayDiskWriter.h \ - IteratableChunkChecksumValidator.cc \ + ServerHost.cc IteratableChunkChecksumValidator.cc \ IteratableChunkChecksumValidator.h \ IteratableChecksumValidator.cc IteratableChecksumValidator.h \ CheckIntegrityCommand.cc CheckIntegrityCommand.h \ @@ -524,11 +524,11 @@ am__objects_12 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ DirectDiskAdaptor.$(OBJEXT) MultiDiskAdaptor.$(OBJEXT) \ Peer.$(OBJEXT) BtRegistry.$(OBJEXT) \ MultiFileAllocationIterator.$(OBJEXT) PeerConnection.$(OBJEXT) \ - ByteArrayDiskWriter.$(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) + ByteArrayDiskWriter.$(OBJEXT) ServerHost.$(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) am_libaria2c_a_OBJECTS = $(am__objects_12) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" @@ -817,7 +817,7 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ BtRegistry.cc BtRegistry.h MultiFileAllocationIterator.cc \ MultiFileAllocationIterator.h PeerConnection.cc \ PeerConnection.h ByteArrayDiskWriter.cc ByteArrayDiskWriter.h \ - $(am__append_1) $(am__append_2) $(am__append_3) \ + ServerHost.cc $(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) @@ -1075,6 +1075,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ResourcesMetalinkParserState.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SeedCheckCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentMan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerHost.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleBtMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleLogger.Po@am__quote@ diff --git a/src/Metalink2RequestGroup.cc b/src/Metalink2RequestGroup.cc index 4b561070..dda5efb9 100644 --- a/src/Metalink2RequestGroup.cc +++ b/src/Metalink2RequestGroup.cc @@ -133,6 +133,9 @@ RequestGroups Metalink2RequestGroup::createRequestGroup(MetalinkEntries entries) Util::slice(locations, _option->get(PREF_METALINK_LOCATION), ',', true); entry->setLocationPreference(locations, 100); } + if(_option->get(PREF_METALINK_PREFERRED_PROTOCOL) != V_NONE) { + entry->setProtocolPreference(_option->get(PREF_METALINK_PREFERRED_PROTOCOL), 100); + } if(useIndex) { if(find(selectIndexes.begin(), selectIndexes.end(), count+1) == selectIndexes.end()) { continue; @@ -206,6 +209,8 @@ RequestGroups Metalink2RequestGroup::createRequestGroup(MetalinkEntries entries) rg->setNumConcurrentCommand(entry->maxConnections < 0 ? _option->getAsInt(PREF_METALINK_SERVERS) : min(_option->getAsInt(PREF_METALINK_SERVERS), entry->maxConnections)); + // In metalink, multi connection to a single host is not allowed. + rg->setSingleHostMultiConnectionEnabled(false); #ifdef ENABLE_BITTORRENT // Inject depenency between rg and torrentRg here if torrentRg.isNull() == false diff --git a/src/MetalinkEntry.cc b/src/MetalinkEntry.cc index 4886118b..c8b24242 100644 --- a/src/MetalinkEntry.cc +++ b/src/MetalinkEntry.cc @@ -74,6 +74,29 @@ void MetalinkEntry::setLocationPreference(const Strings& locations, AddLocationPreference(locations, preferenceToAdd)); } +class AddProtocolPreference { +private: + const string& _protocol; + int32_t _preferenceToAdd; +public: + AddProtocolPreference(const string& protocol, int32_t prefToAdd): + _protocol(protocol), _preferenceToAdd(prefToAdd) {} + + void operator()(const MetalinkResourceHandle& res) const + { + if(_protocol == MetalinkResource::getTypeString(res->type)) { + res->preference += _preferenceToAdd; + } + } +}; + +void MetalinkEntry::setProtocolPreference(const string& protocol, + int32_t preferenceToAdd) +{ + for_each(resources.begin(), resources.end(), + AddProtocolPreference(protocol, preferenceToAdd)); +} + class PrefOrder { public: bool operator()(const MetalinkResourceHandle& res1, diff --git a/src/MetalinkEntry.h b/src/MetalinkEntry.h index 71795645..8ab64b20 100644 --- a/src/MetalinkEntry.h +++ b/src/MetalinkEntry.h @@ -96,6 +96,7 @@ public: void reorderResourcesByPreference(); void setLocationPreference(const Strings& locations, int32_t preferenceToAdd); + void setProtocolPreference(const string& protocol, int32_t preferenceToAdd); static FileEntries toFileEntry(const MetalinkEntries& metalinkEntries); }; diff --git a/src/MetalinkResource.cc b/src/MetalinkResource.cc index 6a6a039e..1fa2277f 100644 --- a/src/MetalinkResource.cc +++ b/src/MetalinkResource.cc @@ -34,6 +34,10 @@ /* copyright --> */ #include "MetalinkResource.h" +string MetalinkResource::type2String[] = { + "ftp", "http", "https", "bittorrent", "not_supported" +}; + MetalinkResource::MetalinkResource(): maxConnections(-1) {} diff --git a/src/MetalinkResource.h b/src/MetalinkResource.h index cd4eedeb..7fb872cc 100644 --- a/src/MetalinkResource.h +++ b/src/MetalinkResource.h @@ -40,12 +40,14 @@ class MetalinkResource { public: enum TYPE { - TYPE_FTP, + TYPE_FTP = 0, TYPE_HTTP, TYPE_HTTPS, TYPE_BITTORRENT, TYPE_NOT_SUPPORTED }; + + static string type2String[]; public: string url; TYPE type; @@ -66,6 +68,11 @@ public: } return *this; } + + static const string& getTypeString(TYPE type) + { + return type2String[type]; + } }; typedef SharedHandle MetalinkResourceHandle; diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 5e134d1c..274ea354 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -35,6 +35,7 @@ #include "OptionHandlerFactory.h" #include "prefs.h" #include "OptionHandlerImpl.h" +#include "a2functional.h" OptionHandlers OptionHandlerFactory::createOptionHandlers() { @@ -102,6 +103,11 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() handlers.push_back(new UnitNumberOptionHandler(PREF_NO_FILE_ALLOCATION_LIMIT, 0)); handlers.push_back(new BooleanOptionHandler(PREF_ENABLE_DIRECT_IO)); handlers.push_back(new BooleanOptionHandler(PREF_ALLOW_PIECE_LENGTH_CHANGE)); + { + const char* params[] = { V_HTTP, V_HTTPS, V_FTP, V_NONE }; + handlers.push_back(new ParameterOptionHandler(PREF_METALINK_PREFERRED_PROTOCOL, + Strings(¶ms[0], ¶ms[arrayLength(params)]))); + } return handlers; } diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 26be1a2d..08264300 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -63,6 +63,7 @@ #include "DownloadHandlerFactory.h" #include "MemoryBufferPreDownloadHandler.h" #include "DownloadHandlerConstants.h" +#include "ServerHost.h" #ifdef ENABLE_MESSAGE_DIGEST # include "CheckIntegrityCommand.h" #endif // ENABLE_MESSAGE_DIGEST @@ -97,6 +98,7 @@ RequestGroup::RequestGroup(const Option* option, _preLocalFileCheckEnabled(true), _haltRequested(false), _forceHaltRequested(false), + _singleHostMultiConnectionEnabled(true), _option(option), _logger(LogFactory::getInstance()) { @@ -381,18 +383,28 @@ Commands RequestGroup::createNextCommandWithAdj(DownloadEngine* e, int32_t numAd Commands RequestGroup::createNextCommand(DownloadEngine* e, int32_t numCommand, const string& method) { Commands commands; + Strings pendingURIs; for(;!_uris.empty() && numCommand--; _uris.pop_front()) { string uri = _uris.front(); - _spentUris.push_back(uri); RequestHandle req = new Request(); - req->setReferer(_option->get(PREF_REFERER)); - req->setMethod(method); if(req->setUrl(uri)) { - commands.push_back(InitiateConnectionCommandFactory::createInitiateConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(), req, this, e)); + ServerHostHandle sv = _singleHostMultiConnectionEnabled ? 0 : searchServerHost(req->getHost()); + if(sv.isNull()) { + _spentUris.push_back(uri); + req->setReferer(_option->get(PREF_REFERER)); + req->setMethod(method); + Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(), req, this, e); + ServerHostHandle sv = new ServerHost(command->getCuid(), req->getHost()); + registerServerHost(sv); + commands.push_back(command); + } else { + pendingURIs.push_front(uri); + } } else { _logger->error(MSG_UNRECOGNIZED_URI, req->getUrl().c_str()); } } + copy(pendingURIs.begin(), pendingURIs.end(), front_inserter(_uris)); return commands; } @@ -744,3 +756,78 @@ DownloadResultHandle RequestGroup::createDownloadResult() const DownloadResult::FINISHED : DownloadResult::NOT_YET); } + +void RequestGroup::registerServerHost(const ServerHostHandle& serverHost) +{ + _serverHosts.push_back(serverHost); +} + +class FindServerHostByCUID +{ +private: + int32_t _cuid; +public: + FindServerHostByCUID(int32_t cuid):_cuid(cuid) {} + + bool operator()(const ServerHostHandle& sv) const + { + return sv->getCuid() == _cuid; + } +}; + +ServerHostHandle RequestGroup::searchServerHost(int32_t cuid) const +{ + ServerHosts::const_iterator itr = find_if(_serverHosts.begin(), + _serverHosts.end(), + FindServerHostByCUID(cuid)); + if(itr == _serverHosts.end()) { + return 0; + } else { + return *itr; + } +} + +class FindServerHostByHostname +{ +private: + const string& _hostname; +public: + FindServerHostByHostname(const string& hostname):_hostname(hostname) {} + + bool operator()(const ServerHostHandle& sv) const + { + return sv->getHostname() == _hostname; + } +}; + +ServerHostHandle RequestGroup::searchServerHost(const string& hostname) const +{ + ServerHosts::const_iterator itr = find_if(_serverHosts.begin(), + _serverHosts.end(), + FindServerHostByHostname(hostname)); + if(itr == _serverHosts.end()) { + return 0; + } else { + return *itr; + } +} + +void RequestGroup::removeServerHost(int32_t cuid) +{ + remove_if(_serverHosts.begin(), _serverHosts.end(), FindServerHostByCUID(cuid)); +} + +void RequestGroup::removeURIWhoseHostnameIs(const string& hostname) +{ + Strings newURIs; + Request req; + for(Strings::const_iterator itr = _uris.begin(); itr != _uris.end(); ++itr) { + if((*itr).find(hostname) == string::npos || + req.setUrl(*itr) && req.getHost() != hostname) { + newURIs.push_back(*itr); + } + } + _logger->debug("GUID#%d - Removed %d duplicate hostname URIs", + _gid, _uris.size()-newURIs.size()); + _uris = newURIs; +} diff --git a/src/RequestGroup.h b/src/RequestGroup.h index 7ac6da9d..433b8bfa 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -71,6 +71,9 @@ class CheckIntegrityEntry; typedef SharedHandle CheckIntegrityEntryHandle; class DownloadResult; typedef SharedHandle DownloadResultHandle; +class ServerHost; +typedef SharedHandle ServerHostHandle; +typedef deque ServerHosts; class RequestGroup { private: @@ -103,6 +106,8 @@ private: DependencyHandle _dependency; + ServerHosts _serverHosts; + bool _fileAllocationEnabled; bool _preLocalFileCheckEnabled; @@ -111,6 +116,8 @@ private: bool _forceHaltRequested; + bool _singleHostMultiConnectionEnabled; + PreDownloadHandlers _preDownloadHandlers; PostDownloadHandlers _postDownloadHandlers; @@ -310,6 +317,33 @@ public: { return _option; } + + bool isSingleHostMultiConnectionEnabled() const + { + return _singleHostMultiConnectionEnabled; + } + + void setSingleHostMultiConnectionEnabled(bool f) + { + _singleHostMultiConnectionEnabled = f; + } + + /** + * Registers given ServerHost. + */ + void registerServerHost(const ServerHostHandle& serverHost); + + /** + * Returns ServerHost whose cuid is given cuid. If it is not found, returns + * 0. + */ + ServerHostHandle searchServerHost(int32_t cuid) const; + + ServerHostHandle searchServerHost(const string& hostname) const; + + void removeServerHost(int32_t cuid); + + void removeURIWhoseHostnameIs(const string& hostname); }; typedef SharedHandle RequestGroupHandle; diff --git a/src/ServerHost.cc b/src/ServerHost.cc new file mode 100644 index 00000000..38393060 --- /dev/null +++ b/src/ServerHost.cc @@ -0,0 +1,40 @@ +/* */ +#include "ServerHost.h" + +ServerHost::ServerHost(int32_t cuid, const string& hostname): + _cuid(cuid), _hostname(hostname) {} + +ServerHost::~ServerHost() {} diff --git a/src/ServerHost.h b/src/ServerHost.h new file mode 100644 index 00000000..aff750be --- /dev/null +++ b/src/ServerHost.h @@ -0,0 +1,69 @@ +/* */ +#ifndef _D_SERVER_HOST_H_ +#define _D_SERVER_HOST_H_ + +#include "common.h" + +class ServerHost { +private: + int32_t _cuid; + + string _hostname; + +public: + ServerHost(int32_t cuid, const string& hostname); + + ~ServerHost(); + + int32_t getCuid() const + { + return _cuid; + } + + const string& getHostname() const + { + return _hostname; + } + + bool operator<(const ServerHost& server) const + { + return this->_cuid < server._cuid; + } +}; + +typedef SharedHandle ServerHostHandle; + +#endif // _D_SERVER_HOST_H_ diff --git a/src/option_processing.cc b/src/option_processing.cc index 6af3bf6d..ef121141 100644 --- a/src/option_processing.cc +++ b/src/option_processing.cc @@ -128,6 +128,7 @@ Option* option_processing(int argc, char* const argv[]) op->put(PREF_SEED_RATIO, "1.0"); op->put(PREF_ENABLE_DIRECT_IO, V_FALSE); op->put(PREF_ALLOW_PIECE_LENGTH_CHANGE, V_FALSE); + op->put(PREF_METALINK_PREFERRED_PROTOCOL, V_NONE); while(1) { int optIndex = 0; int lopt; @@ -205,6 +206,7 @@ Option* option_processing(int argc, char* const argv[]) { "metalink-os", required_argument, &lopt, 102 }, { "follow-metalink", required_argument, &lopt, 103 }, { "metalink-location", required_argument, &lopt, 104 }, + { "metalink-preferred-protocol", required_argument, &lopt, 105 }, #endif // ENABLE_METALINK { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, @@ -300,6 +302,9 @@ Option* option_processing(int argc, char* const argv[]) case 104: cmdstream << PREF_METALINK_LOCATION << "=" << optarg << "\n"; break; + case 105: + cmdstream << PREF_METALINK_PREFERRED_PROTOCOL << "=" << optarg << "\n"; + break; case 200: cmdstream << PREF_LOWEST_SPEED_LIMIT << "=" << optarg << "\n"; break; diff --git a/src/prefs.h b/src/prefs.h index 2e70a0ae..67fe0b87 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -225,5 +225,10 @@ #define PREF_METALINK_SERVERS "metalink-servers" // values: true | false | mem #define PREF_FOLLOW_METALINK "follow-metalink" +// values: http | https | ftp | none +#define PREF_METALINK_PREFERRED_PROTOCOL "metalink-preferred-protocol" +# define V_HTTP "http" +# define V_HTTPS "https" +# define V_FTP "ftp" #endif // _D_PREFS_H_ diff --git a/src/version_usage.cc b/src/version_usage.cc index 4118f1a6..9f62e80d 100644 --- a/src/version_usage.cc +++ b/src/version_usage.cc @@ -300,6 +300,10 @@ void showUsage() { cout << _(" --metalink-location=LOCATION[,...] The location of the preferred server.\n" " A comma-deliminated list of locations is\n" " acceptable.") << endl; + cout << _(" --metalink-preferred-protocol=PROTO Specify preferred protocol. The possible\n" + " values are 'http', 'https', 'ftp' and 'none'.\n" + " Specifiy none to disable this feature.") << "\n" + << DEFAULT_MSG << "none" << "\n"; cout << _(" --follow-metalink=true|false|mem If true or mem is specified, when a file\n" " whose suffix is .metaink or content type is\n" " application/metalink+xml is downloaded, aria2\n" diff --git a/test/MetalinkEntryTest.cc b/test/MetalinkEntryTest.cc index a38189cc..5b27f442 100644 --- a/test/MetalinkEntryTest.cc +++ b/test/MetalinkEntryTest.cc @@ -9,6 +9,7 @@ class MetalinkEntryTest:public CppUnit::TestFixture { CPPUNIT_TEST(testDropUnsupportedResource); CPPUNIT_TEST(testReorderResourcesByPreference); CPPUNIT_TEST(testSetLocationPreference); + CPPUNIT_TEST(testSetProtocolPreference); CPPUNIT_TEST_SUITE_END(); private: @@ -21,6 +22,7 @@ public: void testDropUnsupportedResource(); void testReorderResourcesByPreference(); void testSetLocationPreference(); + void testSetProtocolPreference(); }; @@ -122,3 +124,14 @@ void MetalinkEntryTest::testSetLocationPreference() CPPUNIT_ASSERT_EQUAL(string("JP"), entry->resources[4]->location); CPPUNIT_ASSERT_EQUAL((int32_t)190, entry->resources[4]->preference); } + +void MetalinkEntryTest::testSetProtocolPreference() +{ + MetalinkEntryHandle entry = createTestEntry(); + entry->setProtocolPreference("http", 1); + CPPUNIT_ASSERT_EQUAL(50, entry->resources[0]->preference); // ftp + CPPUNIT_ASSERT_EQUAL(101, entry->resources[1]->preference); // http, +1 + CPPUNIT_ASSERT_EQUAL(60, entry->resources[2]->preference); // bittorrent + CPPUNIT_ASSERT_EQUAL(10, entry->resources[3]->preference); // not supported + CPPUNIT_ASSERT_EQUAL(90, entry->resources[4]->preference); // https +} diff --git a/test/RequestGroupTest.cc b/test/RequestGroupTest.cc index 1c0441ca..7ee7364a 100644 --- a/test/RequestGroupTest.cc +++ b/test/RequestGroupTest.cc @@ -1,5 +1,6 @@ #include "RequestGroup.h" -#include "prefs.h" +#include "ServerHost.h" +#include "Option.h" #include using namespace std; @@ -7,12 +8,63 @@ using namespace std; class RequestGroupTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(RequestGroupTest); + CPPUNIT_TEST(testRegisterSearchRemove); + CPPUNIT_TEST(testRemoveURIWhoseHostnameIs); CPPUNIT_TEST_SUITE_END(); private: public: void setUp() {} + + void testRegisterSearchRemove(); + void testRemoveURIWhoseHostnameIs(); }; CPPUNIT_TEST_SUITE_REGISTRATION( RequestGroupTest ); + +void RequestGroupTest::testRegisterSearchRemove() +{ + Option op; + RequestGroup rg(&op, Strings()); + ServerHostHandle sv1 = new ServerHost(1, "localhost1"); + ServerHostHandle sv2 = new ServerHost(2, "localhost2"); + ServerHostHandle sv3 = new ServerHost(3, "localhost3"); + + rg.registerServerHost(sv3); + rg.registerServerHost(sv1); + rg.registerServerHost(sv2); + + CPPUNIT_ASSERT(rg.searchServerHost(0).isNull()); + + { + ServerHostHandle sv = rg.searchServerHost(1); + CPPUNIT_ASSERT(!sv.isNull()); + CPPUNIT_ASSERT_EQUAL(string("localhost1"), sv->getHostname()); + } + + rg.removeServerHost(1); + + { + ServerHostHandle sv = rg.searchServerHost(1); + CPPUNIT_ASSERT(sv.isNull()); + } + { + ServerHostHandle sv = rg.searchServerHost(2); + CPPUNIT_ASSERT(!sv.isNull()); + CPPUNIT_ASSERT_EQUAL(string("localhost2"), sv->getHostname()); + } +} + +void RequestGroupTest::testRemoveURIWhoseHostnameIs() +{ + const char* uris[] = { "http://localhost/aria2.zip", + "ftp://localhost/aria2.zip", + "http://mirror/aria2.zip" }; + Option op; + RequestGroup rg(&op, Strings(&uris[0], &uris[3])); + rg.removeURIWhoseHostnameIs("localhost"); + CPPUNIT_ASSERT_EQUAL((size_t)1, rg.getRemainingUris().size()); + CPPUNIT_ASSERT_EQUAL(string("http://mirror/aria2.zip"), + rg.getRemainingUris()[0]); +}