2010-02-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Added Metalink4 support. Currently, name attribute of
	metalink::metaurl is ignored and multi-file torrent cannot be used
	with Metalink4.
	* doc/aria2c.1.txt
	* src/DownloadHandlerConstants.cc
	* src/ExpatMetalinkProcessor.cc
	* src/Makefile.am
	* src/Metalink2RequestGroup.cc
	* src/MetalinkEntry.cc
	* src/MetalinkEntry.h
	* src/MetalinkParserController.cc
	* src/MetalinkParserController.h
	* src/MetalinkParserState.h
	* src/MetalinkParserStateImpl.cc
	* src/MetalinkParserStateImpl.h
	* src/MetalinkParserStateMachine.cc
	* src/MetalinkParserStateMachine.h
	* src/MetalinkParserStateV3Impl.cc
	* src/MetalinkParserStateV3Impl.h
	* src/MetalinkParserStateV4Impl.cc
	* src/MetalinkParserStateV4Impl.h
	* src/MetalinkResource.cc
	* src/MetalinkResource.h
	* src/Metalinker.cc
	* src/RequestGroup.cc
	* src/RequestGroup.h
	* src/XML2SAXMetalinkProcessor.cc
	* src/messageDigest.cc
	* src/util.cc
	* src/util.h
	* test/Makefile.am
	* test/MetalinkEntryTest.cc
	* test/MetalinkParserControllerTest.cc
	* test/MetalinkProcessorTest.cc
	* test/MetalinkerTest.cc
	* test/UtilTest.cc
	* test/metalink4-attrs.xml
	* test/metalink4-dirtraversal.xml
	* test/metalink4.xml
pull/1/head
Tatsuhiro Tsujikawa 2010-02-25 14:40:18 +00:00
parent fa6fd758af
commit 3880a5f71b
41 changed files with 2290 additions and 928 deletions

View File

@ -1,3 +1,45 @@
2010-02-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added Metalink4 support. Currently, name attribute of
metalink::metaurl is ignored and multi-file torrent cannot be used
with Metalink4.
* doc/aria2c.1.txt
* src/DownloadHandlerConstants.cc
* src/ExpatMetalinkProcessor.cc
* src/Makefile.am
* src/Metalink2RequestGroup.cc
* src/MetalinkEntry.cc
* src/MetalinkEntry.h
* src/MetalinkParserController.cc
* src/MetalinkParserController.h
* src/MetalinkParserState.h
* src/MetalinkParserStateImpl.cc
* src/MetalinkParserStateImpl.h
* src/MetalinkParserStateMachine.cc
* src/MetalinkParserStateMachine.h
* src/MetalinkParserStateV3Impl.cc
* src/MetalinkParserStateV3Impl.h
* src/MetalinkParserStateV4Impl.cc
* src/MetalinkParserStateV4Impl.h
* src/MetalinkResource.cc
* src/MetalinkResource.h
* src/Metalinker.cc
* src/RequestGroup.cc
* src/RequestGroup.h
* src/XML2SAXMetalinkProcessor.cc
* src/messageDigest.cc
* src/util.cc
* src/util.h
* test/Makefile.am
* test/MetalinkEntryTest.cc
* test/MetalinkParserControllerTest.cc
* test/MetalinkProcessorTest.cc
* test/MetalinkerTest.cc
* test/UtilTest.cc
* test/metalink4-attrs.xml
* test/metalink4-dirtraversal.xml
* test/metalink4.xml
2010-02-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added aiFlags argument to getInterfaceAddress(). Use

View File

@ -2,12 +2,12 @@
.\" Title: aria2c
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 02/20/2010
.\" Date: 02/25/2010
.\" Manual: Aria2 Manual
.\" Source: Aria2 1.9.0a
.\" Language: English
.\"
.TH "ARIA2C" "1" "02/20/2010" "Aria2 1\&.9\&.0a" "Aria2 Manual"
.TH "ARIA2C" "1" "02/25/2010" "Aria2 1\&.9\&.0a" "Aria2 Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -796,7 +796,7 @@ The language of the file to download\&.
\fB\-\-metalink\-location\fR=LOCATION[,\&...]
.RS 4
The location of the preferred server\&. A comma\-delimited list of locations is acceptable, for example,
\fIJP,US\fR\&.
\fIjp,us\fR\&.
.RE
.PP
\fB\-\-metalink\-os\fR=OS
@ -2955,7 +2955,7 @@ The index is printed to the console using \-S option\&.
.RS 4
.\}
.nf
aria2c \-\-metalink\-location=JP,US \-\-metalink\-version=1\&.1 \-\-metalink\-language=en\-US file\&.metalink
aria2c \-\-metalink\-location=jp,us \-\-metalink\-version=1\&.1 \-\-metalink\-language=en\-US file\&.metalink
.fi
.if n \{\
.RE

View File

@ -1556,7 +1556,7 @@ writes the piece to the appropriate files.</td>
<dd>
<p>
The location of the preferred server.
A comma-delimited list of locations is acceptable, for example, <em>JP,US</em>.
A comma-delimited list of locations is acceptable, for example, <em>jp,us</em>.
</p>
</dd>
<dt class="hdlist1">
@ -3444,7 +3444,7 @@ directory.</td>
<h4 id="_download_a_file_using_a_local_metalink_file_with_user_preference">Download a file using a local .metalink file with user preference</h4>
<div class="listingblock">
<div class="content">
<pre><tt>aria2c --metalink-location=JP,US --metalink-version=1.1 --metalink-language=en-US file.metalink</tt></pre>
<pre><tt>aria2c --metalink-location=jp,us --metalink-version=1.1 --metalink-language=en-US file.metalink</tt></pre>
</div></div>
<h3 id="_bittorrent_download">BitTorrent Download</h3><div style="clear:left"></div>
<h4 id="_download_files_from_remote_bittorrent_file">Download files from remote BitTorrent file</h4>
@ -3722,7 +3722,7 @@ files in the program, then also delete it here.</p></div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated 2010-02-20 23:22:54 JST
Last updated 2010-02-23 23:01:01 JST
</div>
</div>
</body>

View File

@ -557,7 +557,7 @@ Metalink Specific Options
*--metalink-location*=LOCATION[,...]::
The location of the preferred server.
A comma-delimited list of locations is acceptable, for example, 'JP,US'.
A comma-delimited list of locations is acceptable, for example, 'jp,us'.
*--metalink-os*=OS::
The operating system of the file to download.
@ -1717,7 +1717,7 @@ The index is printed to the console using -S option.
Download a file using a local .metalink file with user preference
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
------------------------------------------------------------------------------
aria2c --metalink-location=JP,US --metalink-version=1.1 --metalink-language=en-US file.metalink
aria2c --metalink-location=jp,us --metalink-version=1.1 --metalink-language=en-US file.metalink
------------------------------------------------------------------------------
BitTorrent Download

View File

@ -37,10 +37,14 @@
namespace aria2 {
const char* DownloadHandlerConstants::METALINK_EXTENSIONS[] = { ".metalink" };
const char* DownloadHandlerConstants::METALINK_EXTENSIONS[] = {
".metalink", // Metalink3Spec
".meta4" // Metalink4Spec
};
const char* DownloadHandlerConstants::METALINK_CONTENT_TYPES[] = {
"application/metalink+xml"
"application/metalink4+xml", // Metalink4Spec
"application/metalink+xml" // Metalink3Spec
};
const char* DownloadHandlerConstants::BT_EXTENSIONS[] = { ".torrent" };

View File

@ -40,6 +40,8 @@
#include "util.h"
#include "message.h"
#include "DlAbortEx.h"
#include "MetalinkParserState.h"
#include "A2STR.h"
namespace aria2 {
@ -52,37 +54,71 @@ public:
SessionData(const SharedHandle<MetalinkParserStateMachine>& stm):_stm(stm) {}
};
static void mlStartElement(void* userData, const char* name, const char** attrs)
static void splitNsName
(std::string& localname, std::string& prefix, std::string& nsUri,
const std::string& nsName)
{
SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::map<std::string, std::string> attrmap;
if(attrs) {
const char** p = attrs;
while(*p != 0) {
std::string name = *p++;
if(*p == 0) {
break;
}
std::string value = util::trim(*p++);
attrmap[name] = value;
}
}
sd->_stm->beginElement(name, attrmap);
if(sd->_stm->needsCharactersBuffering()) {
sd->_charactersStack.push_front(std::string());
std::pair<std::string, std::string> nsNamePair;
util::split(nsNamePair, nsName, '\t');
if(nsNamePair.second.empty()) {
localname = nsNamePair.first;
} else {
nsUri = nsNamePair.first;
localname = nsNamePair.second;
}
}
static void mlEndElement(void* userData, const char* name)
static void mlStartElement(void* userData, const char* nsName, const char** attrs)
{
SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::vector<XmlAttr> xmlAttrs;
if(attrs) {
const char** p = attrs;
while(*p != 0) {
std::string attrNsName = *p++;
if(*p == 0) {
break;
}
std::string value = *p++;
std::pair<std::string, std::string> nsNamePair;
util::split(nsNamePair, attrNsName, '\t');
XmlAttr xa;
if(nsNamePair.second.empty()) {
xa.localname = nsNamePair.first;
} else {
xa.nsUri = nsNamePair.first;
xa.localname = nsNamePair.second;
}
xa.value = value;
xmlAttrs.push_back(xa);
}
}
std::string localname;
std::string prefix;
std::string nsUri;
splitNsName(localname, prefix, nsUri, nsName);
sd->_stm->beginElement(localname, prefix, nsUri, xmlAttrs);
if(sd->_stm->needsCharactersBuffering()) {
sd->_charactersStack.push_front(A2STR::NIL);
}
}
static void mlEndElement(void* userData, const char* nsName)
{
std::string localname;
std::string prefix;
std::string nsUri;
splitNsName(localname, prefix, nsUri, nsName);
SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::string characters;
if(sd->_stm->needsCharactersBuffering()) {
characters = util::trim(sd->_charactersStack.front());
characters = sd->_charactersStack.front();
sd->_charactersStack.pop_front();
}
sd->_stm->endElement(name, characters);
sd->_stm->endElement(localname, prefix, nsUri, characters);
}
static void mlCharacters(void* userData, const char* ch, int len)
@ -110,7 +146,7 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
unsigned char buf[bufSize];
SharedHandle<SessionData> sessionData(new SessionData(_stm));
XML_Parser parser = XML_ParserCreate(0);
XML_Parser parser = XML_ParserCreateNS(0, static_cast<const XML_Char>('\t'));
try {
XML_SetUserData(parser, sessionData.get());
XML_SetElementHandler(parser, &mlStartElement, &mlEndElement);

View File

@ -457,6 +457,8 @@ SRCS += Metalinker.cc Metalinker.h\
MetalinkParserStateMachine.cc MetalinkParserStateMachine.h\
MetalinkParserState.h\
MetalinkParserStateImpl.cc MetalinkParserStateImpl.h\
MetalinkParserStateV3Impl.cc MetalinkParserStateV3Impl.h\
MetalinkParserStateV4Impl.cc MetalinkParserStateV4Impl.h\
Metalink2RequestGroup.cc Metalink2RequestGroup.h\
MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\
MetalinkHelper.cc MetalinkHelper.h

View File

@ -258,6 +258,8 @@ bin_PROGRAMS = aria2c$(EXEEXT)
@ENABLE_METALINK_TRUE@ MetalinkParserStateMachine.cc MetalinkParserStateMachine.h\
@ENABLE_METALINK_TRUE@ MetalinkParserState.h\
@ENABLE_METALINK_TRUE@ MetalinkParserStateImpl.cc MetalinkParserStateImpl.h\
@ENABLE_METALINK_TRUE@ MetalinkParserStateV3Impl.cc MetalinkParserStateV3Impl.h\
@ENABLE_METALINK_TRUE@ MetalinkParserStateV4Impl.cc MetalinkParserStateV4Impl.h\
@ENABLE_METALINK_TRUE@ Metalink2RequestGroup.cc Metalink2RequestGroup.h\
@ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\
@ENABLE_METALINK_TRUE@ MetalinkHelper.cc MetalinkHelper.h
@ -585,7 +587,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
MetalinkParserController.cc MetalinkParserController.h \
MetalinkParserStateMachine.cc MetalinkParserStateMachine.h \
MetalinkParserState.h MetalinkParserStateImpl.cc \
MetalinkParserStateImpl.h Metalink2RequestGroup.cc \
MetalinkParserStateImpl.h MetalinkParserStateV3Impl.cc \
MetalinkParserStateV3Impl.h MetalinkParserStateV4Impl.cc \
MetalinkParserStateV4Impl.h Metalink2RequestGroup.cc \
Metalink2RequestGroup.h MetalinkPostDownloadHandler.cc \
MetalinkPostDownloadHandler.h MetalinkHelper.cc \
MetalinkHelper.h XML2SAXMetalinkProcessor.cc \
@ -754,6 +758,8 @@ am__objects_6 =
@ENABLE_METALINK_TRUE@ MetalinkParserController.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkParserStateMachine.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkParserStateImpl.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkParserStateV3Impl.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkParserStateV4Impl.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ Metalink2RequestGroup.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandler.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkHelper.$(OBJEXT)
@ -1491,6 +1497,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserController.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserStateImpl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserStateMachine.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserStateV3Impl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkParserStateV4Impl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkPostDownloadHandler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkResource.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalinker.Po@am__quote@

View File

@ -53,6 +53,7 @@
#include "FileEntry.h"
#include "A2STR.h"
#include "a2functional.h"
#include "DownloadHandlerConstants.h"
#ifdef ENABLE_BITTORRENT
# include "BtDependency.h"
# include "download_helper.h"
@ -120,6 +121,17 @@ Metalink2RequestGroup::generate(std::deque<SharedHandle<RequestGroup> >& groups,
createRequestGroup(groups, entries, option);
}
namespace {
void removeMetalinkContentTypes(const SharedHandle<RequestGroup>& group)
{
for(std::vector<std::string>::const_iterator i =
DownloadHandlerConstants::getMetalinkContentTypes().begin();
i != DownloadHandlerConstants::getMetalinkContentTypes().end(); ++i) {
group->removeAcceptType(*i);
}
}
}
void
Metalink2RequestGroup::createRequestGroup
(std::deque<SharedHandle<RequestGroup> >& groups,
@ -146,10 +158,15 @@ Metalink2RequestGroup::createRequestGroup
std::deque<std::string> locations;
util::split(option->get(PREF_METALINK_LOCATION),
std::back_inserter(locations), ",", true);
entry->setLocationPreference(locations, 100);
std::transform
(locations.begin(), locations.end(), locations.begin(), util::toLower);
entry->setLocationPriority
(locations, -MetalinkResource::getLowestPriority());
}
if(option->get(PREF_METALINK_PREFERRED_PROTOCOL) != V_NONE) {
entry->setProtocolPreference(option->get(PREF_METALINK_PREFERRED_PROTOCOL), 100);
entry->setProtocolPriority
(option->get(PREF_METALINK_PREFERRED_PROTOCOL),
-MetalinkResource::getLowestPriority());
}
if(useIndex) {
if(std::find(selectIndexes.begin(), selectIndexes.end(), count+1) ==
@ -186,7 +203,7 @@ Metalink2RequestGroup::createRequestGroup
torrentRg->clearPostDownloadHandler();
// remove "metalink" from Accept Type list to avoid loop in
// tranparent metalink
torrentRg->removeAcceptType(RequestGroup::ACCEPT_METALINK);
removeMetalinkContentTypes(torrentRg);
// make it in-memory download
SharedHandle<PreDownloadHandler> preh
(new MemoryBufferPreDownloadHandler());
@ -197,7 +214,7 @@ Metalink2RequestGroup::createRequestGroup
}
}
#endif // ENABLE_BITTORRENT
entry->reorderResourcesByPreference();
entry->reorderResourcesByPriority();
std::deque<std::string> uris;
std::for_each(entry->resources.begin(), entry->resources.end(),
AccumulateNonP2PUrl(uris));
@ -245,7 +262,7 @@ Metalink2RequestGroup::createRequestGroup
static_cast<int32_t>(entry->maxConnections)));
// remove "metalink" from Accept Type list to avoid loop in tranparent
// metalink
rg->removeAcceptType(RequestGroup::ACCEPT_METALINK);
removeMetalinkContentTypes(rg);
#ifdef ENABLE_BITTORRENT
// Inject depenency between rg and torrentRg here if torrentRg.isNull() == false

View File

@ -56,21 +56,22 @@ MetalinkEntry::MetalinkEntry():
MetalinkEntry::~MetalinkEntry() {}
class AddLocationPreference {
class AddLocationPriority {
private:
std::deque<std::string> _locations;
int _preferenceToAdd;
int _priorityToAdd;
public:
AddLocationPreference(const std::deque<std::string>& locations, int preferenceToAdd):
_locations(locations), _preferenceToAdd(preferenceToAdd)
AddLocationPriority
(const std::deque<std::string>& locations, int priorityToAdd):
_locations(locations), _priorityToAdd(priorityToAdd)
{
std::transform(_locations.begin(), _locations.end(), _locations.begin(), util::toUpper);
std::sort(_locations.begin(), _locations.end());
}
void operator()(SharedHandle<MetalinkResource>& res) {
if(std::binary_search(_locations.begin(), _locations.end(), res->location)) {
res->preference += _preferenceToAdd;
if(std::binary_search
(_locations.begin(), _locations.end(), res->location)) {
res->priority += _priorityToAdd;
}
}
};
@ -80,8 +81,8 @@ MetalinkEntry& MetalinkEntry::operator=(const MetalinkEntry& metalinkEntry)
if(this != &metalinkEntry) {
this->file = metalinkEntry.file;
this->version = metalinkEntry.version;
this->language = metalinkEntry.language;
this->os = metalinkEntry.os;
this->languages = metalinkEntry.languages;
this->oses = metalinkEntry.oses;
this->maxConnections = metalinkEntry.maxConnections;
#ifdef ENABLE_MESSAGE_DIGEST
this->checksum = metalinkEntry.checksum;
@ -102,45 +103,46 @@ uint64_t MetalinkEntry::getLength() const
return file->getLength();
}
void MetalinkEntry::setLocationPreference(const std::deque<std::string>& locations,
int preferenceToAdd)
void MetalinkEntry::setLocationPriority
(const std::deque<std::string>& locations, int priorityToAdd)
{
std::for_each(resources.begin(), resources.end(),
AddLocationPreference(locations, preferenceToAdd));
AddLocationPriority(locations, priorityToAdd));
}
class AddProtocolPreference {
class AddProtocolPriority {
private:
std::string _protocol;
int _preferenceToAdd;
int _priorityToAdd;
public:
AddProtocolPreference(const std::string& protocol, int prefToAdd):
_protocol(protocol), _preferenceToAdd(prefToAdd) {}
AddProtocolPriority(const std::string& protocol, int prefToAdd):
_protocol(protocol), _priorityToAdd(prefToAdd) {}
void operator()(const SharedHandle<MetalinkResource>& res) const
{
if(_protocol == MetalinkResource::getTypeString(res->type)) {
res->preference += _preferenceToAdd;
res->priority += _priorityToAdd;
}
}
};
void MetalinkEntry::setProtocolPreference(const std::string& protocol,
int preferenceToAdd)
void MetalinkEntry::setProtocolPriority(const std::string& protocol,
int priorityToAdd)
{
std::for_each(resources.begin(), resources.end(),
AddProtocolPreference(protocol, preferenceToAdd));
AddProtocolPriority(protocol, priorityToAdd));
}
class PrefOrder {
public:
bool operator()(const SharedHandle<MetalinkResource>& res1,
const SharedHandle<MetalinkResource>& res2) {
return res1->preference > res2->preference;
const SharedHandle<MetalinkResource>& res2)
{
return res1->priority < res2->priority;
}
};
void MetalinkEntry::reorderResourcesByPreference() {
void MetalinkEntry::reorderResourcesByPriority() {
std::random_shuffle(resources.begin(), resources.end(),
*(SimpleRandomizer::getInstance().get()));
std::sort(resources.begin(), resources.end(), PrefOrder());

View File

@ -39,6 +39,8 @@
#include <string>
#include <deque>
#include <vector>
#include <algorithm>
#include "SharedHandle.h"
@ -56,10 +58,10 @@ class MetalinkEntry {
public:
SharedHandle<FileEntry> file;
std::string version;
std::string language;
std::string os;
std::vector<std::string> languages;
std::vector<std::string> oses;
std::deque<SharedHandle<MetalinkResource> > resources;
int maxConnections;
int maxConnections; // Metalink3Spec
#ifdef ENABLE_MESSAGE_DIGEST
SharedHandle<Checksum> checksum;
SharedHandle<ChunkChecksum> chunkChecksum;
@ -84,10 +86,23 @@ public:
void dropUnsupportedResource();
void reorderResourcesByPreference();
void reorderResourcesByPriority();
void setLocationPreference(const std::deque<std::string>& locations, int preferenceToAdd);
void setProtocolPreference(const std::string& protocol, int preferenceToAdd);
bool containsLanguage(const std::string& lang) const
{
return
std::find(languages.begin(), languages.end(), lang) != languages.end();
}
bool containsOS(const std::string& os) const
{
return std::find(oses.begin(), oses.end(), os) != oses.end();
}
void setLocationPriority
(const std::deque<std::string>& locations, int priorityToAdd);
void setProtocolPriority(const std::string& protocol, int priorityToAdd);
static void toFileEntry
(std::deque<SharedHandle<FileEntry> >& fileEntries,
@ -99,7 +114,6 @@ public:
{
return _signature;
}
};
} // namespace aria2

View File

@ -53,7 +53,7 @@
namespace aria2 {
const std::string MetalinkParserController::SHA1("sha1");
const std::string MetalinkParserController::SHA1("sha1");// Metalink3Spec
MetalinkParserController::MetalinkParserController():
_metalinker(new Metalinker())
@ -67,6 +67,7 @@ void MetalinkParserController::newEntryTransaction()
_tResource.reset();
#ifdef ENABLE_MESSAGE_DIGEST
_tChecksum.reset();
_tChunkChecksumV4.reset();
_tChunkChecksum.reset();
#endif // ENABLE_MESSAGE_DIGEST
}
@ -112,7 +113,7 @@ void MetalinkParserController::setLanguageOfEntry(const std::string& language)
if(_tEntry.isNull()) {
return;
}
_tEntry->language = language;
_tEntry->languages.push_back(language);
}
void MetalinkParserController::setOSOfEntry(const std::string& os)
@ -120,7 +121,7 @@ void MetalinkParserController::setOSOfEntry(const std::string& os)
if(_tEntry.isNull()) {
return;
}
_tEntry->os = os;
_tEntry->oses.push_back(os);
}
void MetalinkParserController::setMaxConnectionsOfEntry(int maxConnections)
@ -138,6 +139,7 @@ void MetalinkParserController::commitEntryTransaction()
}
commitResourceTransaction();
commitChecksumTransaction();
commitChunkChecksumTransactionV4();
commitChunkChecksumTransaction();
commitSignatureTransaction();
_metalinker->entries.push_back(_tEntry);
@ -148,6 +150,7 @@ void MetalinkParserController::cancelEntryTransaction()
{
cancelResourceTransaction();
cancelChecksumTransaction();
cancelChunkChecksumTransactionV4();
cancelChunkChecksumTransaction();
cancelSignatureTransaction();
_tEntry.reset();
@ -167,6 +170,14 @@ void MetalinkParserController::setURLOfResource(const std::string& url)
return;
}
_tResource->url = url;
// Metalink4Spec
if(_tResource->type == MetalinkResource::TYPE_UNKNOWN) {
// guess from URI sheme
std::string::size_type pos = url.find("://");
if(pos != std::string::npos) {
setTypeOfResource(url.substr(0, pos));
}
}
}
void MetalinkParserController::setTypeOfResource(const std::string& type)
@ -182,6 +193,8 @@ void MetalinkParserController::setTypeOfResource(const std::string& type)
_tResource->type = MetalinkResource::TYPE_HTTPS;
} else if(type == MetalinkResource::BITTORRENT) {
_tResource->type = MetalinkResource::TYPE_BITTORRENT;
} else if(type == MetalinkResource::TORRENT) { // Metalink4Spec
_tResource->type = MetalinkResource::TYPE_BITTORRENT;
} else {
_tResource->type = MetalinkResource::TYPE_NOT_SUPPORTED;
}
@ -195,12 +208,12 @@ void MetalinkParserController::setLocationOfResource(const std::string& location
_tResource->location = location;
}
void MetalinkParserController::setPreferenceOfResource(int preference)
void MetalinkParserController::setPriorityOfResource(int priority)
{
if(_tResource.isNull()) {
return;
}
_tResource->preference = preference;
_tResource->priority = priority;
}
void MetalinkParserController::setMaxConnectionsOfResource(int maxConnections)
@ -266,7 +279,10 @@ void MetalinkParserController::commitChecksumTransaction()
return;
}
if(_tEntry->checksum.isNull() ||
_tEntry->checksum->getAlgo() != MetalinkParserController::SHA1) {
// Metalink3Spec
(_tEntry->checksum->getAlgo() != MetalinkParserController::SHA1 &&
// Metalink4Spec
_tEntry->checksum->getAlgo() != MessageDigestContext::SHA1)) {
_tEntry->checksum = _tChecksum;
}
_tChecksum.reset();
@ -279,7 +295,80 @@ void MetalinkParserController::cancelChecksumTransaction()
_tChecksum.reset();
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::newChunkChecksumTransactionV4()
{
#ifdef ENABLE_MESSAGE_DIGEST
if(_tEntry.isNull()) {
return;
}
_tChunkChecksumV4.reset(new ChunkChecksum());
_tempChunkChecksumsV4.clear();
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::setTypeOfChunkChecksumV4(const std::string& type)
{
#ifdef ENABLE_MESSAGE_DIGEST
if(_tChunkChecksumV4.isNull()) {
return;
}
if(MessageDigestContext::supports(type)) {
_tChunkChecksumV4->setAlgo(type);
} else {
cancelChunkChecksumTransactionV4();
}
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::setLengthOfChunkChecksumV4(size_t length)
{
#ifdef ENABLE_MESSAGE_DIGEST
if(_tChunkChecksumV4.isNull()) {
return;
}
if(length > 0) {
_tChunkChecksumV4->setChecksumLength(length);
} else {
cancelChunkChecksumTransactionV4();
}
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::addHashOfChunkChecksumV4(const std::string& md)
{
#ifdef ENABLE_MESSAGE_DIGEST
if(_tChunkChecksumV4.isNull()) {
return;
}
_tempChunkChecksumsV4.push_back(md);
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::commitChunkChecksumTransactionV4()
{
#ifdef ENABLE_MESSAGE_DIGEST
if(_tChunkChecksumV4.isNull()) {
return;
}
if(_tEntry->chunkChecksum.isNull() ||
_tEntry->chunkChecksum->getAlgo() != MessageDigestContext::SHA1) {
std::deque<std::string> checksums(_tempChunkChecksumsV4.begin(),
_tempChunkChecksumsV4.end());
_tChunkChecksumV4->setChecksums(checksums);
_tEntry->chunkChecksum = _tChunkChecksumV4;
}
_tChunkChecksumV4.reset();
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::cancelChunkChecksumTransactionV4()
{
#ifdef ENABLE_MESSAGE_DIGEST
_tChunkChecksumV4.reset();
#endif // ENABLE_MESSAGE_DIGEST
}
void MetalinkParserController::newChunkChecksumTransaction()
{
#ifdef ENABLE_MESSAGE_DIGEST

View File

@ -36,11 +36,13 @@
#define _D_METALINK_PARSER_CONTROLLER_H_
#include "common.h"
#include "SharedHandle.h"
#include <string>
#include <utility>
#include <deque>
#include "SharedHandle.h"
namespace aria2 {
class Metalinker;
@ -64,11 +66,16 @@ private:
#ifdef ENABLE_MESSAGE_DIGEST
SharedHandle<Checksum> _tChecksum;
SharedHandle<ChunkChecksum> _tChunkChecksum;
SharedHandle<ChunkChecksum> _tChunkChecksumV4; // Metalink4Spec
std::deque<std::string> _tempChunkChecksumsV4; // Metalink4Spec
SharedHandle<ChunkChecksum> _tChunkChecksum; // Metalink3Spec
std::deque<std::pair<size_t, std::string> > _tempChunkChecksums;//Metalink3Spec
std::pair<size_t, std::string> _tempHashPair; // Metalink3Spec
std::deque<std::pair<size_t, std::string> > _tempChunkChecksums;
std::pair<size_t, std::string> _tempHashPair;
#endif // ENABLE_MESSAGE_DIGEST
SharedHandle<Signature> _tSignature;
@ -110,7 +117,7 @@ public:
void setLocationOfResource(const std::string& location);
void setPreferenceOfResource(int preference);
void setPriorityOfResource(int priority);
void setMaxConnectionsOfResource(int maxConnections);
@ -127,24 +134,36 @@ public:
void commitChecksumTransaction();
void cancelChecksumTransaction();
void newChunkChecksumTransaction();
void setTypeOfChunkChecksum(const std::string& type);
void newChunkChecksumTransactionV4(); // Metalink4Spec
void setLengthOfChunkChecksum(size_t length);
void setTypeOfChunkChecksumV4(const std::string& type); // Metalink4Spec
void addHashOfChunkChecksum(size_t order, const std::string& md);
void setLengthOfChunkChecksumV4(size_t length); // Metalink4Spec
void createNewHashOfChunkChecksum(size_t order);
void addHashOfChunkChecksumV4(const std::string& md); // Metalink4Spec
void setMessageDigestOfChunkChecksum(const std::string& md);
void commitChunkChecksumTransactionV4(); // Metalink4Spec
void addHashOfChunkChecksum();
void cancelChunkChecksumTransactionV4(); // Metalink4Spec
void commitChunkChecksumTransaction();
void newChunkChecksumTransaction(); // Metalink3Spec
void cancelChunkChecksumTransaction();
void setTypeOfChunkChecksum(const std::string& type); // Metalink3Spec
void setLengthOfChunkChecksum(size_t length); // Metalink3Spec
void addHashOfChunkChecksum(size_t order, const std::string& md);// Metalink3Spec
void createNewHashOfChunkChecksum(size_t order); // Metalink3Spec
void setMessageDigestOfChunkChecksum(const std::string& md); // Metalink3Spec
void addHashOfChunkChecksum(); // Metalink3Spec
void commitChunkChecksumTransaction(); // Metalink3Spec
void cancelChunkChecksumTransaction(); // Metalink3Spec
void newSignatureTransaction();

View File

@ -36,13 +36,21 @@
#define _D_METALINK_PARSER_STATE_H_
#include "common.h"
#include <map>
#include <vector>
#include <string>
namespace aria2 {
class MetalinkParserStateMachine;
struct XmlAttr {
std::string localname;
std::string prefix;
std::string nsUri;
std::string value;
};
class MetalinkParserState
{
public:
@ -50,14 +58,22 @@ public:
virtual void beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs) = 0;
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs) {}
virtual void endElement
(MetalinkParserStateMachine* stm,
const std::string& name, const std::string& characters) = 0;
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const = 0;
virtual bool needsCharactersBuffering() const
{
return false;
}
};
} // namespace aria2

View File

@ -2,7 +2,7 @@
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 Tatsuhiro Tsujikawa
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -33,422 +33,34 @@
*/
/* copyright --> */
#include "MetalinkParserStateImpl.h"
#include "MetalinkParserStateV3Impl.h"
#include "MetalinkParserStateV4Impl.h"
#include "MetalinkParserStateMachine.h"
#include "RecoverableException.h"
#include "util.h"
namespace aria2 {
namespace {
const std::string FILE("file");
const std::string FILES("files");
const std::string HASH("hash");
const std::string LANGUAGE("language");
const std::string LENGTH("length");
const std::string LOCATION("location");
const std::string MAXCONNECTIONS("maxconnections");
const std::string METALINK("metalink");
// Can't use name VERSION because it is used as a macro.
const std::string METALINK_VERSION("version");
const std::string METAURL("metaurl");
const std::string NAME("name");
const std::string OS("os");
const std::string PIECE("piece");
const std::string PIECES("pieces");
const std::string PREFERENCE("preference");
const std::string RESOURCES("resources");
const std::string SIGNATURE("signature");
const std::string SIZE("size");
const std::string TYPE("type");
const std::string URL("url");
const std::string VERIFICATION("verification");
}
void InitialMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(name == METALINK) {
if(nsUri == METALINK4_NAMESPACE_URI && localname == "metalink") {
stm->setMetalinkStateV4();
} else if(nsUri == METALINK3_NAMESPACE_URI && localname == "metalink") {
stm->setMetalinkState();
} else {
stm->setSkipTagState();
}
}
void MetalinkMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
if(name == FILES) {
stm->setFilesState();
} else {
stm->setSkipTagState();
}
}
void FilesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
if(name == FILE) {
stm->setFileState();
std::map<std::string, std::string>::const_iterator itr = attrs.find(NAME);
if(itr != attrs.end()) {
stm->newEntryTransaction();
stm->setFileNameOfEntry((*itr).second);
}
} else {
stm->setSkipTagState();
}
}
void FileMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
if(name == SIZE) {
stm->setSizeState();
} else if(name == METALINK_VERSION) {
stm->setVersionState();
} else if(name == LANGUAGE) {
stm->setLanguageState();
} else if(name == OS) {
stm->setOSState();
} else if(name == VERIFICATION) {
stm->setVerificationState();
} else if(name == RESOURCES) {
stm->setResourcesState();
int maxConnections;
{
std::map<std::string, std::string>::const_iterator itr =
attrs.find(MAXCONNECTIONS);
if(itr == attrs.end()) {
maxConnections = -1;
} else {
try {
maxConnections = util::parseInt((*itr).second);
} catch(RecoverableException& e) {
maxConnections = -1;
}
}
}
stm->setMaxConnectionsOfEntry(maxConnections);
} else {
stm->setSkipTagState();
}
}
void FileMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->commitEntryTransaction();
}
void SizeMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void SizeMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
try {
stm->setFileLengthOfEntry(util::parseLLInt(characters));
} catch(RecoverableException& e) {
// current metalink specification doesn't require size element.
}
}
void VersionMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void VersionMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setVersionOfEntry(characters);
}
void LanguageMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void LanguageMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setLanguageOfEntry(characters);
}
void OSMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void OSMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setOSOfEntry(characters);
}
void VerificationMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
#ifdef ENABLE_MESSAGE_DIGEST
if(name == HASH) {
stm->setHashState();
std::map<std::string, std::string>::const_iterator itr = attrs.find(TYPE);
if(itr == attrs.end()) {
return;
} else {
std::string type = (*itr).second;
stm->newChecksumTransaction();
stm->setTypeOfChecksum(type);
}
} else if(name == PIECES) {
stm->setPiecesState();
try {
size_t length;
{
std::map<std::string, std::string>::const_iterator itr =
attrs.find(LENGTH);
if(itr == attrs.end()) {
return;
} else {
length = util::parseInt((*itr).second);
}
}
std::string type;
{
std::map<std::string, std::string>::const_iterator itr =
attrs.find(TYPE);
if(itr == attrs.end()) {
return;
} else {
type = (*itr).second;
}
}
stm->newChunkChecksumTransaction();
stm->setLengthOfChunkChecksum(length);
stm->setTypeOfChunkChecksum(type);
} catch(RecoverableException& e) {
stm->cancelChunkChecksumTransaction();
}
} else
#endif // ENABLE_MESSAGE_DIGEST
if(name == SIGNATURE) {
stm->setSignatureState();
std::map<std::string, std::string>::const_iterator itr = attrs.find(TYPE);
if(itr == attrs.end()) {
return;
} else {
stm->newSignatureTransaction();
stm->setTypeOfSignature((*itr).second);
std::map<std::string, std::string>::const_iterator itr = attrs.find(FILE);
if(itr != attrs.end()) {
stm->setFileOfSignature((*itr).second);
}
}
} else {
stm->setSkipTagState();
}
}
void HashMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void HashMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setHashOfChecksum(characters);
stm->commitChecksumTransaction();
}
void PiecesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
if(name == HASH) {
stm->setPieceHashState();
std::map<std::string, std::string>::const_iterator itr = attrs.find(PIECE);
if(itr == attrs.end()) {
stm->cancelChunkChecksumTransaction();
} else {
try {
stm->createNewHashOfChunkChecksum(util::parseInt((*itr).second));
} catch(RecoverableException& e) {
stm->cancelChunkChecksumTransaction();
}
}
} else {
stm->setSkipTagState();
}
}
void PiecesMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->commitChunkChecksumTransaction();
}
void PieceHashMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void PieceHashMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setMessageDigestOfChunkChecksum(characters);
stm->addHashOfChunkChecksum();
}
void SignatureMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void SignatureMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setBodyOfSignature(characters);
stm->commitSignatureTransaction();
}
void ResourcesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
if(name == URL) {
stm->setURLState();
std::string type;
{
std::map<std::string, std::string>::const_iterator itr = attrs.find(TYPE);
if(itr == attrs.end()) {
return;
} else {
type = (*itr).second;
}
}
std::string location;
{
std::map<std::string, std::string>::const_iterator itr =
attrs.find(LOCATION);
if(itr != attrs.end()) {
location = util::toUpper((*itr).second);
}
}
int preference;
{
std::map<std::string, std::string>::const_iterator itr =
attrs.find(PREFERENCE);
if(itr == attrs.end()) {
preference = 0;
} else {
try {
preference = util::parseInt((*itr).second);
} catch(RecoverableException& e) {
preference = 0;
}
}
}
int maxConnections;
{
std::map<std::string, std::string>::const_iterator itr =
attrs.find(MAXCONNECTIONS);
if(itr == attrs.end()) {
maxConnections = -1;
} else {
try {
maxConnections = util::parseInt((*itr).second);
} catch(RecoverableException& e) {
maxConnections = -1;
}
}
}
stm->newResourceTransaction();
stm->setTypeOfResource(type);
stm->setLocationOfResource(location);
stm->setPreferenceOfResource(preference);
stm->setMaxConnectionsOfResource(maxConnections);
} else {
stm->setSkipTagState();
}
}
void URLMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
{
stm->setSkipTagState();
}
void URLMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters)
{
stm->setURLOfResource(characters);
stm->commitResourceTransaction();
}
void SkipTagMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs)
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
stm->setSkipTagState();
}

View File

@ -2,7 +2,7 @@
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 Tatsuhiro Tsujikawa
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -39,276 +39,24 @@
namespace aria2 {
class InitialMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const
{
return false;
}
};
class MetalinkMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const
{
return false;
}
};
class FilesMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class FileMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SizeMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class VersionMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class LanguageMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class OSMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class VerificationMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class HashMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class PiecesMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class PieceHashMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SignatureMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name, const std::map<std::string,
std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class ResourcesMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class URLMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SkipTagMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::map<std::string, std::string>& attrs);
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
};
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& name,
const std::string& characters) {}
virtual bool needsCharactersBuffering() const
{
return false;
}
class InitialMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
};
} // namespace aria2

View File

@ -34,6 +34,8 @@
/* copyright --> */
#include "MetalinkParserStateMachine.h"
#include "MetalinkParserStateImpl.h"
#include "MetalinkParserStateV3Impl.h"
#include "MetalinkParserStateV4Impl.h"
#include "Metalinker.h"
#include "MetalinkEntry.h"
@ -41,6 +43,9 @@ namespace aria2 {
MetalinkParserState* MetalinkParserStateMachine::_initialState =
new InitialMetalinkParserState();
MetalinkParserState* MetalinkParserStateMachine::_skipTagState =
new SkipTagMetalinkParserState();
MetalinkParserState* MetalinkParserStateMachine::_metalinkState =
new MetalinkMetalinkParserState();
MetalinkParserState* MetalinkParserStateMachine::_filesState =
@ -69,8 +74,29 @@ MetalinkParserState* MetalinkParserStateMachine::_resourcesState =
new ResourcesMetalinkParserState();
MetalinkParserState* MetalinkParserStateMachine::_urlState =
new URLMetalinkParserState();
MetalinkParserState* MetalinkParserStateMachine::_skipTagState =
new SkipTagMetalinkParserState();
MetalinkParserState* MetalinkParserStateMachine::_metalinkStateV4 =
new MetalinkMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_fileStateV4 =
new FileMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_sizeStateV4 =
new SizeMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_versionStateV4 =
new VersionMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_languageStateV4 =
new LanguageMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_osStateV4 =
new OSMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_hashStateV4 =
new HashMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_piecesStateV4 =
new PiecesMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_pieceHashStateV4 =
new PieceHashMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_signatureStateV4 =
new SignatureMetalinkParserStateV4();
MetalinkParserState* MetalinkParserStateMachine::_urlStateV4 =
new URLMetalinkParserStateV4();
MetalinkParserStateMachine::MetalinkParserStateMachine():
_ctrl(new MetalinkParserController())
@ -148,6 +174,61 @@ void MetalinkParserStateMachine::setURLState()
_stateStack.push(_urlState);
}
void MetalinkParserStateMachine::setMetalinkStateV4()
{
_stateStack.push(_metalinkStateV4);
}
void MetalinkParserStateMachine::setFileStateV4()
{
_stateStack.push(_fileStateV4);
}
void MetalinkParserStateMachine::setSizeStateV4()
{
_stateStack.push(_sizeStateV4);
}
void MetalinkParserStateMachine::setVersionStateV4()
{
_stateStack.push(_versionStateV4);
}
void MetalinkParserStateMachine::setLanguageStateV4()
{
_stateStack.push(_languageStateV4);
}
void MetalinkParserStateMachine::setOSStateV4()
{
_stateStack.push(_osStateV4);
}
void MetalinkParserStateMachine::setHashStateV4()
{
_stateStack.push(_hashStateV4);
}
void MetalinkParserStateMachine::setPiecesStateV4()
{
_stateStack.push(_piecesStateV4);
}
void MetalinkParserStateMachine::setPieceHashStateV4()
{
_stateStack.push(_pieceHashStateV4);
}
void MetalinkParserStateMachine::setSignatureStateV4()
{
_stateStack.push(_signatureStateV4);
}
void MetalinkParserStateMachine::setURLStateV4()
{
_stateStack.push(_urlStateV4);
}
void MetalinkParserStateMachine::setSkipTagState()
{
_stateStack.push(_skipTagState);
@ -219,9 +300,9 @@ void MetalinkParserStateMachine::setLocationOfResource
_ctrl->setLocationOfResource(location);
}
void MetalinkParserStateMachine::setPreferenceOfResource(int preference)
void MetalinkParserStateMachine::setPriorityOfResource(int priority)
{
_ctrl->setPreferenceOfResource(preference);
_ctrl->setPriorityOfResource(priority);
}
void MetalinkParserStateMachine::setMaxConnectionsOfResource(int maxConnections)
@ -264,6 +345,37 @@ void MetalinkParserStateMachine::cancelChecksumTransaction()
_ctrl->cancelChecksumTransaction();
}
void MetalinkParserStateMachine::newChunkChecksumTransactionV4()
{
_ctrl->newChunkChecksumTransactionV4();
}
void MetalinkParserStateMachine::setLengthOfChunkChecksumV4(size_t length)
{
_ctrl->setLengthOfChunkChecksumV4(length);
}
void MetalinkParserStateMachine::setTypeOfChunkChecksumV4
(const std::string& type)
{
_ctrl->setTypeOfChunkChecksumV4(type);
}
void MetalinkParserStateMachine::addHashOfChunkChecksumV4(const std::string& md)
{
_ctrl->addHashOfChunkChecksumV4(md);
}
void MetalinkParserStateMachine::commitChunkChecksumTransactionV4()
{
_ctrl->commitChunkChecksumTransactionV4();
}
void MetalinkParserStateMachine::cancelChunkChecksumTransactionV4()
{
_ctrl->cancelChunkChecksumTransactionV4();
}
void MetalinkParserStateMachine::newChunkChecksumTransaction()
{
_ctrl->newChunkChecksumTransaction();
@ -336,16 +448,21 @@ void MetalinkParserStateMachine::cancelSignatureTransaction()
}
void MetalinkParserStateMachine::beginElement
(const std::string& name,
const std::map<std::string, std::string>& attrs)
(const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
_stateStack.top()->beginElement(this, name, attrs);
_stateStack.top()->beginElement(this, localname, prefix, nsUri, attrs);
}
void MetalinkParserStateMachine::endElement
(const std::string& name, const std::string& characters)
(const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
_stateStack.top()->endElement(this, name, characters);
_stateStack.top()->endElement(this, localname, prefix, nsUri, characters);
_stateStack.pop();
}

View File

@ -37,15 +37,15 @@
#include "common.h"
#include <string>
#include <map>
#include <vector>
#include <stack>
#include "SharedHandle.h"
#include "MetalinkParserController.h"
#include "MetalinkParserState.h"
namespace aria2 {
class MetalinkParserState;
class Metalinker;
class MetalinkParserStateMachine {
@ -55,27 +55,44 @@ private:
std::stack<MetalinkParserState*> _stateStack;
static MetalinkParserState* _initialState;
static MetalinkParserState* _skipTagState;
// Metalink3
static MetalinkParserState* _metalinkState;
static MetalinkParserState* _filesState;
static MetalinkParserState* _filesState; // Metalink3Spec
static MetalinkParserState* _fileState;
static MetalinkParserState* _sizeState;
static MetalinkParserState* _versionState;
static MetalinkParserState* _languageState;
static MetalinkParserState* _osState;
static MetalinkParserState* _verificationState;
static MetalinkParserState* _verificationState; // Metalink3Spec
static MetalinkParserState* _hashState;
static MetalinkParserState* _piecesState;
static MetalinkParserState* _pieceHashState;
static MetalinkParserState* _piecesState; // Metalink3Spec
static MetalinkParserState* _pieceHashState; // Metalink3Spec
static MetalinkParserState* _signatureState;
static MetalinkParserState* _resourcesState;
static MetalinkParserState* _resourcesState; // Metalink3Spec
static MetalinkParserState* _urlState;
static MetalinkParserState* _skipTagState;
// Metalink4
static MetalinkParserState* _metalinkStateV4;
static MetalinkParserState* _fileStateV4;
static MetalinkParserState* _sizeStateV4;
static MetalinkParserState* _versionStateV4;
static MetalinkParserState* _languageStateV4;
static MetalinkParserState* _osStateV4;
static MetalinkParserState* _hashStateV4;
static MetalinkParserState* _piecesStateV4; // Metalink4Spec
static MetalinkParserState* _pieceHashStateV4; // Metalink4Spec
static MetalinkParserState* _signatureStateV4;
static MetalinkParserState* _urlStateV4;
public:
MetalinkParserStateMachine();
void setSkipTagState();
void setMetalinkState();
void setFilesState();
void setFilesState(); // Metalink3Spec
void setFileState();
@ -87,28 +104,46 @@ public:
void setOSState();
void setVerificationState();
void setVerificationState(); // Metalink3Spec
void setHashState();
void setPiecesState();
void setPiecesState(); // Metalink3Spec
void setPieceHashState();
void setPieceHashState(); // Metalink3Spec
void setSignatureState();
void setResourcesState();
void setResourcesState(); // Metalink3Spec
void setURLState();
void setSkipTagState();
// Metalink4
void setMetalinkStateV4();
void setFileStateV4();
void setSizeStateV4();
void setVersionStateV4();
void setLanguageStateV4();
void setOSStateV4();
void setHashStateV4();
void setPiecesStateV4(); // Metalink4Spec
void setPieceHashStateV4(); // Metalink4Spec
void setSignatureStateV4();
void setURLStateV4();
bool finished() const;
void beginElement
(const std::string& name, const std::map<std::string, std::string>& attrs);
(const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
void endElement(const std::string& name, const std::string& characters);
void endElement
(const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
void newEntryTransaction();
@ -122,7 +157,7 @@ public:
void setOSOfEntry(const std::string& os);
void setMaxConnectionsOfEntry(int maxConnections);
void setMaxConnectionsOfEntry(int maxConnections); // Metalink3Spec
void commitEntryTransaction();
@ -134,9 +169,9 @@ public:
void setLocationOfResource(const std::string& location);
void setPreferenceOfResource(int preference);
void setPriorityOfResource(int priority);
void setMaxConnectionsOfResource(int maxConnections);
void setMaxConnectionsOfResource(int maxConnections); // Metalink3Spec
void commitResourceTransaction();
@ -152,21 +187,33 @@ public:
void cancelChecksumTransaction();
void newChunkChecksumTransaction();
void newChunkChecksumTransactionV4(); // Metalink4Spec
void setLengthOfChunkChecksum(size_t length);
void setLengthOfChunkChecksumV4(size_t length); // Metalink4Spec
void setTypeOfChunkChecksum(const std::string& type);
void setTypeOfChunkChecksumV4(const std::string& type); // Metalink4Spec
void createNewHashOfChunkChecksum(size_t order);
void addHashOfChunkChecksumV4(const std::string& md); // Metalink4Spec
void setMessageDigestOfChunkChecksum(const std::string& md);
void commitChunkChecksumTransactionV4(); // Metalink4Spec
void addHashOfChunkChecksum();
void cancelChunkChecksumTransactionV4(); // Metalink4Spec
void commitChunkChecksumTransaction();
void newChunkChecksumTransaction(); // Metalink3Spec
void cancelChunkChecksumTransaction();
void setLengthOfChunkChecksum(size_t length); // Metalink3Spec
void setTypeOfChunkChecksum(const std::string& type); // Metalink3Spec
void createNewHashOfChunkChecksum(size_t order); // Metalink3Spec
void setMessageDigestOfChunkChecksum(const std::string& md); // Metalink3Spec
void addHashOfChunkChecksum(); // Metalink3Spec
void commitChunkChecksumTransaction(); // Metalink3Spec
void cancelChunkChecksumTransaction(); // Metalink3Spec
void newSignatureTransaction();

View File

@ -0,0 +1,430 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "MetalinkParserStateV3Impl.h"
#include "MetalinkParserStateMachine.h"
#include "RecoverableException.h"
#include "MetalinkResource.h"
#include "util.h"
namespace aria2 {
namespace {
const std::string FILE("file");
const std::string FILES("files");
const std::string HASH("hash");
const std::string LANGUAGE("language");
const std::string LENGTH("length");
const std::string LOCATION("location");
const std::string MAXCONNECTIONS("maxconnections");
// Can't use name VERSION because it is used as a macro.
const std::string METALINK_VERSION("version");
const std::string NAME("name");
const std::string OS("os");
const std::string PIECE("piece");
const std::string PIECES("pieces");
const std::string PREFERENCE("preference");
const std::string RESOURCES("resources");
const std::string SIGNATURE("signature");
const std::string SIZE("size");
const std::string TYPE("type");
const std::string URL("url");
const std::string VERIFICATION("verification");
}
const std::string METALINK3_NAMESPACE_URI("http://www.metalinker.org/");
namespace {
class FindAttr {
private:
const std::string& _localname;
public:
FindAttr(const std::string& localname):_localname(localname) {}
bool operator()(const XmlAttr& attr) const
{
return attr.localname == _localname &&
(attr.nsUri.empty() || attr.nsUri == METALINK3_NAMESPACE_URI);
}
};
}
template<typename Container>
static typename Container::const_iterator findAttr
(const Container& attrs, const std::string& localname)
{
return std::find_if(attrs.begin(), attrs.end(), FindAttr(localname));
}
void MetalinkMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri == METALINK3_NAMESPACE_URI && localname == FILES) {
stm->setFilesState();
} else {
stm->setSkipTagState();
}
}
void FilesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri == METALINK3_NAMESPACE_URI && localname == FILE) {
stm->setFileState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME);
if(itr != attrs.end()) {
stm->newEntryTransaction();
stm->setFileNameOfEntry(util::trim((*itr).value));
}
} else {
stm->setSkipTagState();
}
}
void FileMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri != METALINK3_NAMESPACE_URI) {
stm->setSkipTagState();
} else if(localname == SIZE) {
stm->setSizeState();
} else if(localname == METALINK_VERSION) {
stm->setVersionState();
} else if(localname == LANGUAGE) {
stm->setLanguageState();
} else if(localname == OS) {
stm->setOSState();
} else if(localname == VERIFICATION) {
stm->setVerificationState();
} else if(localname == RESOURCES) {
stm->setResourcesState();
int maxConnections;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs,MAXCONNECTIONS);
if(itr == attrs.end()) {
maxConnections = -1;
} else {
try {
maxConnections = util::parseInt((*itr).value);
} catch(RecoverableException& e) {
maxConnections = -1;
}
}
}
stm->setMaxConnectionsOfEntry(maxConnections);
} else {
stm->setSkipTagState();
}
}
void FileMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->commitEntryTransaction();
}
void SizeMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
try {
stm->setFileLengthOfEntry(util::parseLLInt(characters));
} catch(RecoverableException& e) {
// current metalink specification doesn't require size element.
}
}
void VersionMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setVersionOfEntry(util::trim(characters));
}
void LanguageMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setLanguageOfEntry(util::trim(characters));
}
void OSMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setOSOfEntry(util::trim(characters));
}
void VerificationMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri != METALINK3_NAMESPACE_URI) {
stm->setSkipTagState();
} else
#ifdef ENABLE_MESSAGE_DIGEST
if(localname == HASH) {
stm->setHashState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) {
return;
} else {
std::string type = util::trim((*itr).value);
stm->newChecksumTransaction();
stm->setTypeOfChecksum(type);
}
} else if(localname == PIECES) {
stm->setPiecesState();
try {
size_t length;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LENGTH);
if(itr == attrs.end()) {
return;
} else {
length = util::parseInt((*itr).value);
}
}
std::string type;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) {
return;
} else {
type = util::trim((*itr).value);
}
}
stm->newChunkChecksumTransaction();
stm->setLengthOfChunkChecksum(length);
stm->setTypeOfChunkChecksum(type);
} catch(RecoverableException& e) {
stm->cancelChunkChecksumTransaction();
}
} else
#endif // ENABLE_MESSAGE_DIGEST
if(localname == SIGNATURE) {
stm->setSignatureState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) {
return;
} else {
stm->newSignatureTransaction();
stm->setTypeOfSignature(util::trim((*itr).value));
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, FILE);
if(itr != attrs.end()) {
stm->setFileOfSignature(util::trim((*itr).value));
}
}
} else {
stm->setSkipTagState();
}
}
void HashMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setHashOfChecksum(util::trim(characters));
stm->commitChecksumTransaction();
}
void PiecesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri == METALINK3_NAMESPACE_URI && localname == HASH) {
stm->setPieceHashState();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PIECE);
if(itr == attrs.end()) {
stm->cancelChunkChecksumTransaction();
} else {
try {
stm->createNewHashOfChunkChecksum(util::parseInt((*itr).value));
} catch(RecoverableException& e) {
stm->cancelChunkChecksumTransaction();
}
}
} else {
stm->setSkipTagState();
}
}
void PiecesMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->commitChunkChecksumTransaction();
}
void PieceHashMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setMessageDigestOfChunkChecksum(util::trim(characters));
stm->addHashOfChunkChecksum();
}
void SignatureMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setBodyOfSignature(util::trim(characters));
stm->commitSignatureTransaction();
}
void ResourcesMetalinkParserState::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri != METALINK3_NAMESPACE_URI) {
stm->setSkipTagState();
} else if(localname == URL) {
stm->setURLState();
std::string type;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) {
return;
} else {
type = util::trim((*itr).value);
}
}
std::string location;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LOCATION);
if(itr != attrs.end()) {
location = util::trim((*itr).value);
}
}
int preference;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PREFERENCE);
if(itr == attrs.end()) {
preference = MetalinkResource::getLowestPriority();
} else {
try {
// In Metalink3Spec, highest prefernce value is 100. We
// uses Metalink4Spec priority unit system in which 1 is
// higest.
preference = 101-util::parseInt((*itr).value);
} catch(RecoverableException& e) {
preference = MetalinkResource::getLowestPriority();
}
}
}
int maxConnections;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs,MAXCONNECTIONS);
if(itr == attrs.end()) {
maxConnections = -1;
} else {
try {
maxConnections = util::parseInt((*itr).value);
} catch(RecoverableException& e) {
maxConnections = -1;
}
}
}
stm->newResourceTransaction();
stm->setTypeOfResource(type);
stm->setLocationOfResource(location);
stm->setPriorityOfResource(preference);
stm->setMaxConnectionsOfResource(maxConnections);
} else {
stm->setSkipTagState();
}
}
void URLMetalinkParserState::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setURLOfResource(util::trim(characters));
stm->commitResourceTransaction();
}
} // namespace aria2

View File

@ -0,0 +1,264 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_METALINK_PARSER_STATE_V3_IMPL_H_
#define _D_METALINK_PARSER_STATE_V3_IMPL_H_
#include "MetalinkParserState.h"
#include "MetalinkParserStateImpl.h"
namespace aria2 {
extern const std::string METALINK3_NAMESPACE_URI;
class MetalinkMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
};
class FilesMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class FileMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SizeMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class VersionMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class LanguageMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class OSMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class VerificationMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class HashMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class PiecesMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class PieceHashMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SignatureMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class ResourcesMetalinkParserState:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class URLMetalinkParserState:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
} // namespace aria2
#endif // _D_METALINK_PARSER_STATE_V3_IMPL_H_

View File

@ -0,0 +1,366 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "MetalinkParserStateV4Impl.h"
#include "MetalinkParserStateMachine.h"
#include "RecoverableException.h"
#include "MetalinkResource.h"
#include "util.h"
namespace aria2 {
namespace {
const std::string FILE("file");
const std::string HASH("hash");
const std::string LANGUAGE("language");
const std::string LENGTH("length");
const std::string LOCATION("location");
const std::string METALINK("metalink");
// Can't use name VERSION because it is used as a macro.
const std::string METALINK_VERSION("version");
const std::string METAURL("metaurl");
const std::string NAME("name");
const std::string OS("os");
const std::string PIECE("piece");
const std::string PIECES("pieces");
const std::string PRIORITY("priority");
const std::string SIGNATURE("signature");
const std::string SIZE("size");
const std::string TYPE("type");
const std::string MEDIATYPE("mediatype");
const std::string URL("url");
}
const std::string METALINK4_NAMESPACE_URI("urn:ietf:params:xml:ns:metalink");
namespace {
class FindAttr {
private:
const std::string& _localname;
public:
FindAttr(const std::string& localname):_localname(localname) {}
bool operator()(const XmlAttr& attr) const
{
return attr.localname == _localname &&
(attr.nsUri.empty() || attr.nsUri == METALINK4_NAMESPACE_URI);
}
};
}
template<typename Container>
static typename Container::const_iterator findAttr
(const Container& attrs, const std::string& localname)
{
return std::find_if(attrs.begin(), attrs.end(), FindAttr(localname));
}
void MetalinkMetalinkParserStateV4::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri == METALINK4_NAMESPACE_URI && localname == FILE) {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME);
if(itr != attrs.end()) {
// TODO Windows path separator support.
if(util::detectDirTraversal((*itr).value)) {
stm->setSkipTagState();
} else {
stm->setFileStateV4();
stm->newEntryTransaction();
stm->setFileNameOfEntry((*itr).value);
}
}
} else {
stm->setSkipTagState();
}
}
void FileMetalinkParserStateV4::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri != METALINK4_NAMESPACE_URI) {
stm->setSkipTagState();
} else if(localname == SIZE) {
stm->setSizeStateV4();
} else if(localname == METALINK_VERSION) {
stm->setVersionStateV4();
} else if(localname == LANGUAGE) {
stm->setLanguageStateV4();
} else if(localname == OS) {
stm->setOSStateV4();
} else if(localname == METAURL) {
stm->setURLStateV4();
// TODO currently NAME is ignored
int priority;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PRIORITY);
if(itr == attrs.end()) {
priority = MetalinkResource::getLowestPriority();
} else {
try {
priority = util::parseInt((*itr).value);
if(priority < 1 || MetalinkResource::getLowestPriority() < priority) {
priority = MetalinkResource::getLowestPriority();
}
} catch(RecoverableException& e) {
priority = MetalinkResource::getLowestPriority();
}
}
}
std::string mediatype;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE);
if(itr == attrs.end()) {
return;
} else {
mediatype = (*itr).value;
}
}
stm->newResourceTransaction();
stm->setPriorityOfResource(priority);
stm->setTypeOfResource(mediatype);
} else if(localname == URL) {
stm->setURLStateV4();
std::string location;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LOCATION);
if(itr != attrs.end()) {
location = (*itr).value;
}
}
int priority;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, PRIORITY);
if(itr == attrs.end()) {
priority = MetalinkResource::getLowestPriority();
} else {
try {
priority = util::parseInt((*itr).value);
if(priority < 1 || MetalinkResource::getLowestPriority() < priority) {
priority = MetalinkResource::getLowestPriority();
}
} catch(RecoverableException& e) {
priority = MetalinkResource::getLowestPriority();
}
}
}
stm->newResourceTransaction();
stm->setLocationOfResource(location);
stm->setPriorityOfResource(priority);
}
#ifdef ENABLE_MESSAGE_DIGEST
else if(localname == HASH) {
stm->setHashStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) {
return;
} else {
std::string type = (*itr).value;
stm->newChecksumTransaction();
stm->setTypeOfChecksum(type);
}
} else if(localname == PIECES) {
stm->setPiecesStateV4();
try {
size_t length;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LENGTH);
if(itr == attrs.end()) {
return;
} else {
length = util::parseInt((*itr).value);
}
}
std::string type;
{
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) {
return;
} else {
type = (*itr).value;
}
}
stm->newChunkChecksumTransactionV4();
stm->setLengthOfChunkChecksumV4(length);
stm->setTypeOfChunkChecksumV4(type);
} catch(RecoverableException& e) {
stm->cancelChunkChecksumTransactionV4();
}
}
#endif // ENABLE_MESSAGE_DIGEST
else if(localname == SIGNATURE) {
stm->setSignatureStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE);
if(itr == attrs.end()) {
return;
} else {
stm->newSignatureTransaction();
stm->setTypeOfSignature((*itr).value);
}
} else {
stm->setSkipTagState();
}
}
void FileMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->commitEntryTransaction();
}
void SizeMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
try {
stm->setFileLengthOfEntry(util::parseLLInt(characters));
} catch(RecoverableException& e) {
// current metalink specification doesn't require size element.
}
}
void VersionMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setVersionOfEntry(characters);
}
void LanguageMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setLanguageOfEntry(characters);
}
void OSMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setOSOfEntry(characters);
}
void HashMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setHashOfChecksum(characters);
stm->commitChecksumTransaction();
}
void PiecesMetalinkParserStateV4::beginElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs)
{
if(nsUri == METALINK4_NAMESPACE_URI && localname == HASH) {
stm->setPieceHashStateV4();
} else {
stm->setSkipTagState();
}
}
void PiecesMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->commitChunkChecksumTransaction();
}
void PieceHashMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->addHashOfChunkChecksumV4(characters);
}
void SignatureMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setBodyOfSignature(characters);
stm->commitSignatureTransaction();
}
void URLMetalinkParserStateV4::endElement
(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters)
{
stm->setURLOfResource(characters);
stm->commitResourceTransaction();
}
} // namespace aria2

View File

@ -0,0 +1,219 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2010 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_METALINK_PARSER_STATE_V4_IMPL_H_
#define _D_METALINK_PARSER_STATE_V4_IMPL_H_
#include "MetalinkParserState.h"
#include "MetalinkParserStateImpl.h"
namespace aria2 {
extern const std::string METALINK4_NAMESPACE_URI;
class MetalinkMetalinkParserStateV4:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
};
class FileMetalinkParserStateV4:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SizeMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class VersionMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class LanguageMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class OSMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class HashMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class PiecesMetalinkParserStateV4:public MetalinkParserState
{
public:
virtual void beginElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::vector<XmlAttr>& attrs);
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class PieceHashMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class SignatureMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
class URLMetalinkParserStateV4:public SkipTagMetalinkParserState
{
public:
virtual void endElement(MetalinkParserStateMachine* stm,
const std::string& localname,
const std::string& prefix,
const std::string& nsUri,
const std::string& characters);
virtual bool needsCharactersBuffering() const
{
return true;
}
};
} // namespace aria2
#endif // _D_METALINK_PARSER_STATE_IMPL_H_

View File

@ -37,7 +37,7 @@
namespace aria2 {
std::string MetalinkResource::type2String[] = {
"ftp", "http", "https", "bittorrent", "not_supported"
"ftp", "http", "https", "bittorrent", "not_supported", "unknown"
};
const std::string MetalinkResource::HTTP("http");
@ -48,7 +48,11 @@ const std::string MetalinkResource::FTP("ftp");
const std::string MetalinkResource::BITTORRENT("bittorrent");
const std::string MetalinkResource::TORRENT("torrent");
MetalinkResource::MetalinkResource():
type(TYPE_UNKNOWN),
priority(getLowestPriority()),
maxConnections(-1)
{}

View File

@ -47,7 +47,8 @@ public:
TYPE_HTTP,
TYPE_HTTPS,
TYPE_BITTORRENT,
TYPE_NOT_SUPPORTED
TYPE_NOT_SUPPORTED,
TYPE_UNKNOWN
};
static std::string type2String[];
@ -60,12 +61,14 @@ public:
static const std::string BITTORRENT;
static const std::string TORRENT; // Metalink4Spec
public:
std::string url;
TYPE type;
std::string location;
int preference;
int maxConnections;
int priority;
int maxConnections; // Metalink3Spec
public:
MetalinkResource();
~MetalinkResource();
@ -75,7 +78,7 @@ public:
this->url = metalinkResource.url;
this->type = metalinkResource.type;
this->location = metalinkResource.location;
this->preference = metalinkResource.preference;
this->priority = metalinkResource.priority;
this->maxConnections = metalinkResource.maxConnections;
}
return *this;
@ -85,6 +88,11 @@ public:
{
return type2String[type];
}
static int getLowestPriority()
{
return 999999;
}
};
} // namespace aria2

View File

@ -62,12 +62,12 @@ public:
}
}
if(!language.empty()) {
if(language != entry->language) {
if(!entry->containsLanguage(language)) {
return false;
}
}
if(!os.empty()) {
if(os != entry->os) {
if(!entry->containsOS(os)) {
return false;
}
}

View File

@ -110,8 +110,6 @@ namespace aria2 {
int32_t RequestGroup::_gidCounter = 0;
const std::string RequestGroup::ACCEPT_METALINK = "application/metalink+xml";
RequestGroup::RequestGroup(const SharedHandle<Option>& option):
_gid(newGID()),
_option(new Option(*option.get())),
@ -138,8 +136,9 @@ RequestGroup::RequestGroup(const SharedHandle<Option>& option):
// Add types to be sent as a Accept header value here.
// It would be good to put this value in Option so that user can tweak
// and add this list.
// ACCEPT_METALINK is used for `transparent metalink'.
addAcceptType(ACCEPT_METALINK);
// The mime types of Metalink is used for `transparent metalink'.
addAcceptType(DownloadHandlerConstants::getMetalinkContentTypes().begin(),
DownloadHandlerConstants::getMetalinkContentTypes().end());
if(!_option->getAsBool(PREF_DRY_RUN)) {
initializePreDownloadHandler();
initializePostDownloadHandler();

View File

@ -39,6 +39,7 @@
#include <string>
#include <deque>
#include <algorithm>
#include <vector>
#include "SharedHandle.h"
@ -379,9 +380,18 @@ public:
void addAcceptType(const std::string& type);
void removeAcceptType(const std::string& type);
template<typename InputIterator>
void addAcceptType(InputIterator first, InputIterator last)
{
for(; first != last; ++first) {
if(std::find(_acceptTypes.begin(), _acceptTypes.end(), *first) ==
_acceptTypes.end()) {
_acceptTypes.push_back(*first);
}
}
}
static const std::string ACCEPT_METALINK;
void removeAcceptType(const std::string& type);
void setURISelector(const SharedHandle<URISelector>& uriSelector);

View File

@ -33,6 +33,9 @@
*/
/* copyright --> */
#include "XML2SAXMetalinkProcessor.h"
#include <cassert>
#include "BinaryStream.h"
#include "MetalinkParserStateMachine.h"
#include "Metalinker.h"
@ -40,6 +43,7 @@
#include "util.h"
#include "message.h"
#include "DlAbortEx.h"
#include "A2STR.h"
namespace aria2 {
@ -52,38 +56,73 @@ public:
SessionData(const SharedHandle<MetalinkParserStateMachine>& stm):_stm(stm) {}
};
static void mlStartElement(void* userData, const xmlChar* name, const xmlChar** attrs)
static void mlStartElement
(void* userData,
const xmlChar* srcLocalname,
const xmlChar* srcPrefix,
const xmlChar* srcNsUri,
int numNamespaces,
const xmlChar **namespaces,
int numAttrs,
int numDefaulted,
const xmlChar **attrs)
{
SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::map<std::string, std::string> attrmap;
if(attrs) {
const xmlChar** p = attrs;
while(*p != 0) {
std::string name = reinterpret_cast<const char*>(*p);
++p;
if(*p == 0) {
break;
}
std::string value = util::trim(reinterpret_cast<const char*>(*p));
++p;
attrmap[name] = value;
std::vector<XmlAttr> xmlAttrs;
size_t index = 0;
for(int attrIndex = 0; attrIndex < numAttrs; ++attrIndex, index += 5) {
XmlAttr xmlAttr;
assert(attrs[index]);
xmlAttr.localname = reinterpret_cast<const char*>(attrs[index]);
if(attrs[index+1]) {
xmlAttr.prefix = reinterpret_cast<const char*>(attrs[index+1]);
}
if(attrs[index+2]) {
xmlAttr.nsUri = reinterpret_cast<const char*>(attrs[index+2]);
}
const char* valueBegin = reinterpret_cast<const char*>(attrs[index+3]);
const char* valueEnd = reinterpret_cast<const char*>(attrs[index+4]);
xmlAttr.value = std::string(valueBegin, valueEnd);
xmlAttrs.push_back(xmlAttr);
}
sd->_stm->beginElement(reinterpret_cast<const char*>(name), attrmap);
assert(srcLocalname);
std::string localname = reinterpret_cast<const char*>(srcLocalname);
std::string prefix;
std::string nsUri;
if(srcPrefix) {
prefix = reinterpret_cast<const char*>(srcPrefix);
}
if(srcNsUri) {
nsUri = reinterpret_cast<const char*>(srcNsUri);
}
sd->_stm->beginElement(localname, prefix, nsUri, xmlAttrs);
if(sd->_stm->needsCharactersBuffering()) {
sd->_charactersStack.push_front(std::string());
sd->_charactersStack.push_front(A2STR::NIL);
}
}
static void mlEndElement(void* userData, const xmlChar* name)
static void mlEndElement
(void* userData,
const xmlChar* srcLocalname,
const xmlChar* srcPrefix,
const xmlChar* srcNsUri)
{
SessionData* sd = reinterpret_cast<SessionData*>(userData);
std::string characters;
if(sd->_stm->needsCharactersBuffering()) {
characters = util::trim(sd->_charactersStack.front());
characters = sd->_charactersStack.front();
sd->_charactersStack.pop_front();
}
sd->_stm->endElement(reinterpret_cast<const char*>(name), characters);
std::string localname = reinterpret_cast<const char*>(srcLocalname);
std::string prefix;
std::string nsUri;
if(srcPrefix) {
prefix = reinterpret_cast<const char*>(srcPrefix);
}
if(srcNsUri) {
nsUri = reinterpret_cast<const char*>(srcNsUri);
}
sd->_stm->endElement(localname, prefix, nsUri, characters);
}
static void mlCharacters(void* userData, const xmlChar* ch, int len)
@ -110,8 +149,8 @@ static xmlSAXHandler mySAXHandler =
0, // setDocumentLocatorSAXFunc
0, // startDocumentSAXFunc
0, // endDocumentSAXFunc
&mlStartElement, // startElementSAXFunc
&mlEndElement, // endElementSAXFunc
0, // startElementSAXFunc
0, // endElementSAXFunc
0, // referenceSAXFunc
&mlCharacters, // charactersSAXFunc
0, // ignorableWhitespaceSAXFunc
@ -123,10 +162,10 @@ static xmlSAXHandler mySAXHandler =
0, // getParameterEntitySAXFunc
0, // cdataBlockSAXFunc
0, // externalSubsetSAXFunc
0, // unsigned int initialized
XML_SAX2_MAGIC, // unsigned int initialized
0, // void * _private
0, // startElementNsSAX2Func
0, // endElementNsSAX2Func
&mlStartElement, // startElementNsSAX2Func
&mlEndElement, // endElementNsSAX2Func
0, // xmlStructuredErrorFunc
};

View File

@ -37,22 +37,26 @@
namespace aria2 {
const std::string MessageDigestContext::SHA1("sha1");
const std::string MessageDigestContext::SHA1("sha-1");
const std::string MessageDigestContext::SHA256("sha256");
const std::string MessageDigestContext::SHA256("sha-256");
const std::string MessageDigestContext::MD5("md5");
const std::string MessageDigestContext::MD5("md-5");
static MessageDigestContext::DigestAlgoMap::value_type digests[] = {
#ifdef HAVE_LIBSSL
MessageDigestContext::DigestAlgoMap::value_type("md5", EVP_md5()),
MessageDigestContext::DigestAlgoMap::value_type("sha-1", EVP_sha1()),
MessageDigestContext::DigestAlgoMap::value_type("sha1", EVP_sha1()),
# ifdef HAVE_EVP_SHA256
MessageDigestContext::DigestAlgoMap::value_type("sha-256", EVP_sha256()),
MessageDigestContext::DigestAlgoMap::value_type("sha256", EVP_sha256()),
# endif // HAVE_EVP_SHA256
#elif HAVE_LIBGCRYPT
MessageDigestContext::DigestAlgoMap::value_type("md5", GCRY_MD_MD5),
MessageDigestContext::DigestAlgoMap::value_type("sha-1", GCRY_MD_SHA1),
MessageDigestContext::DigestAlgoMap::value_type("sha1", GCRY_MD_SHA1),
MessageDigestContext::DigestAlgoMap::value_type("sha-256", GCRY_MD_SHA256),
MessageDigestContext::DigestAlgoMap::value_type("sha256", GCRY_MD_SHA256),
#endif // HAVE_LIBGCRYPT
};

View File

@ -1167,6 +1167,20 @@ bool inPrivateAddress(const std::string& ipv4addr)
return false;
}
bool detectDirTraversal(const std::string& s)
{
return s == A2STR::DOT_C ||
s == ".." ||
util::startsWith(s, A2STR::SLASH_C) ||
util::startsWith(s, "./") ||
util::startsWith(s, "../") ||
s.find("/../") != std::string::npos ||
s.find("/./") != std::string::npos ||
util::endsWith(s, "/") ||
util::endsWith(s, "/.") ||
util::endsWith(s, "/..");
}
} // namespace util
} // namespace aria2

View File

@ -381,6 +381,10 @@ void generateRandomKey(unsigned char* key);
// Returns true is given numeric ipv4addr is in Private Address Space.
bool inPrivateAddress(const std::string& ipv4addr);
// Returns true if s contains directory traversal path component such
// as '..'.
bool detectDirTraversal(const std::string& s);
} // namespace util
} // namespace aria2

View File

@ -247,4 +247,7 @@ EXTRA_DIST = 4096chunk.txt\
url-list-singleFileEndsWithSlash.torrent\
input_uris.txt\
2files.metalink\
utf8.torrent
utf8.torrent\
metalink4.xml\
metalink4-attrs.xml\
metalink4-dirtraversal.xml

View File

@ -685,7 +685,10 @@ EXTRA_DIST = 4096chunk.txt\
url-list-singleFileEndsWithSlash.torrent\
input_uris.txt\
2files.metalink\
utf8.torrent
utf8.torrent\
metalink4.xml\
metalink4-attrs.xml\
metalink4-dirtraversal.xml
all: all-am

View File

@ -1,16 +1,18 @@
#include "MetalinkEntry.h"
#include "MetalinkResource.h"
#include <cppunit/extensions/HelperMacros.h>
#include "MetalinkResource.h"
namespace aria2 {
class MetalinkEntryTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MetalinkEntryTest);
CPPUNIT_TEST(testDropUnsupportedResource);
CPPUNIT_TEST(testReorderResourcesByPreference);
CPPUNIT_TEST(testSetLocationPreference);
CPPUNIT_TEST(testSetProtocolPreference);
CPPUNIT_TEST(testReorderResourcesByPriority);
CPPUNIT_TEST(testSetLocationPriority);
CPPUNIT_TEST(testSetProtocolPriority);
CPPUNIT_TEST_SUITE_END();
private:
@ -21,9 +23,9 @@ public:
}
void testDropUnsupportedResource();
void testReorderResourcesByPreference();
void testSetLocationPreference();
void testSetProtocolPreference();
void testReorderResourcesByPriority();
void testSetLocationPriority();
void testSetProtocolPriority();
};
@ -34,28 +36,28 @@ SharedHandle<MetalinkEntry> createTestEntry() {
SharedHandle<MetalinkResource> res1(new MetalinkResource());
res1->url = "ftp://myhost/aria2.tar.bz2";
res1->type = MetalinkResource::TYPE_FTP;
res1->location = "RO";
res1->preference = 50;
res1->location = "ro";
res1->priority = 50;
SharedHandle<MetalinkResource> res2(new MetalinkResource());
res2->url = "http://myhost/aria2.tar.bz2";
res2->type = MetalinkResource::TYPE_HTTP;
res2->location = "AT";
res2->preference = 100;
res2->location = "at";
res2->priority = 1;
SharedHandle<MetalinkResource> res3(new MetalinkResource());
res3->url = "http://myhost/aria2.torrent";
res3->type = MetalinkResource::TYPE_BITTORRENT;
res3->location = "AL";
res3->preference = 60;
res3->location = "al";
res3->priority = 40;
SharedHandle<MetalinkResource> res4(new MetalinkResource());
res4->url = "http://myhost/aria2.ext";
res4->type = MetalinkResource::TYPE_NOT_SUPPORTED;
res4->location = "AD";
res4->preference = 10;
res4->location = "ad";
res4->priority = 90;
SharedHandle<MetalinkResource> res5(new MetalinkResource());
res5->url = "https://myhost/aria2.tar.bz2";
res5->type = MetalinkResource::TYPE_HTTPS;
res5->location = "JP";
res5->preference = 90;
res5->location = "jp";
res5->priority = 10;
entry->resources.push_back(res1);
entry->resources.push_back(res2);
@ -93,49 +95,49 @@ void MetalinkEntryTest::testDropUnsupportedResource() {
#endif // ENABLE_SSL
}
void MetalinkEntryTest::testReorderResourcesByPreference() {
void MetalinkEntryTest::testReorderResourcesByPriority() {
SharedHandle<MetalinkEntry> entry(createTestEntry());
entry->reorderResourcesByPreference();
entry->reorderResourcesByPriority();
CPPUNIT_ASSERT_EQUAL(100, entry->resources.at(0)->preference);
CPPUNIT_ASSERT_EQUAL(90, entry->resources.at(1)->preference);
CPPUNIT_ASSERT_EQUAL(60, entry->resources.at(2)->preference);
CPPUNIT_ASSERT_EQUAL(50, entry->resources.at(3)->preference);
CPPUNIT_ASSERT_EQUAL(10, entry->resources.at(4)->preference);
CPPUNIT_ASSERT_EQUAL(1, entry->resources.at(0)->priority);
CPPUNIT_ASSERT_EQUAL(10, entry->resources.at(1)->priority);
CPPUNIT_ASSERT_EQUAL(40, entry->resources.at(2)->priority);
CPPUNIT_ASSERT_EQUAL(50, entry->resources.at(3)->priority);
CPPUNIT_ASSERT_EQUAL(90, entry->resources.at(4)->priority);
}
void MetalinkEntryTest::testSetLocationPreference()
void MetalinkEntryTest::testSetLocationPriority()
{
SharedHandle<MetalinkEntry> entry(createTestEntry());
const char* locationsSrc[] = { "jp", "al", "RO" };
const char* locationsSrc[] = { "jp", "al", "ro" };
std::deque<std::string> locations(&locationsSrc[0], &locationsSrc[3]);
entry->setLocationPreference(locations, 100);
entry->setLocationPriority(locations, -100);
CPPUNIT_ASSERT_EQUAL(std::string("RO"), entry->resources[0]->location);
CPPUNIT_ASSERT_EQUAL(150, entry->resources[0]->preference);
CPPUNIT_ASSERT_EQUAL(std::string("AT"), entry->resources[1]->location);
CPPUNIT_ASSERT_EQUAL(100, entry->resources[1]->preference);
CPPUNIT_ASSERT_EQUAL(std::string("AL"), entry->resources[2]->location);
CPPUNIT_ASSERT_EQUAL(160, entry->resources[2]->preference);
CPPUNIT_ASSERT_EQUAL(std::string("AD"), entry->resources[3]->location);
CPPUNIT_ASSERT_EQUAL(10, entry->resources[3]->preference);
CPPUNIT_ASSERT_EQUAL(std::string("JP"), entry->resources[4]->location);
CPPUNIT_ASSERT_EQUAL(190, entry->resources[4]->preference);
CPPUNIT_ASSERT_EQUAL(std::string("ro"), entry->resources[0]->location);
CPPUNIT_ASSERT_EQUAL(-50, entry->resources[0]->priority);
CPPUNIT_ASSERT_EQUAL(std::string("at"), entry->resources[1]->location);
CPPUNIT_ASSERT_EQUAL(1, entry->resources[1]->priority);
CPPUNIT_ASSERT_EQUAL(std::string("al"), entry->resources[2]->location);
CPPUNIT_ASSERT_EQUAL(-60, entry->resources[2]->priority);
CPPUNIT_ASSERT_EQUAL(std::string("ad"), entry->resources[3]->location);
CPPUNIT_ASSERT_EQUAL(90, entry->resources[3]->priority);
CPPUNIT_ASSERT_EQUAL(std::string("jp"), entry->resources[4]->location);
CPPUNIT_ASSERT_EQUAL(-90, entry->resources[4]->priority);
}
void MetalinkEntryTest::testSetProtocolPreference()
void MetalinkEntryTest::testSetProtocolPriority()
{
SharedHandle<MetalinkEntry> 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
entry->setProtocolPriority("http", -1);
CPPUNIT_ASSERT_EQUAL(50, entry->resources[0]->priority); // ftp
CPPUNIT_ASSERT_EQUAL(0, entry->resources[1]->priority); // http, -1
CPPUNIT_ASSERT_EQUAL(40, entry->resources[2]->priority); // bittorrent
CPPUNIT_ASSERT_EQUAL(90, entry->resources[3]->priority); // not supported
CPPUNIT_ASSERT_EQUAL(10, entry->resources[4]->priority); // https
}
} // namespace aria2

View File

@ -1,4 +1,7 @@
#include "MetalinkParserController.h"
#include <cppunit/extensions/HelperMacros.h>
#include "Metalinker.h"
#include "MetalinkEntry.h"
#include "MetalinkResource.h"
@ -8,7 +11,6 @@
# include "ChunkChecksum.h"
#endif // ENABLE_MESSAGE_DIGEST
#include "Signature.h"
#include <cppunit/extensions/HelperMacros.h>
namespace aria2 {
@ -20,6 +22,7 @@ class MetalinkParserControllerTest:public CppUnit::TestFixture {
#ifdef ENABLE_MESSAGE_DIGEST
CPPUNIT_TEST(testChecksumTransaction);
CPPUNIT_TEST(testChunkChecksumTransaction);
CPPUNIT_TEST(testChunkChecksumTransactionV4);
#endif // ENABLE_MESSAGE_DIGEST
CPPUNIT_TEST(testSignatureTransaction);
@ -36,6 +39,7 @@ public:
#ifdef ENABLE_MESSAGE_DIGEST
void testChecksumTransaction();
void testChunkChecksumTransaction();
void testChunkChecksumTransactionV4();
#endif // ENABLE_MESSAGE_DIGEST
void testSignatureTransaction();
};
@ -62,8 +66,8 @@ void MetalinkParserControllerTest::testEntryTransaction()
CPPUNIT_ASSERT_EQUAL((uint64_t)(1024*1024ULL), e->file->getLength());
CPPUNIT_ASSERT_EQUAL((off_t)0, e->file->getOffset());
CPPUNIT_ASSERT_EQUAL(std::string("1.0"), e->version);
CPPUNIT_ASSERT_EQUAL(std::string("ja_JP"), e->language);
CPPUNIT_ASSERT_EQUAL(std::string("Linux"), e->os);
CPPUNIT_ASSERT_EQUAL(std::string("ja_JP"), e->languages[0]);
CPPUNIT_ASSERT_EQUAL(std::string("Linux"), e->oses[0]);
}
ctrl.newEntryTransaction();
ctrl.cancelEntryTransaction();
@ -78,7 +82,7 @@ void MetalinkParserControllerTest::testResourceTransaction()
ctrl.setURLOfResource("http://mirror/aria2.tar.bz2");
ctrl.setTypeOfResource("http");
ctrl.setLocationOfResource("US");
ctrl.setPreferenceOfResource(100);
ctrl.setPriorityOfResource(100);
ctrl.setMaxConnectionsOfResource(1);
ctrl.commitEntryTransaction();
{
@ -88,7 +92,7 @@ void MetalinkParserControllerTest::testResourceTransaction()
CPPUNIT_ASSERT_EQUAL(std::string("http://mirror/aria2.tar.bz2"), res->url);
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, res->type);
CPPUNIT_ASSERT_EQUAL(std::string("US"), res->location);
CPPUNIT_ASSERT_EQUAL(100, res->preference);
CPPUNIT_ASSERT_EQUAL(100, res->priority);
CPPUNIT_ASSERT_EQUAL(1, res->maxConnections);
}
ctrl.newEntryTransaction();
@ -151,6 +155,34 @@ void MetalinkParserControllerTest::testChunkChecksumTransaction()
ctrl.commitEntryTransaction();
CPPUNIT_ASSERT(ctrl.getResult()->entries[1]->chunkChecksum.isNull());
}
void MetalinkParserControllerTest::testChunkChecksumTransactionV4()
{
MetalinkParserController ctrl;
ctrl.newEntryTransaction();
ctrl.newChunkChecksumTransactionV4();
ctrl.setTypeOfChunkChecksumV4("md5");
ctrl.setLengthOfChunkChecksumV4(256*1024);
ctrl.addHashOfChunkChecksumV4("hash1");
ctrl.addHashOfChunkChecksumV4("hash2");
ctrl.addHashOfChunkChecksumV4("hash3");
ctrl.commitEntryTransaction();
{
SharedHandle<Metalinker> m = ctrl.getResult();
SharedHandle<ChunkChecksum> md = m->entries.front()->chunkChecksum;
CPPUNIT_ASSERT_EQUAL(std::string("md5"), md->getAlgo());
CPPUNIT_ASSERT_EQUAL((size_t)256*1024, md->getChecksumLength());
CPPUNIT_ASSERT_EQUAL((size_t)3, md->countChecksum());
CPPUNIT_ASSERT_EQUAL(std::string("hash1"), md->getChecksums()[0]);
CPPUNIT_ASSERT_EQUAL(std::string("hash2"), md->getChecksums()[1]);
CPPUNIT_ASSERT_EQUAL(std::string("hash3"), md->getChecksums()[2]);
}
ctrl.newEntryTransaction();
ctrl.newChunkChecksumTransactionV4();
ctrl.cancelChunkChecksumTransactionV4();
ctrl.commitEntryTransaction();
CPPUNIT_ASSERT(ctrl.getResult()->entries[1]->chunkChecksum.isNull());
}
#endif // ENABLE_MESSAGE_DIGEST
void MetalinkParserControllerTest::testSignatureTransaction()

View File

@ -22,6 +22,9 @@ namespace aria2 {
class MetalinkProcessorTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MetalinkProcessorTest);
CPPUNIT_TEST(testParseFileV4);
CPPUNIT_TEST(testParseFileV4_dirtraversal);
CPPUNIT_TEST(testParseFileV4_attrs);
CPPUNIT_TEST(testParseFile);
CPPUNIT_TEST(testParseFromBinaryStream);
CPPUNIT_TEST(testMalformedXML);
@ -39,10 +42,14 @@ class MetalinkProcessorTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testUnsupportedType_piece);
#endif // ENABLE_MESSAGE_DIGEST
CPPUNIT_TEST(testLargeFileSize);
CPPUNIT_TEST(testXmlPrefixV3);
CPPUNIT_TEST_SUITE_END();
private:
public:
void testParseFileV4();
void testParseFileV4_dirtraversal();
void testParseFileV4_attrs();
void testParseFile();
void testParseFromBinaryStream();
void testMalformedXML();
@ -60,11 +67,89 @@ public:
void testUnsupportedType_piece();
#endif // ENABLE_MESSAGE_DIGEST
void testLargeFileSize();
void testXmlPrefixV3();
};
CPPUNIT_TEST_SUITE_REGISTRATION( MetalinkProcessorTest );
void MetalinkProcessorTest::testParseFileV4()
{
MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4.xml");
SharedHandle<MetalinkEntry> e;
SharedHandle<MetalinkResource> r;
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
e = m->entries[0];
CPPUNIT_ASSERT_EQUAL(std::string("example.ext"), e->getPath());
CPPUNIT_ASSERT_EQUAL((uint64_t)786430LL, e->getLength());
CPPUNIT_ASSERT_EQUAL(-1, e->maxConnections);
#ifdef ENABLE_MESSAGE_DIGEST
CPPUNIT_ASSERT_EQUAL(std::string("80bc95fd391772fa61c91ed68567f0980bb45fd9"),
e->checksum->getMessageDigest());
CPPUNIT_ASSERT(!e->checksum.isNull());
CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), e->checksum->getAlgo());
CPPUNIT_ASSERT(!e->chunkChecksum.isNull());
CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), e->chunkChecksum->getAlgo());
CPPUNIT_ASSERT_EQUAL((size_t)262144, e->chunkChecksum->getChecksumLength());
CPPUNIT_ASSERT_EQUAL((size_t)3, e->chunkChecksum->countChecksum());
CPPUNIT_ASSERT_EQUAL(std::string("metalinkhash1"),
e->chunkChecksum->getChecksum(0));
CPPUNIT_ASSERT_EQUAL(std::string("metalinkhash2"),
e->chunkChecksum->getChecksum(1));
CPPUNIT_ASSERT_EQUAL(std::string("metalinkhash3"),
e->chunkChecksum->getChecksum(2));
#endif // ENABLE_MESSAGE_DIGEST
CPPUNIT_ASSERT(!e->getSignature().isNull());
CPPUNIT_ASSERT_EQUAL(std::string("application/pgp-signature"),
e->getSignature()->getType());
CPPUNIT_ASSERT_EQUAL(std::string("a signature"),
e->getSignature()->getBody());
CPPUNIT_ASSERT_EQUAL((size_t)3, e->resources.size());
r = e->resources[0];
CPPUNIT_ASSERT_EQUAL(std::string("ftp://ftp.example.com/example.ext"),
r->url);
CPPUNIT_ASSERT_EQUAL(std::string("de"), r->location);
CPPUNIT_ASSERT_EQUAL(1, r->priority);
CPPUNIT_ASSERT_EQUAL(std::string("ftp"),
MetalinkResource::getTypeString(r->type));
CPPUNIT_ASSERT_EQUAL(-1, r->maxConnections);
r = e->resources[2];
CPPUNIT_ASSERT_EQUAL(std::string("http://example.com/example.ext.torrent"),
r->url);
CPPUNIT_ASSERT_EQUAL(2, r->priority);
CPPUNIT_ASSERT_EQUAL(std::string("bittorrent"),
MetalinkResource::getTypeString(r->type));
CPPUNIT_ASSERT_EQUAL(-1, r->maxConnections);
}
void MetalinkProcessorTest::testParseFileV4_dirtraversal()
{
MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4-dirtraversal.xml");
CPPUNIT_ASSERT_EQUAL((size_t)0, m->entries.size());
}
void MetalinkProcessorTest::testParseFileV4_attrs()
{
MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4-attrs.xml");
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
CPPUNIT_ASSERT_EQUAL((size_t)6, m->entries[0]->resources.size());
std::deque<SharedHandle<MetalinkResource> > resources =
m->entries[0]->resources;
CPPUNIT_ASSERT_EQUAL(999999, resources[0]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[1]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[2]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[3]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[4]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[5]->priority);
}
void MetalinkProcessorTest::testParseFile()
{
MetalinkProcessor proc;
@ -77,8 +162,8 @@ void MetalinkProcessorTest::testParseFile()
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2"), entry1->getPath());
CPPUNIT_ASSERT_EQUAL((uint64_t)0ULL, entry1->getLength());
CPPUNIT_ASSERT_EQUAL(std::string("0.5.2"), entry1->version);
CPPUNIT_ASSERT_EQUAL(std::string("en-US"), entry1->language);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), entry1->os);
CPPUNIT_ASSERT_EQUAL(std::string("en-US"), entry1->languages[0]);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), entry1->oses[0]);
CPPUNIT_ASSERT_EQUAL(1, entry1->maxConnections);
#ifdef ENABLE_MESSAGE_DIGEST
CPPUNIT_ASSERT_EQUAL(std::string("a96cf3f0266b91d87d5124cf94326422800b627d"),
@ -104,8 +189,8 @@ void MetalinkProcessorTest::testParseFile()
std::deque<SharedHandle<MetalinkResource> >::iterator resourceItr1 = entry1->resources.begin();
SharedHandle<MetalinkResource> resource1 = *resourceItr1;
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, resource1->type);
CPPUNIT_ASSERT_EQUAL(std::string("JP"), resource1->location);
CPPUNIT_ASSERT_EQUAL(100, resource1->preference);
CPPUNIT_ASSERT_EQUAL(std::string("jp"), resource1->location);
CPPUNIT_ASSERT_EQUAL(1, resource1->priority);
CPPUNIT_ASSERT_EQUAL(std::string("ftp://ftphost/aria2-0.5.2.tar.bz2"),
resource1->url);
CPPUNIT_ASSERT_EQUAL(1, resource1->maxConnections);
@ -113,8 +198,8 @@ void MetalinkProcessorTest::testParseFile()
resourceItr1++;
SharedHandle<MetalinkResource> resource2 = *resourceItr1;
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_HTTP, resource2->type);
CPPUNIT_ASSERT_EQUAL(std::string("US"), resource2->location);
CPPUNIT_ASSERT_EQUAL(100, resource2->preference);
CPPUNIT_ASSERT_EQUAL(std::string("us"), resource2->location);
CPPUNIT_ASSERT_EQUAL(1, resource2->priority);
CPPUNIT_ASSERT_EQUAL(std::string("http://httphost/aria2-0.5.2.tar.bz2"),
resource2->url);
CPPUNIT_ASSERT_EQUAL(-1, resource2->maxConnections);
@ -125,8 +210,8 @@ void MetalinkProcessorTest::testParseFile()
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.1.tar.bz2"), entry2->getPath());
CPPUNIT_ASSERT_EQUAL((uint64_t)345689ULL, entry2->getLength());
CPPUNIT_ASSERT_EQUAL(std::string("0.5.1"), entry2->version);
CPPUNIT_ASSERT_EQUAL(std::string("ja-JP"), entry2->language);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-m68k"), entry2->os);
CPPUNIT_ASSERT_EQUAL(std::string("ja-JP"), entry2->languages[0]);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-m68k"), entry2->oses[0]);
CPPUNIT_ASSERT_EQUAL(-1, entry2->maxConnections);
#ifdef ENABLE_MESSAGE_DIGEST
CPPUNIT_ASSERT_EQUAL(std::string("4c255b0ed130f5ea880f0aa061c3da0487e251cc"),
@ -193,7 +278,7 @@ void MetalinkProcessorTest::testMalformedXML()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink><files></file></metalink>");
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></file></metalink>");
try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw);
@ -207,7 +292,7 @@ void MetalinkProcessorTest::testMalformedXML2()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink><files></files>");
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\"><files></files>");
try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw);
@ -221,7 +306,7 @@ void MetalinkProcessorTest::testBadSize()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>abc</size>"
@ -240,8 +325,8 @@ void MetalinkProcessorTest::testBadSize()
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.2.tar.bz2"), e->getPath());
CPPUNIT_ASSERT_EQUAL((uint64_t)0ULL, e->getLength());
CPPUNIT_ASSERT_EQUAL(std::string("0.5.2"), e->version);
CPPUNIT_ASSERT_EQUAL(std::string("en-US"), e->language);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), e->os);
CPPUNIT_ASSERT_EQUAL(std::string("en-US"), e->languages[0]);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), e->oses[0]);
} catch(Exception& e) {
CPPUNIT_FAIL(e.stackTrace());
@ -252,7 +337,7 @@ void MetalinkProcessorTest::testBadMaxConn()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>"
@ -279,7 +364,7 @@ void MetalinkProcessorTest::testNoName()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file>"
" <size>1024</size>"
@ -311,7 +396,7 @@ void MetalinkProcessorTest::testBadURLPrefs()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>"
@ -319,7 +404,8 @@ void MetalinkProcessorTest::testBadURLPrefs()
" <language>en-US</language>"
" <os>Linux-x86</os>"
" <resources>"
" <url type=\"ftp\" maxconnections=\"1\" preference=\"xyz\" location=\"JP\">ftp://mirror/</url>"
" <url type=\"ftp\" maxconnections=\"1\" preference=\"xyz\""
" location=\"jp\">ftp://mirror/</url>"
" </resources>"
"</file>"
"</files>"
@ -330,9 +416,9 @@ void MetalinkProcessorTest::testBadURLPrefs()
SharedHandle<MetalinkEntry> e = m->entries[0];
SharedHandle<MetalinkResource> r = e->resources[0];
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
CPPUNIT_ASSERT_EQUAL(0, r->preference);
CPPUNIT_ASSERT_EQUAL(MetalinkResource::getLowestPriority(), r->priority);
CPPUNIT_ASSERT_EQUAL(1, r->maxConnections);
CPPUNIT_ASSERT_EQUAL(std::string("JP"), r->location);
CPPUNIT_ASSERT_EQUAL(std::string("jp"), r->location);
} catch(Exception& e) {
CPPUNIT_FAIL(e.stackTrace());
}
@ -342,7 +428,7 @@ void MetalinkProcessorTest::testBadURLMaxConn()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>"
@ -350,7 +436,9 @@ void MetalinkProcessorTest::testBadURLMaxConn()
" <language>en-US</language>"
" <os>Linux-x86</os>"
" <resources>"
" <url maxconnections=\"xyz\" type=\"ftp\" preference=\"100\" location=\"JP\">ftp://mirror/</url>"
" <url maxconnections=\"xyz\" type=\"ftp\""
" preference=\"100\""
" location=\"jp\">ftp://mirror/</url>"
" </resources>"
"</file>"
"</files>"
@ -361,9 +449,9 @@ void MetalinkProcessorTest::testBadURLMaxConn()
SharedHandle<MetalinkEntry> e = m->entries[0];
SharedHandle<MetalinkResource> r = e->resources[0];
CPPUNIT_ASSERT_EQUAL(MetalinkResource::TYPE_FTP, r->type);
CPPUNIT_ASSERT_EQUAL(100, r->preference);
CPPUNIT_ASSERT_EQUAL(1, r->priority);
CPPUNIT_ASSERT_EQUAL(-1, r->maxConnections);
CPPUNIT_ASSERT_EQUAL(std::string("JP"), r->location);
CPPUNIT_ASSERT_EQUAL(std::string("jp"), r->location);
} catch(Exception& e) {
CPPUNIT_FAIL(e.stackTrace());
}
@ -374,7 +462,7 @@ void MetalinkProcessorTest::testUnsupportedType()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2-0.5.2.tar.bz2\">"
" <size>43743838</size>"
@ -409,7 +497,7 @@ void MetalinkProcessorTest::testMultiplePieces()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2.tar.bz2\">"
" <verification>"
@ -439,7 +527,7 @@ void MetalinkProcessorTest::testBadPieceNo()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2.tar.bz2\">"
" <verification>"
@ -472,7 +560,7 @@ void MetalinkProcessorTest::testBadPieceLength()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2.tar.bz2\">"
" <verification>"
@ -504,7 +592,7 @@ void MetalinkProcessorTest::testUnsupportedType_piece()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"aria2.tar.bz2\">"
" <verification>"
@ -537,7 +625,7 @@ void MetalinkProcessorTest::testLargeFileSize()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<metalink>"
dw->setString("<metalink version=\"3.0\" xmlns=\"http://www.metalinker.org/\">"
"<files>"
"<file name=\"dvd.iso\">"
" <size>9223372036854775807</size>"
@ -557,4 +645,29 @@ void MetalinkProcessorTest::testLargeFileSize()
}
}
void MetalinkProcessorTest::testXmlPrefixV3()
{
MetalinkProcessor proc;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
dw->setString("<m:metalink version=\"3.0\" xmlns:m=\"http://www.metalinker.org/\">"
"<m:files>"
"<m:file name=\"dvd.iso\">"
" <m:size>9223372036854775807</m:size>"
" <m:resources>"
" <m:url type=\"http\">ftp://mirror/</m:url>"
" </m:resources>"
"</m:file>"
"</m:files>"
"</m:metalink>");
try {
SharedHandle<Metalinker> m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
SharedHandle<MetalinkEntry> e = m->entries[0];
CPPUNIT_ASSERT_EQUAL((uint64_t)9223372036854775807ULL, e->getLength());
} catch(Exception& e) {
CPPUNIT_FAIL(e.stackTrace());
}
}
} // namespace aria2

View File

@ -27,12 +27,12 @@ void MetalinkerTest::testQueryEntry() {
SharedHandle<Metalinker> metalinker(new Metalinker());
SharedHandle<MetalinkEntry> entry1(new MetalinkEntry());
entry1->version = "0.5.2";
entry1->language = "en-US";
entry1->os = "Linux-x86";
entry1->languages.push_back("en-US");
entry1->oses.push_back("Linux-x86");
SharedHandle<MetalinkEntry> entry2(new MetalinkEntry());
entry2->version = "0.5.1";
entry2->language = "ja-JP";
entry2->os = "Linux-m68k";
entry2->languages.push_back("ja-JP");
entry2->oses.push_back("Linux-m68k");
metalinker->entries.push_back(entry1);
metalinker->entries.push_back(entry2);
@ -48,8 +48,8 @@ void MetalinkerTest::testQueryEntry() {
metalinker->queryEntry(result, version, language, os);
CPPUNIT_ASSERT_EQUAL((size_t)1, result.size());
CPPUNIT_ASSERT_EQUAL(std::string("0.5.1"), result.at(0)->version);
CPPUNIT_ASSERT_EQUAL(std::string("ja-JP"), result.at(0)->language);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-m68k"), result.at(0)->os);
CPPUNIT_ASSERT_EQUAL(std::string("ja-JP"), result.at(0)->languages[0]);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-m68k"), result.at(0)->oses[0]);
}
version = "0.6.0";
language = "";
@ -68,8 +68,8 @@ void MetalinkerTest::testQueryEntry() {
metalinker->queryEntry(result, version, language, os);
CPPUNIT_ASSERT_EQUAL((size_t)1, result.size());
CPPUNIT_ASSERT_EQUAL(std::string("0.5.2"), result.at(0)->version);
CPPUNIT_ASSERT_EQUAL(std::string("en-US"), result.at(0)->language);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), result.at(0)->os);
CPPUNIT_ASSERT_EQUAL(std::string("en-US"), result.at(0)->languages[0]);
CPPUNIT_ASSERT_EQUAL(std::string("Linux-x86"), result.at(0)->oses[0]);
}
}

View File

@ -61,6 +61,7 @@ class UtilTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testApplyDir);
CPPUNIT_TEST(testFixTaintedBasename);
CPPUNIT_TEST(testIsNumericHost);
CPPUNIT_TEST(testDetectDirTraversal);
CPPUNIT_TEST_SUITE_END();
private:
@ -110,6 +111,7 @@ public:
void testApplyDir();
void testFixTaintedBasename();
void testIsNumericHost();
void testDetectDirTraversal();
};
@ -1015,4 +1017,21 @@ void UtilTest::testIsNumericHost()
CPPUNIT_ASSERT(util::isNumericHost("::1"));
}
void UtilTest::testDetectDirTraversal()
{
CPPUNIT_ASSERT(util::detectDirTraversal("/foo"));
CPPUNIT_ASSERT(util::detectDirTraversal("./foo"));
CPPUNIT_ASSERT(util::detectDirTraversal("../foo"));
CPPUNIT_ASSERT(util::detectDirTraversal("foo/../bar"));
CPPUNIT_ASSERT(util::detectDirTraversal("foo/./bar"));
CPPUNIT_ASSERT(util::detectDirTraversal("foo/."));
CPPUNIT_ASSERT(util::detectDirTraversal("foo/.."));
CPPUNIT_ASSERT(util::detectDirTraversal("."));
CPPUNIT_ASSERT(util::detectDirTraversal(".."));
CPPUNIT_ASSERT(util::detectDirTraversal("/"));
CPPUNIT_ASSERT(util::detectDirTraversal("foo/"));
CPPUNIT_ASSERT(!util::detectDirTraversal("foo/bar"));
CPPUNIT_ASSERT(!util::detectDirTraversal("foo"));
}
} // namespace aria2

11
test/metalink4-attrs.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<file name="priority/example.ext">
<url location="de" priority="0">ftp://ftp.example.com/example.ext</url>
<url location="fr" priority="">http://example.com/example.ext</url>
<url location="jp" priority="1000000">http://example.org/example.ext</url>
<metaurl mediatype="torrent" priority="0">http://example.com/example.ext.torrent</metaurl>
<metaurl mediatype="torrent" priority="">http://example.org/example.ext.torrent</metaurl>
<metaurl mediatype="torrent" priority="1000000">http://example.net/example.ext.torrent</metaurl>
</file>
</metalink>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<file name="/example1.ext">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
<file name="./example2.ext">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
<file name="../example3.ext">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
<file name="dir/../example4.ext">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
<file name="example5.ext/..">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
<file name=".">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
<file name="..">
<url location="fr" priority="1">http://example.com/example.ext</url>
</file>
</metalink>

21
test/metalink4.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<published>2009-05-15T12:23:23Z</published>
<file name="example.ext">
<size>786430</size>
<identity>Example</identity>
<version>1.0</version>
<language>en</language>
<description>A description of the example file for download.</description>
<hash type="sha-1">80bc95fd391772fa61c91ed68567f0980bb45fd9</hash>
<pieces length="262144" type="sha-1">
<hash>metalinkhash1</hash>
<hash>metalinkhash2</hash>
<hash>metalinkhash3</hash>
</pieces>
<url location="de" priority="1">ftp://ftp.example.com/example.ext</url>
<url location="fr" priority="1">http://example.com/example.ext</url>
<metaurl mediatype="torrent" priority="2">http://example.com/example.ext.torrent</metaurl>
<signature mediatype="application/pgp-signature">a signature</signature>
</file>
</metalink>