mirror of https://github.com/aria2/aria2
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: Removedpull/1/head
parent
eb32f56479
commit
ba78b6f167
14
ChangeLog
14
ChangeLog
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
Loading…
Reference in New Issue