From: Klaas Freitag Date: Tue, 14 Apr 2015 06:36:17 +0000 (+0200) Subject: LsColJob: Create a XML parser object for better unit testability. X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~1803^2~196 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4283ab3b44e8801a9707ff24baf2dd7b1d6e09b8;p=nextcloud-desktop.git LsColJob: Create a XML parser object for better unit testability. --- diff --git a/src/libsync/networkjobs.cpp b/src/libsync/networkjobs.cpp index e8a571a34..18837ea8b 100644 --- a/src/libsync/networkjobs.cpp +++ b/src/libsync/networkjobs.cpp @@ -320,6 +320,124 @@ bool MkColJob::finished() return true; } +/*********************************************************************************************/ +// supposed to read when pointing to .. +static QString readContentsAsString(QXmlStreamReader &reader) { + QString result; + int level = 0; + do { + QXmlStreamReader::TokenType type = reader.readNext(); + if (type == QXmlStreamReader::StartElement) { + level++; + result += "<" + reader.name().toString() + ">"; + } else if (type == QXmlStreamReader::Characters) { + result += reader.text(); + } else if (type == QXmlStreamReader::EndElement) { + level--; + if (level < 0) { + break; + } + result += ""; + } + + } while (!reader.atEnd()); + return result; +} + + +LsColXMLParser::LsColXMLParser() +{ + +} + +bool LsColXMLParser::parse( const QByteArray& xml, QHash *sizes) +{ + // Parse DAV response + QXmlStreamReader reader(xml); + reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); + + QStringList folders; + QString currentHref; + QMap currentTmpProperties; + QMap currentHttp200Properties; + bool currentPropsHaveHttp200 = false; + bool insidePropstat = false; + bool insideProp = false; + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType type = reader.readNext(); + QString name = reader.name().toString(); + // Start elements with DAV: + if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) { + if (name == QLatin1String("href")) { + currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8()); + } else if (name == QLatin1String("response")) { + } else if (name == QLatin1String("propstat")) { + insidePropstat = true; + } else if (name == QLatin1String("status") && insidePropstat) { + QString httpStatus = reader.readElementText(); + if (httpStatus.startsWith("HTTP/1.1 200")) { + currentPropsHaveHttp200 = true; + } else { + currentPropsHaveHttp200 = false; + } + } else if (name == QLatin1String("prop")) { + insideProp = true; + continue; + } + } + + if (type == QXmlStreamReader::StartElement && insidePropstat && insideProp) { + // All those elements are properties + QString propertyContent = readContentsAsString(reader); + if (name == QLatin1String("resourcetype") && propertyContent.contains("collection")) { + folders.append(currentHref); + } else if (name == QLatin1String("quota-used-bytes")) { + bool ok = false; + auto s = propertyContent.toLongLong(&ok); + if (ok && sizes) { + sizes->insert(currentHref, s); + } + } + currentTmpProperties.insert(reader.name().toString(), propertyContent); + } + + // End elements with DAV: + if (type == QXmlStreamReader::EndElement) { + if (reader.namespaceUri() == QLatin1String("DAV:")) { + if (reader.name() == "response") { + if (currentHref.endsWith('/')) { + currentHref.chop(1); + } + emit directoryListingIterated(currentHref, currentHttp200Properties); + currentHref.clear(); + currentHttp200Properties.clear(); + } else if (reader.name() == "propstat") { + insidePropstat = false; + if (currentPropsHaveHttp200) { + currentHttp200Properties = QMap(currentTmpProperties); + } + currentTmpProperties.clear(); + currentPropsHaveHttp200 = false; + } else if (reader.name() == "prop") { + insideProp = false; + } + } + } + } + + if (reader.hasError()) { + // XML Parser error? Whatever had been emitted before will come as directoryListingIterated + qDebug() << "ERROR" << reader.errorString(); + return false; + } else { + emit directoryListingSubfolders(folders); + emit finishedWithoutError(); + } + return true; + +} + /*********************************************************************************************/ LsColJob::LsColJob(AccountPtr account, const QString &path, QObject *parent) @@ -377,29 +495,6 @@ void LsColJob::start() AbstractNetworkJob::start(); } -// supposed to read when pointing to .. -static QString readContentsAsString(QXmlStreamReader &reader) { - QString result; - int level = 0; - do { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement) { - level++; - result += "<" + reader.name().toString() + ">"; - } else if (type == QXmlStreamReader::Characters) { - result += reader.text(); - } else if (type == QXmlStreamReader::EndElement) { - level--; - if (level < 0) { - break; - } - result += ""; - } - - } while (!reader.atEnd()); - return result; -} - // TODO: Instead of doing all in this slot, we should iteratively parse in readyRead(). This // would allow us to be more asynchronous in processing while data is coming from the network, // not in all in one big blobb at the end. @@ -408,88 +503,19 @@ bool LsColJob::finished() QString contentType = reply()->header(QNetworkRequest::ContentTypeHeader).toString(); int httpCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (httpCode == 207 && contentType.contains("application/xml; charset=utf-8")) { - // Parse DAV response - QByteArray xml = reply()->readAll(); - QXmlStreamReader reader(xml); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - - QStringList folders; - QString currentHref; - QMap currentTmpProperties; - QMap currentHttp200Properties; - bool currentPropsHaveHttp200 = false; - bool insidePropstat = false; - bool insideProp = false; - - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - QString name = reader.name().toString(); - // Start elements with DAV: - if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) { - if (name == QLatin1String("href")) { - currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8()); - } else if (name == QLatin1String("response")) { - } else if (name == QLatin1String("propstat")) { - insidePropstat = true; - } else if (name == QLatin1String("status") && insidePropstat) { - QString httpStatus = reader.readElementText(); - if (httpStatus.startsWith("HTTP/1.1 200")) { - currentPropsHaveHttp200 = true; - } else { - currentPropsHaveHttp200 = false; - } - } else if (name == QLatin1String("prop")) { - insideProp = true; - continue; - } - } - - if (type == QXmlStreamReader::StartElement && insidePropstat && insideProp) { - // All those elements are properties - QString propertyContent = readContentsAsString(reader); - if (name == QLatin1String("resourcetype") && propertyContent.contains("collection")) { - folders.append(currentHref); - } else if (name == QLatin1String("quota-used-bytes")) { - bool ok = false; - auto s = propertyContent.toLongLong(&ok); - if (ok) { - _sizes[currentHref] = s; - } - } - currentTmpProperties.insert(reader.name().toString(), propertyContent); - } - - // End elements with DAV: - if (type == QXmlStreamReader::EndElement) { - if (reader.namespaceUri() == QLatin1String("DAV:")) { - if (reader.name() == "response") { - if (currentHref.endsWith('/')) { - currentHref.chop(1); - } - emit directoryListingIterated(currentHref, currentHttp200Properties); - currentHref.clear(); - currentHttp200Properties.clear(); - } else if (reader.name() == "propstat") { - insidePropstat = false; - if (currentPropsHaveHttp200) { - currentHttp200Properties = QMap(currentTmpProperties); - } - currentTmpProperties.clear(); - currentPropsHaveHttp200 = false; - } else if (reader.name() == "prop") { - insideProp = false; - } - } - } - } - - if (reader.hasError()) { - // XML Parser error? Whatever had been emitted before will come as directoryListingIterated - qDebug() << "ERROR" << reader.errorString(); + LsColXMLParser parser; + connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)), + this, SIGNAL(directoryListingSubfolders(const QStringList&)) ); + connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap&)), + this, SIGNAL(directoryListingIterated(const QString&, const QMap&)) ); + connect( &parser, SIGNAL(finishedWithError(QNetworkReply *)), + this, SIGNAL(finishedWithError(QNetworkReply *)) ); + connect( &parser, SIGNAL(finishedWithoutError()), + this, SIGNAL(finishedWithoutError()) ); + + if( !parser.parse( reply()->readAll(), &_sizes ) ) { + // XML parse error emit finishedWithError(reply()); - } else { - emit directoryListingSubfolders(folders); - emit finishedWithoutError(); } } else if (httpCode == 207) { // wrong content type @@ -498,6 +524,7 @@ bool LsColJob::finished() // wrong HTTP code or any other network error emit finishedWithError(reply()); } + return true; }