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

Added strict attribute validation for metalink4. When
	specification violation is found, discard the whole document.
	* src/ExpatMetalinkProcessor.cc
	* src/MetalinkParserStateMachine.cc
	* src/MetalinkParserStateMachine.h
	* src/MetalinkParserStateV4Impl.cc
	* src/XML2SAXMetalinkProcessor.cc
	* test/Makefile.am
	* test/MetalinkProcessorTest.cc
	* test/metalink4-attrs.xml: Removed
	* test/metalink4-dirtraversal.xml: Removed
pull/1/head
Tatsuhiro Tsujikawa 2010-03-02 14:07:30 +00:00
parent eb32f56479
commit ba78b6f167
11 changed files with 461 additions and 151 deletions

View File

@ -1,3 +1,17 @@
2010-03-02 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added strict attribute validation for metalink4. When
specification violation is found, discard the whole document.
* src/ExpatMetalinkProcessor.cc
* src/MetalinkParserStateMachine.cc
* src/MetalinkParserStateMachine.h
* src/MetalinkParserStateV4Impl.cc
* src/XML2SAXMetalinkProcessor.cc
* test/Makefile.am
* test/MetalinkProcessorTest.cc
* test/metalink4-attrs.xml: Removed
* test/metalink4-dirtraversal.xml: Removed
2010-03-02 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2010-03-02 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added test for Metaurl transaction. Added test for Metaurl transaction.

View File

@ -147,7 +147,7 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
SharedHandle<SessionData> sessionData(new SessionData(_stm)); SharedHandle<SessionData> sessionData(new SessionData(_stm));
XML_Parser parser = XML_ParserCreateNS(0, static_cast<const XML_Char>('\t')); XML_Parser parser = XML_ParserCreateNS(0, static_cast<const XML_Char>('\t'));
try { auto_delete<XML_Parser> deleter(parser, XML_ParserFree);
XML_SetUserData(parser, sessionData.get()); XML_SetUserData(parser, sessionData.get());
XML_SetElementHandler(parser, &mlStartElement, &mlEndElement); XML_SetElementHandler(parser, &mlStartElement, &mlEndElement);
XML_SetCharacterDataHandler(parser, &mlCharacters); XML_SetCharacterDataHandler(parser, &mlCharacters);
@ -167,14 +167,12 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) { if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
} }
} catch(Exception& e) {
XML_ParserFree(parser);
throw;
}
XML_ParserFree(parser);
if(!_stm->finished()) { if(!_stm->finished()) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
} }
if(!_stm->getErrors().empty()) {
throw DL_ABORT_EX(_stm->getErrorString());
}
return _stm->getResult(); return _stm->getResult();
} }

View File

@ -33,6 +33,10 @@
*/ */
/* copyright --> */ /* copyright --> */
#include "MetalinkParserStateMachine.h" #include "MetalinkParserStateMachine.h"
#include <sstream>
#include <iterator>
#include "MetalinkParserStateImpl.h" #include "MetalinkParserStateImpl.h"
#include "MetalinkParserStateV3Impl.h" #include "MetalinkParserStateV3Impl.h"
#include "MetalinkParserStateV4Impl.h" #include "MetalinkParserStateV4Impl.h"
@ -514,4 +518,21 @@ bool MetalinkParserStateMachine::needsCharactersBuffering() const
return _stateStack.top()->needsCharactersBuffering(); return _stateStack.top()->needsCharactersBuffering();
} }
void MetalinkParserStateMachine::logError(const std::string& log)
{
if(_errors.size() < 10) {
_errors.push_back(log);
}
}
std::string MetalinkParserStateMachine::getErrorString() const
{
std::stringstream error;
error << "Specification violation: ";
std::copy(_errors.begin(), _errors.end(),
std::ostream_iterator<std::string>(error, ", "));
return error.str();
}
} // namespace aria2 } // namespace aria2

View File

@ -54,6 +54,9 @@ private:
std::stack<MetalinkParserState*> _stateStack; std::stack<MetalinkParserState*> _stateStack;
// Error messages encountered while parsing document.
std::vector<std::string> _errors;
static MetalinkParserState* _initialState; static MetalinkParserState* _initialState;
static MetalinkParserState* _skipTagState; static MetalinkParserState* _skipTagState;
@ -245,6 +248,16 @@ public:
bool needsCharactersBuffering() const; bool needsCharactersBuffering() const;
// Only stores first 10 errors.
void logError(const std::string& log);
const std::vector<std::string>& getErrors() const
{
return _errors;
}
std::string getErrorString() const;
const SharedHandle<Metalinker>& getResult() const const SharedHandle<Metalinker>& getResult() const
{ {
return _ctrl->getResult(); return _ctrl->getResult();

View File

@ -95,16 +95,17 @@ void MetalinkMetalinkParserStateV4::beginElement
const std::vector<XmlAttr>& attrs) const std::vector<XmlAttr>& attrs)
{ {
if(nsUri == METALINK4_NAMESPACE_URI && localname == FILE) { if(nsUri == METALINK4_NAMESPACE_URI && localname == FILE) {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME);
if(itr != attrs.end()) {
if((*itr).value.empty() || util::detectDirTraversal((*itr).value)) {
stm->setSkipTagState();
} else {
stm->setFileStateV4(); stm->setFileStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME);
if(itr == attrs.end() || (*itr).value.empty()) {
stm->logError("Missing file@name");
return;
} else if(util::detectDirTraversal((*itr).value)) {
stm->logError("Bad file@name");
return;
}
stm->newEntryTransaction(); stm->newEntryTransaction();
stm->setFileNameOfEntry((*itr).value); stm->setFileNameOfEntry((*itr).value);
}
}
} else { } else {
stm->setSkipTagState(); stm->setSkipTagState();
} }
@ -133,9 +134,11 @@ void FileMetalinkParserStateV4::beginElement
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME); std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, NAME);
if(itr != attrs.end()) { if(itr != attrs.end()) {
name = (*itr).value; if((*itr).value.empty() || util::detectDirTraversal((*itr).value)) {
if(util::detectDirTraversal(name)) { stm->logError("Bad metaurl@name");
return; return;
} else {
name = (*itr).value;
} }
} }
} }
@ -148,17 +151,20 @@ void FileMetalinkParserStateV4::beginElement
try { try {
priority = util::parseInt((*itr).value); priority = util::parseInt((*itr).value);
if(priority < 1 || MetalinkResource::getLowestPriority() < priority) { if(priority < 1 || MetalinkResource::getLowestPriority() < priority) {
priority = MetalinkResource::getLowestPriority(); stm->logError("metaurl@priority is out of range");
return;
} }
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
priority = MetalinkResource::getLowestPriority(); stm->logError("Bad metaurl@priority");
return;
} }
} }
} }
std::string mediatype; std::string mediatype;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE); std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE);
if(itr == attrs.end()) { if(itr == attrs.end() || (*itr).value.empty()) {
stm->logError("Missing metaurl@mediatype");
return; return;
} else { } else {
mediatype = (*itr).value; mediatype = (*itr).value;
@ -186,10 +192,12 @@ void FileMetalinkParserStateV4::beginElement
try { try {
priority = util::parseInt((*itr).value); priority = util::parseInt((*itr).value);
if(priority < 1 || MetalinkResource::getLowestPriority() < priority) { if(priority < 1 || MetalinkResource::getLowestPriority() < priority) {
priority = MetalinkResource::getLowestPriority(); stm->logError("url@priority is out of range");
return;
} }
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
priority = MetalinkResource::getLowestPriority(); stm->logError("Bad url@priority");
return;
} }
} }
} }
@ -201,7 +209,8 @@ void FileMetalinkParserStateV4::beginElement
else if(localname == HASH) { else if(localname == HASH) {
stm->setHashStateV4(); stm->setHashStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) { if(itr == attrs.end() || (*itr).value.empty()) {
stm->logError("Missing hash@type");
return; return;
} else { } else {
std::string type = (*itr).value; std::string type = (*itr).value;
@ -210,20 +219,26 @@ void FileMetalinkParserStateV4::beginElement
} }
} else if(localname == PIECES) { } else if(localname == PIECES) {
stm->setPiecesStateV4(); stm->setPiecesStateV4();
try {
size_t length; size_t length;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LENGTH); std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, LENGTH);
if(itr == attrs.end()) { if(itr == attrs.end() || (*itr).value.empty()) {
stm->logError("Missing pieces@length");
return; return;
} else { } else {
try {
length = util::parseInt((*itr).value); length = util::parseInt((*itr).value);
} catch(RecoverableException& e) {
stm->logError("Bad pieces@length");
return;
}
} }
} }
std::string type; std::string type;
{ {
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE); std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, TYPE);
if(itr == attrs.end()) { if(itr == attrs.end() || (*itr).value.empty()) {
stm->logError("Missing pieces@type");
return; return;
} else { } else {
type = (*itr).value; type = (*itr).value;
@ -232,20 +247,17 @@ void FileMetalinkParserStateV4::beginElement
stm->newChunkChecksumTransactionV4(); stm->newChunkChecksumTransactionV4();
stm->setLengthOfChunkChecksumV4(length); stm->setLengthOfChunkChecksumV4(length);
stm->setTypeOfChunkChecksumV4(type); stm->setTypeOfChunkChecksumV4(type);
} catch(RecoverableException& e) {
stm->cancelChunkChecksumTransactionV4();
}
} }
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
else if(localname == SIGNATURE) { else if(localname == SIGNATURE) {
stm->setSignatureStateV4(); stm->setSignatureStateV4();
std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE); std::vector<XmlAttr>::const_iterator itr = findAttr(attrs, MEDIATYPE);
if(itr == attrs.end()) { if(itr == attrs.end() || (*itr).value.empty()) {
stm->logError("Missing signature@mediatype");
return; return;
} else { }
stm->newSignatureTransaction(); stm->newSignatureTransaction();
stm->setTypeOfSignature((*itr).value); stm->setTypeOfSignature((*itr).value);
}
} else { } else {
stm->setSkipTagState(); stm->setSkipTagState();
} }

View File

@ -179,6 +179,12 @@ MetalinkProcessor::parseFile(const std::string& filename)
if(retval != 0) { if(retval != 0) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
} }
if(!_stm->finished()) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
}
if(!_stm->getErrors().empty()) {
throw DL_ABORT_EX(_stm->getErrorString());
}
return _stm->getResult(); return _stm->getResult();
} }
@ -198,7 +204,8 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt
(&mySAXHandler, sessionData.get(), (&mySAXHandler, sessionData.get(),
reinterpret_cast<const char*>(buf), res, 0); reinterpret_cast<const char*>(buf), res, 0);
try { auto_delete<xmlParserCtxtPtr> deleter(ctx, xmlFreeParserCtxt);
off_t readOffset = res; off_t readOffset = res;
while(1) { while(1) {
ssize_t res = binaryStream->readData(buf, bufSize, readOffset); ssize_t res = binaryStream->readData(buf, bufSize, readOffset);
@ -211,15 +218,13 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
readOffset += res; readOffset += res;
} }
xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), 0, 1); xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), 0, 1);
} catch(Exception& e) {
xmlFreeParserCtxt(ctx);
throw;
}
xmlFreeParserCtxt(ctx);
if(!_stm->finished()) { if(!_stm->finished()) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
} }
if(!_stm->getErrors().empty()) {
throw DL_ABORT_EX(_stm->getErrorString());
}
return _stm->getResult(); return _stm->getResult();
} }

View File

@ -249,7 +249,5 @@ EXTRA_DIST = 4096chunk.txt\
2files.metalink\ 2files.metalink\
utf8.torrent\ utf8.torrent\
metalink4.xml\ metalink4.xml\
metalink4-attrs.xml\
metalink4-dirtraversal.xml\
metalink3-dirtraversal.xml\ metalink3-dirtraversal.xml\
metalink4-groupbymetaurl.xml metalink4-groupbymetaurl.xml

View File

@ -687,8 +687,6 @@ EXTRA_DIST = 4096chunk.txt\
2files.metalink\ 2files.metalink\
utf8.torrent\ utf8.torrent\
metalink4.xml\ metalink4.xml\
metalink4-attrs.xml\
metalink4-dirtraversal.xml\
metalink3-dirtraversal.xml\ metalink3-dirtraversal.xml\
metalink4-groupbymetaurl.xml metalink4-groupbymetaurl.xml

View File

@ -17,6 +17,8 @@
# include "Checksum.h" # include "Checksum.h"
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
#include "Signature.h" #include "Signature.h"
#include "StringFormat.h"
#include "RecoverableException.h"
namespace aria2 { namespace aria2 {
@ -24,7 +26,6 @@ class MetalinkProcessorTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MetalinkProcessorTest); CPPUNIT_TEST_SUITE(MetalinkProcessorTest);
CPPUNIT_TEST(testParseFileV4); CPPUNIT_TEST(testParseFileV4);
CPPUNIT_TEST(testParseFileV4_dirtraversal);
CPPUNIT_TEST(testParseFileV4_attrs); CPPUNIT_TEST(testParseFileV4_attrs);
CPPUNIT_TEST(testParseFile); CPPUNIT_TEST(testParseFile);
CPPUNIT_TEST(testParseFile_dirtraversal); CPPUNIT_TEST(testParseFile_dirtraversal);
@ -50,7 +51,6 @@ private:
public: public:
void testParseFileV4(); void testParseFileV4();
void testParseFileV4_dirtraversal();
void testParseFileV4_attrs(); void testParseFileV4_attrs();
void testParseFile(); void testParseFile();
void testParseFile_dirtraversal(); void testParseFile_dirtraversal();
@ -80,7 +80,6 @@ void MetalinkProcessorTest::testParseFileV4()
{ {
MetalinkProcessor proc; MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4.xml"); SharedHandle<Metalinker> m = proc.parseFile("metalink4.xml");
SharedHandle<MetalinkEntry> e; SharedHandle<MetalinkEntry> e;
SharedHandle<MetalinkResource> r; SharedHandle<MetalinkResource> r;
SharedHandle<MetalinkMetaurl> mu; SharedHandle<MetalinkMetaurl> mu;
@ -133,37 +132,327 @@ void MetalinkProcessorTest::testParseFileV4()
#endif // !ENABLE_BITTORRENT #endif // !ENABLE_BITTORRENT
} }
void MetalinkProcessorTest::testParseFileV4_dirtraversal()
{
MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4-dirtraversal.xml");
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
CPPUNIT_ASSERT_EQUAL((size_t)0, m->entries[0]->resources.size());
CPPUNIT_ASSERT_EQUAL((size_t)0, m->entries[0]->metaurls.size());
}
void MetalinkProcessorTest::testParseFileV4_attrs() void MetalinkProcessorTest::testParseFileV4_attrs()
{ {
MetalinkProcessor proc; MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4-attrs.xml"); SharedHandle<Metalinker> m;
SharedHandle<ByteArrayDiskWriter> dw(new ByteArrayDiskWriter());
{
// Testing file@name
const char* tmpl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"%s\">"
"<url>http://example.org</url>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "foo").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
std::vector<SharedHandle<MetalinkResource> > resources =
m->entries[0]->resources;
CPPUNIT_ASSERT_EQUAL((size_t)3, resources.size());
CPPUNIT_ASSERT_EQUAL(999999, resources[0]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[1]->priority);
CPPUNIT_ASSERT_EQUAL(999999, resources[2]->priority);
std::vector<SharedHandle<MetalinkMetaurl> > metaurls = // empty name
m->entries[0]->metaurls; dw->setString(StringFormat(tmpl, "").str());
#ifdef ENABLE_BITTORRENT try {
CPPUNIT_ASSERT_EQUAL((size_t)3, metaurls.size()); m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL(999999, metaurls[0]->priority); CPPUNIT_FAIL("exception must be thrown.");
CPPUNIT_ASSERT_EQUAL(999999, metaurls[1]->priority); } catch(RecoverableException& e) {
CPPUNIT_ASSERT_EQUAL(999999, metaurls[2]->priority); // success
#else // !ENABLE_BITTORRENT }
CPPUNIT_ASSERT_EQUAL((size_t)0, metaurls.size());
#endif // !ENABLE_BITTORRENT // dir traversing
dw->setString(StringFormat(tmpl, "../doughnuts").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
}
{
// Testing url@priority
const char* tmpl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url priority=\"%s\">http://example.org</url>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "0").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
dw->setString(StringFormat(tmpl, "1").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
dw->setString(StringFormat(tmpl, "100").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
dw->setString(StringFormat(tmpl, "999999").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
dw->setString(StringFormat(tmpl, "1000000").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
}
{
// Testing metaurl@priority
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<metaurl priority=\"%s\" mediatype=\"torrent\">http://example.org</metaurl>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "0").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
dw->setString(StringFormat(tmpl, "1").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
dw->setString(StringFormat(tmpl, "100").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
dw->setString(StringFormat(tmpl, "999999").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
dw->setString(StringFormat(tmpl, "1000000").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
}
{
// Testing metaurl@mediatype
// no mediatype
dw->setString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<metaurl>http://example.org</metaurl>"
"</file>"
"</metalink>");
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<metaurl mediatype=\"%s\">http://example.org</metaurl>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "torrent").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
// empty mediatype
dw->setString(StringFormat(tmpl, "").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
}
{
// Testing metaurl@name
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<metaurl mediatype=\"torrent\" name=\"%s\">http://example.org</metaurl>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "foo").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->entries.size());
// dir traversing
dw->setString(StringFormat(tmpl, "../doughnuts").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
// empty name
dw->setString(StringFormat(tmpl, "").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
}
{
// Testing pieces@length
// No pieces@length
dw->setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<pieces type=\"sha-1\">"
"<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
"</pieces>"
"</file>"
"</metalink>");
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<pieces length=\"%s\" type=\"sha-1\">"
"<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
"</pieces>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "262144").str());
m = proc.parseFromBinaryStream(dw);
// empty
try {
dw->setString(StringFormat(tmpl, "").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
}
{
// Testing pieces@type
// No pieces@type
dw->setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<pieces length=\"262144\">"
"<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
"</pieces>"
"</file>"
"</metalink>");
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<pieces length=\"262144\" type=\"%s\">"
"<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
"</pieces>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "sha-1").str());
m = proc.parseFromBinaryStream(dw);
// empty
try {
dw->setString(StringFormat(tmpl, "").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
}
{
// Testing hash@type
// No hash@type
dw->setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<hash>0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
"</file>"
"</metalink>");
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<hash type=\"%s\">0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33</hash>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "sha-1").str());
m = proc.parseFromBinaryStream(dw);
// empty
try {
dw->setString(StringFormat(tmpl, "").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
}
{
// Testing signature@mediatype
// No hash@type
dw->setString
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<signature>sig</signature>"
"</file>"
"</metalink>");
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
const char* tmpl =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\">"
"<file name=\"example.ext\">"
"<url>http://example.org</url>"
"<signature mediatype=\"%s\">sig</signature>"
"</file>"
"</metalink>";
dw->setString(StringFormat(tmpl, "application/pgp-signature").str());
m = proc.parseFromBinaryStream(dw);
// empty
try {
dw->setString(StringFormat(tmpl, "").str());
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {}
}
} }
void MetalinkProcessorTest::testParseFile() void MetalinkProcessorTest::testParseFile()

View File

@ -1,11 +0,0 @@
<?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

@ -1,27 +0,0 @@
<?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>
<file name="foo">
<metaurl name="../foo" mediatype="torrent">http://example.com/example.torrent</metaurl>
</file>
</metalink>