// 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. 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")) { LsColXMLParser parser; connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)), this, SIGNAL(directoryListingSubfolders(const QStringList&)) ); connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)), this, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)) ); connect( &parser, SIGNAL(finishedWithError(QNetworkReply *)), this, SIGNAL(finishedWithError(QNetworkReply *)) ); connect( &parser, SIGNAL(finishedWithoutError()), this, SIGNAL(finishedWithoutError()) ); 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()); } } else if (httpCode == 207) {
void PropagateUploadFileNG::doStartUpload() { propagator()->_activeJobList.append(this); const SyncJournalDb::UploadInfo progressInfo = propagator()->_journal->getUploadInfo(_item->_file); if (progressInfo._valid && Utility::qDateTimeToTime_t(progressInfo._modtime) == _item->_modtime) { _transferId = progressInfo._transferid; auto url = chunkUrl(); auto job = new LsColJob(propagator()->account(), url, this); _jobs.append(job); job->setProperties(QList<QByteArray>() << "resourcetype" << "getcontentlength"); connect(job, SIGNAL(finishedWithoutError()), this, SLOT(slotPropfindFinished())); connect(job, SIGNAL(finishedWithError(QNetworkReply *)), this, SLOT(slotPropfindFinishedWithError())); connect(job, SIGNAL(destroyed(QObject *)), this, SLOT(slotJobDestroyed(QObject *))); connect(job, SIGNAL(directoryListingIterated(QString, QMap<QString, QString>)), this, SLOT(slotPropfindIterate(QString, QMap<QString, QString>))); job->start(); return; } else if (progressInfo._valid) {
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; }