Discovery: Test better, treat invalid hrefs as error #3176
authorMarkus Goetz <markus@woboq.com>
Thu, 7 May 2015 15:19:14 +0000 (17:19 +0200)
committerMarkus Goetz <markus@woboq.com>
Thu, 7 May 2015 15:19:48 +0000 (17:19 +0200)
src/libsync/networkjobs.cpp
src/libsync/networkjobs.h
test/testxmlparse.h

index 7e92d96c14ae969b4a9429922dc81a73698d0779..8a43e5cea80f3cf5144e7eef7f5924127f3a921c 100644 (file)
@@ -350,7 +350,7 @@ LsColXMLParser::LsColXMLParser()
 
 }
 
-bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes)
+bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes, const QString& expectedPath)
 {
     // Parse DAV response
     QXmlStreamReader reader(xml);
@@ -371,7 +371,14 @@ bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes
         // Start elements with DAV:
         if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
             if (name == QLatin1String("href")) {
-                currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
+                // We don't use URL encoding in our request URL (which is the expected path) (QNAM will do it for us)
+                // but the result will have URL encoding..
+                QString hrefString = QString::fromUtf8(QByteArray::fromPercentEncoding(reader.readElementText().toUtf8()));
+                if (!hrefString.startsWith(expectedPath)) {
+                    qDebug() << "Invalid href" << hrefString << "expected starting with" << expectedPath;
+                    return false;
+                }
+                currentHref = hrefString;
             } else if (name == QLatin1String("response")) {
             } else if (name == QLatin1String("propstat")) {
                 insidePropstat = true;
@@ -520,7 +527,8 @@ bool LsColJob::finished()
         connect( &parser, SIGNAL(finishedWithoutError()),
                  this, SIGNAL(finishedWithoutError()) );
 
-        if( !parser.parse( reply()->readAll(), &_sizes ) ) {
+        QString expectedPath = reply()->request().url().path(); // something like "/owncloud/remote.php/webdav/folder"
+        if( !parser.parse( reply()->readAll(), &_sizes, expectedPath ) ) {
             // XML parse error
             emit finishedWithError(reply());
         }
index f3bc5d1bfc2bb00e726543390e5aecb4abb17495..868207da7ee58c2f961b147c6685c8a0517175fa 100644 (file)
@@ -137,7 +137,7 @@ class OWNCLOUDSYNC_EXPORT LsColXMLParser : public QObject {
 public:
     explicit LsColXMLParser();
 
-    bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes);
+    bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes, const QString& expectedPath);
 
 signals:
     void directoryListingSubfolders(const QStringList &items);
index add06cdd8c883180b60f1136d73247dc659c17fe..0b667eb5077562568fc9042258a201de0e1a3158 100644 (file)
@@ -113,7 +113,7 @@ private slots:
                  this, SLOT(slotFinishedSuccessfully()) );
 
         QHash <QString, qint64> sizes;
-        QVERIFY(parser.parse( testXml, &sizes ));
+        QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
 
         QVERIFY(_success);
         QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -187,7 +187,7 @@ private slots:
                  this, SLOT(slotFinishedSuccessfully()) );
 
         QHash <QString, qint64> sizes;
-        QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
+        QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
 
         QVERIFY(!_success);
         QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -210,7 +210,7 @@ private slots:
                  this, SLOT(slotFinishedSuccessfully()) );
 
         QHash <QString, qint64> sizes;
-        QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
+        QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
 
         QVERIFY(!_success);
         QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -232,7 +232,7 @@ private slots:
                  this, SLOT(slotFinishedSuccessfully()) );
 
         QHash <QString, qint64> sizes;
-        QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
+        QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
 
         QVERIFY(!_success);
         QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -240,6 +240,208 @@ private slots:
         QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
         QVERIFY(_subdirs.size() == 0);
     }
+
+    void testParserBogfusHref1() {
+        const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
+              "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
+              "<d:response>"
+              "<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/</d:href>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:id>00004213ocobzus5kn6s</oc:id>"
+              "<oc:permissions>RDNVCK</oc:permissions>"
+              "<oc:size>121780</oc:size>"
+              "<d:getetag>\"5527beb0400b0\"</d:getetag>"
+              "<d:resourcetype>"
+              "<d:collection/>"
+              "</d:resourcetype>"
+              "<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 200 OK</d:status>"
+              "</d:propstat>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<d:getcontentlength/>"
+              "<oc:downloadURL/>"
+              "<oc:dDC/>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 404 Not Found</d:status>"
+              "</d:propstat>"
+              "</d:response>"
+              "<d:response>"
+              "<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:id>00004215ocobzus5kn6s</oc:id>"
+              "<oc:permissions>RDNVW</oc:permissions>"
+              "<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
+              "<d:resourcetype/>"
+              "<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
+              "<d:getcontentlength>121780</d:getcontentlength>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 200 OK</d:status>"
+              "</d:propstat>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:downloadURL/>"
+              "<oc:dDC/>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 404 Not Found</d:status>"
+              "</d:propstat>"
+              "</d:response>"
+              "</d:multistatus>";
+
+
+        LsColXMLParser parser;
+
+        connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
+                 this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
+        connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
+                 this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
+        connect( &parser, SIGNAL(finishedWithoutError()),
+                 this, SLOT(slotFinishedSuccessfully()) );
+
+        QHash <QString, qint64> sizes;
+        QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
+        QVERIFY(!_success);
+    }
+
+    void testParserBogfusHref2() {
+        const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
+              "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
+              "<d:response>"
+              "<d:href>/sharefolder</d:href>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:id>00004213ocobzus5kn6s</oc:id>"
+              "<oc:permissions>RDNVCK</oc:permissions>"
+              "<oc:size>121780</oc:size>"
+              "<d:getetag>\"5527beb0400b0\"</d:getetag>"
+              "<d:resourcetype>"
+              "<d:collection/>"
+              "</d:resourcetype>"
+              "<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 200 OK</d:status>"
+              "</d:propstat>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<d:getcontentlength/>"
+              "<oc:downloadURL/>"
+              "<oc:dDC/>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 404 Not Found</d:status>"
+              "</d:propstat>"
+              "</d:response>"
+              "<d:response>"
+              "<d:href>/sharefolder/quitte.pdf</d:href>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:id>00004215ocobzus5kn6s</oc:id>"
+              "<oc:permissions>RDNVW</oc:permissions>"
+              "<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
+              "<d:resourcetype/>"
+              "<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
+              "<d:getcontentlength>121780</d:getcontentlength>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 200 OK</d:status>"
+              "</d:propstat>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:downloadURL/>"
+              "<oc:dDC/>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 404 Not Found</d:status>"
+              "</d:propstat>"
+              "</d:response>"
+              "</d:multistatus>";
+
+
+        LsColXMLParser parser;
+
+        connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
+                 this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
+        connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
+                 this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
+        connect( &parser, SIGNAL(finishedWithoutError()),
+                 this, SLOT(slotFinishedSuccessfully()) );
+
+        QHash <QString, qint64> sizes;
+        QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
+        QVERIFY(!_success);
+    }
+
+    void testHrefUrlEncoding() {
+        const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
+              "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
+              "<d:response>"
+              "<d:href>/%C3%A4</d:href>" // a-umlaut utf8
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:id>00004213ocobzus5kn6s</oc:id>"
+              "<oc:permissions>RDNVCK</oc:permissions>"
+              "<oc:size>121780</oc:size>"
+              "<d:getetag>\"5527beb0400b0\"</d:getetag>"
+              "<d:resourcetype>"
+              "<d:collection/>"
+              "</d:resourcetype>"
+              "<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 200 OK</d:status>"
+              "</d:propstat>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<d:getcontentlength/>"
+              "<oc:downloadURL/>"
+              "<oc:dDC/>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 404 Not Found</d:status>"
+              "</d:propstat>"
+              "</d:response>"
+              "<d:response>"
+              "<d:href>/%C3%A4/%C3%A4.pdf</d:href>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:id>00004215ocobzus5kn6s</oc:id>"
+              "<oc:permissions>RDNVW</oc:permissions>"
+              "<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
+              "<d:resourcetype/>"
+              "<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
+              "<d:getcontentlength>121780</d:getcontentlength>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 200 OK</d:status>"
+              "</d:propstat>"
+              "<d:propstat>"
+              "<d:prop>"
+              "<oc:downloadURL/>"
+              "<oc:dDC/>"
+              "</d:prop>"
+              "<d:status>HTTP/1.1 404 Not Found</d:status>"
+              "</d:propstat>"
+              "</d:response>"
+              "</d:multistatus>";
+
+        LsColXMLParser parser;
+
+        connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
+                 this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
+        connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
+                 this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
+        connect( &parser, SIGNAL(finishedWithoutError()),
+                 this, SLOT(slotFinishedSuccessfully()) );
+
+        QHash <QString, qint64> sizes;
+        QVERIFY(parser.parse( testXml, &sizes, "/ä" ));
+        QVERIFY(_success);
+
+        QVERIFY(_items.contains("/ä/ä.pdf"));
+        QVERIFY(_items.contains("/ä"));
+        QVERIFY(_items.size() == 2 );
+
+        QVERIFY(_subdirs.contains("/ä"));
+        QVERIFY(_subdirs.size() == 1);
+    }
+
 };
 
 #endif