Skip to content

Commit

Permalink
Report error Virus Detected. Updated tests.
Browse files Browse the repository at this point in the history
Signed-off-by: alex-z <[email protected]>
  • Loading branch information
allexzander committed Dec 11, 2023
1 parent 5f29942 commit ab95ae8
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/libsync/bulkpropagatorjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ void BulkPropagatorJob::slotPutFinishedOneFile(const BulkUploadItem &singleFile,
singleFile._item->_requestId = job->requestId();
if (singleFile._item->_httpErrorCode != 200) {
commonErrorHandling(singleFile._item, fileReply[QStringLiteral("message")].toString());
const auto exceptionParsed = getExceptionFromReply(job->reply());
singleFile._item->_errorExceptionName = exceptionParsed.first;
singleFile._item->_errorExceptionMessage = exceptionParsed.second;
return;
}

Expand Down
10 changes: 9 additions & 1 deletion src/libsync/owncloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,15 @@ void PropagateItemJob::reportClientStatuses()
propagator()->account()->reportClientStatus(ClientStatusReporting::Status::DownloadError_ConflictInvalidCharacters);
} else if (_item->_httpErrorCode != 0 && _item->_httpErrorCode != 200 && _item->_httpErrorCode != 201 && _item->_httpErrorCode != 204) {
if (_item->_direction == SyncFileItem::Up) {
propagator()->account()->reportClientStatus(ClientStatusReporting::Status::UploadError_ServerError);
const auto isCodeBadReqOrUnsupportedMediaType = (_item->_httpErrorCode == 400 || _item->_httpErrorCode == 415);
const auto isExceptionInfoPresent = !_item->_errorExceptionName.isEmpty() && !_item->_errorExceptionMessage.isEmpty();
if (isCodeBadReqOrUnsupportedMediaType && isExceptionInfoPresent
&& _item->_errorExceptionName.contains(QStringLiteral("UnsupportedMediaType"))
&& _item->_errorExceptionMessage.contains(QStringLiteral("virus"), Qt::CaseInsensitive)) {
propagator()->account()->reportClientStatus(ClientStatusReporting::Status::UploadError_Virus_Detected);
} else {
propagator()->account()->reportClientStatus(ClientStatusReporting::Status::UploadError_ServerError);
}
} else {
propagator()->account()->reportClientStatus(ClientStatusReporting::Status::DownloadError_ServerError);
}
Expand Down
47 changes: 47 additions & 0 deletions src/libsync/owncloudpropagator_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ inline bool fileIsStillChanging(const OCC::SyncFileItem &item)

namespace OCC {


inline QByteArray getEtagFromReply(QNetworkReply *reply)
{
QByteArray ocEtag = parseEtag(reply->rawHeader("OC-ETag"));
Expand All @@ -62,6 +63,52 @@ inline QByteArray getEtagFromReply(QNetworkReply *reply)
return ret;
}

inline QPair<QByteArray, QByteArray> getExceptionFromReply(QNetworkReply *reply)
{
Q_ASSERT(reply);
if (!reply) {
qDebug() << "Could not parse null reply";
return {};
}
const auto httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// only for BadRequest and UnsupportedMediaType
if (httpStatusCode != 400 && httpStatusCode != 415) {
return {};
}

// we must not modify the buffer
const auto replyBody = reply->peek(reply->bytesAvailable());

// parse exception name
auto exceptionNameStartIndex = replyBody.indexOf(QByteArrayLiteral("<s:exception>"));
if (exceptionNameStartIndex == -1) {
qDebug() << "Could not parse exception. No <s:exception> tag.";
return {};
}
exceptionNameStartIndex += QByteArrayLiteral("<s:exception>").size();
const auto exceptionNameEndIndex = replyBody.indexOf('<', exceptionNameStartIndex);
if (exceptionNameEndIndex == -1) {
return {};
}
const auto exceptionName = replyBody.mid(exceptionNameStartIndex, exceptionNameEndIndex - exceptionNameStartIndex);

// parse exception message
auto exceptionMessageStartIndex = replyBody.indexOf(QByteArrayLiteral("<s:message>"), exceptionNameEndIndex);
if (exceptionMessageStartIndex == -1) {
qDebug() << "Could not parse exception. No <s:message> tag.";
return {exceptionName, {}};
}
exceptionMessageStartIndex += QByteArrayLiteral("<s:message>").size();
const auto exceptionMessageEndIndex = replyBody.indexOf('<', exceptionMessageStartIndex);
if (exceptionMessageEndIndex == -1) {
return {exceptionName, {}};
}

const auto exceptionMessage = replyBody.mid(exceptionMessageStartIndex, exceptionMessageEndIndex - exceptionMessageStartIndex);

return {exceptionName, exceptionMessage};
}

/**
* Given an error from the network, map to a SyncFileItem::Status error
*/
Expand Down
3 changes: 3 additions & 0 deletions src/libsync/propagateupload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ bool PollJob::finished()
_item->_requestId = requestId();
_item->_status = classifyError(err, _item->_httpErrorCode);
_item->_errorString = errorString();
const auto exceptionParsed = getExceptionFromReply(reply());
_item->_errorExceptionName = exceptionParsed.first;
_item->_errorExceptionMessage = exceptionParsed.second;

if (_item->_status == SyncFileItem::FatalError || _item->_httpErrorCode >= 400) {
if (_item->_status != SyncFileItem::FatalError
Expand Down
6 changes: 6 additions & 0 deletions src/libsync/propagateuploadng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ void PropagateUploadFileNG::slotPutFinished()
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
_item->_requestId = job->requestId();
commonErrorHandling(job);
const auto exceptionParsed = getExceptionFromReply(job->reply());
_item->_errorExceptionName = exceptionParsed.first;
_item->_errorExceptionMessage = exceptionParsed.second;
return;
}

Expand Down Expand Up @@ -496,6 +499,9 @@ void PropagateUploadFileNG::slotMoveJobFinished()

if (err != QNetworkReply::NoError) {
commonErrorHandling(job);
const auto exceptionParsed = getExceptionFromReply(job->reply());
_item->_errorExceptionName = exceptionParsed.first;
_item->_errorExceptionMessage = exceptionParsed.second;
return;
}

Expand Down
3 changes: 3 additions & 0 deletions src/libsync/propagateuploadv1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ void PropagateUploadFileV1::slotPutFinished()
QNetworkReply::NetworkError err = job->reply()->error();
if (err != QNetworkReply::NoError) {
commonErrorHandling(job);
const auto exceptionParsed = getExceptionFromReply(job->reply());
_item->_errorExceptionName = exceptionParsed.first;
_item->_errorExceptionMessage = exceptionParsed.second;
return;
}

Expand Down
2 changes: 2 additions & 0 deletions src/libsync/syncfileitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ class OWNCLOUDSYNC_EXPORT SyncFileItem
quint16 _httpErrorCode = 0;
RemotePermissions _remotePerm;
QString _errorString; // Contains a string only in case of error
QString _errorExceptionName; // Contains a server exception string only in case of error
QString _errorExceptionMessage; // Contains a server exception message string only in case of error
QByteArray _responseTimeStamp;
QByteArray _requestId; // X-Request-Id of the failed request
quint32 _affectedItems = 1; // the number of affected items by the operation on this item.
Expand Down
23 changes: 23 additions & 0 deletions test/testnextcloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "propagatedownload.h"
#include "owncloudpropagator_p.h"
#include "syncenginetestutils.h"

using namespace OCC;
namespace OCC {
Expand Down Expand Up @@ -76,6 +77,28 @@ private slots:
QCOMPARE(parseEtag(test.first), QByteArray(test.second));
}
}

void testParseException()
{
QNetworkRequest request;
request.setUrl(QStringLiteral("http://cloud.example.de/"));
const auto body = QByteArrayLiteral(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<d:error xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\">\n"
"<s:exception>Sabre\\Exception\\UnsupportedMediaType</s:exception>\n"
"<s:message>Virus detected!</s:message>\n"
"</d:error>");
const auto reply = new FakeErrorReply(QNetworkAccessManager::PutOperation,
request,
this,
415, body);
const auto exceptionParsed = OCC::getExceptionFromReply(reply);
// verify parsing succeeded
QVERIFY(!exceptionParsed.first.isEmpty());
QVERIFY(!exceptionParsed.second.isEmpty());
// verify buffer is not changed
QCOMPARE(reply->readAll().size(), body.size());
}
};

QTEST_APPLESS_MAIN(TestNextcloudPropagator)
Expand Down

0 comments on commit ab95ae8

Please sign in to comment.