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>
Added test for Metaurl transaction.

View File

@ -147,34 +147,32 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
SharedHandle<SessionData> sessionData(new SessionData(_stm));
XML_Parser parser = XML_ParserCreateNS(0, static_cast<const XML_Char>('\t'));
try {
XML_SetUserData(parser, sessionData.get());
XML_SetElementHandler(parser, &mlStartElement, &mlEndElement);
XML_SetCharacterDataHandler(parser, &mlCharacters);
auto_delete<XML_Parser> deleter(parser, XML_ParserFree);
XML_SetUserData(parser, sessionData.get());
XML_SetElementHandler(parser, &mlStartElement, &mlEndElement);
XML_SetCharacterDataHandler(parser, &mlCharacters);
off_t readOffset = 0;
while(1) {
ssize_t res = binaryStream->readData(buf, bufSize, readOffset);
if(res == 0) {
break;
}
if(XML_Parse(parser, reinterpret_cast<const char*>(buf), res, 0) ==
XML_STATUS_ERROR) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
}
readOffset += res;
off_t readOffset = 0;
while(1) {
ssize_t res = binaryStream->readData(buf, bufSize, readOffset);
if(res == 0) {
break;
}
if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) {
if(XML_Parse(parser, reinterpret_cast<const char*>(buf), res, 0) ==
XML_STATUS_ERROR) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
}
} catch(Exception& e) {
XML_ParserFree(parser);
throw;
readOffset += res;
}
if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
}
XML_ParserFree(parser);
if(!_stm->finished()) {
throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
}
if(!_stm->getErrors().empty()) {
throw DL_ABORT_EX(_stm->getErrorString());
}
return _stm->getResult();
}

View File

@ -33,6 +33,10 @@
*/
/* copyright --> */
#include "MetalinkParserStateMachine.h"
#include <sstream>
#include <iterator>
#include "MetalinkParserStateImpl.h"
#include "MetalinkParserStateV3Impl.h"
#include "MetalinkParserStateV4Impl.h"
@ -514,4 +518,21 @@ bool MetalinkParserStateMachine::needsCharactersBuffering() const
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

View File

@ -54,6 +54,9 @@ private:
std::stack<MetalinkParserState*> _stateStack;
// Error messages encountered while parsing document.
std::vector<std::string> _errors;
static MetalinkParserState* _initialState;
static MetalinkParserState* _skipTagState;
@ -245,6 +248,16 @@ public:
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
{
return _ctrl->getResult();

View File

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

View File

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

View File

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

View File

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

View File

@ -17,6 +17,8 @@
# include "Checksum.h"
#endif // ENABLE_MESSAGE_DIGEST
#include "Signature.h"
#include "StringFormat.h"
#include "RecoverableException.h"
namespace aria2 {
@ -24,7 +26,6 @@ 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(testParseFile_dirtraversal);
@ -50,7 +51,6 @@ private:
public:
void testParseFileV4();
void testParseFileV4_dirtraversal();
void testParseFileV4_attrs();
void testParseFile();
void testParseFile_dirtraversal();
@ -80,7 +80,6 @@ void MetalinkProcessorTest::testParseFileV4()
{
MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4.xml");
SharedHandle<MetalinkEntry> e;
SharedHandle<MetalinkResource> r;
SharedHandle<MetalinkMetaurl> mu;
@ -133,37 +132,327 @@ void MetalinkProcessorTest::testParseFileV4()
#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()
{
MetalinkProcessor proc;
SharedHandle<Metalinker> m = proc.parseFile("metalink4-attrs.xml");
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);
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());
std::vector<SharedHandle<MetalinkMetaurl> > metaurls =
m->entries[0]->metaurls;
#ifdef ENABLE_BITTORRENT
CPPUNIT_ASSERT_EQUAL((size_t)3, metaurls.size());
CPPUNIT_ASSERT_EQUAL(999999, metaurls[0]->priority);
CPPUNIT_ASSERT_EQUAL(999999, metaurls[1]->priority);
CPPUNIT_ASSERT_EQUAL(999999, metaurls[2]->priority);
#else // !ENABLE_BITTORRENT
CPPUNIT_ASSERT_EQUAL((size_t)0, metaurls.size());
#endif // !ENABLE_BITTORRENT
// empty name
dw->setString(StringFormat(tmpl, "").str());
try {
m = proc.parseFromBinaryStream(dw);
CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) {
// success
}
// 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()

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>