bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes, const QString& expectedPath) { // Parse DAV response QXmlStreamReader reader(xml); reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); QStringList folders; QString currentHref; QMap<QString, QString> currentTmpProperties; QMap<QString, QString> currentHttp200Properties; bool currentPropsHaveHttp200 = false; bool insidePropstat = false; bool insideProp = false; bool insideMultiStatus = 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")) { // 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; } 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; } else if (name == QLatin1String("multistatus")) { insideMultiStatus = 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<QString,QString>(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() << xml; return false; } else if (!insideMultiStatus) { qDebug() << "ERROR no WebDAV response?" << xml; return false; } else { emit directoryListingSubfolders(folders); emit finishedWithoutError(); } return true; }
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<QString, QString> currentTmpProperties; QMap<QString, QString> 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<QString,QString>(currentTmpProperties); } currentTmpProperties.clear(); currentPropsHaveHttp200 = false; } else if (reader.name() == "prop") { insideProp = false; } } } } emit directoryListingSubfolders(folders); emit finishedWithoutError(); } else if (httpCode == 207) { // wrong content type emit finishedWithError(reply()); } else { // wrong HTTP code emit finishedWithError(reply()); } return true; }