1515#include < QJsonArray>
1616#include < QJsonObject>
1717#include < QJsonValue>
18+ #include < QCryptographicHash>
1819
1920#include < memory>
2021#include < filesystem>
@@ -522,18 +523,19 @@ void FakePutReply::abort()
522523 emit finished ();
523524}
524525
525- FakePutMultiFileReply::FakePutMultiFileReply (FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, const QString &contentType, const QByteArray &putPayload, QObject *parent)
526+ FakePutMultiFileReply::FakePutMultiFileReply (FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, const QString &contentType, const QByteArray &putPayload, const QString &serverVersion, QObject *parent)
526527 : FakeReply { parent }
528+ , _serverVersion(serverVersion)
527529{
528530 setRequest (request);
529531 setUrl (request.url ());
530532 setOperation (op);
531533 open (QIODevice::ReadOnly);
532- _allFileInfo = performMultiPart (remoteRootFileInfo, request, putPayload, contentType);
534+ _allFileInfo = performMultiPart (remoteRootFileInfo, request, putPayload, contentType, _serverVersion );
533535 QMetaObject::invokeMethod (this , " respond" , Qt::QueuedConnection);
534536}
535537
536- QVector<FileInfo *> FakePutMultiFileReply::performMultiPart (FileInfo &remoteRootFileInfo, const QNetworkRequest &request, const QByteArray &putPayload, const QString &contentType)
538+ QVector<FileInfo *> FakePutMultiFileReply::performMultiPart (FileInfo &remoteRootFileInfo, const QNetworkRequest &request, const QByteArray &putPayload, const QString &contentType, const QString &serverVersion )
537539{
538540 Q_UNUSED (request)
539541 QVector<FileInfo *> result;
@@ -555,8 +557,55 @@ QVector<FileInfo *> FakePutMultiFileReply::performMultiPart(FileInfo &remoteRoot
555557 }
556558 const auto fileName = allHeaders[QStringLiteral (" x-file-path" )];
557559 const auto modtime = allHeaders[QByteArrayLiteral (" x-file-mtime" )].toLongLong ();
560+ const auto expectedMd5Checksum = allHeaders[QStringLiteral (" x-file-md5" )];
561+ const auto standardChecksum = allHeaders[QStringLiteral (" oc-checksum" )];
558562 Q_ASSERT (!fileName.isEmpty ());
559563 Q_ASSERT (modtime > 0 );
564+
565+ auto components = serverVersion.split (' .' );
566+ const auto serverIntVersion = OCC::Account::makeServerVersion (components.value (0 ).toInt (),
567+ components.value (1 ).toInt (),
568+ components.value (2 ).toInt ());
569+
570+ const auto md5ChecksumMandatory = serverIntVersion < OCC::Account::makeServerVersion (32 , 0 , 0 );
571+
572+ if (md5ChecksumMandatory) {
573+ Q_ASSERT (!expectedMd5Checksum.isEmpty ());
574+ } else {
575+ Q_ASSERT (expectedMd5Checksum.isEmpty ());
576+ }
577+ Q_ASSERT (!standardChecksum.isEmpty ());
578+
579+ const auto standardChecksumComponents = standardChecksum.split (' :' );
580+ Q_ASSERT (standardChecksumComponents.size () == 2 );
581+ auto standardHashAlgorithm = QCryptographicHash::Algorithm::Sha1;
582+ const auto standardHashAlgorithmString = standardChecksumComponents.at (0 );
583+ if (standardHashAlgorithmString == QStringLiteral (" MD5" )) {
584+ standardHashAlgorithm = QCryptographicHash::Algorithm::Md5;
585+ } else if (standardHashAlgorithmString == QStringLiteral (" SHA1" )) {
586+ standardHashAlgorithm = QCryptographicHash::Algorithm::Sha1;
587+ } else if (standardHashAlgorithmString == QStringLiteral (" SHA256" )) {
588+ standardHashAlgorithm = QCryptographicHash::Algorithm::Sha256;
589+ } else if (standardHashAlgorithmString == QStringLiteral (" SHA3_256" )) {
590+ standardHashAlgorithm = QCryptographicHash::Algorithm::Sha3_256;
591+ } else if (standardHashAlgorithmString == QStringLiteral (" Adler32" )) {
592+ Q_ASSERT (false );
593+ }
594+
595+ if (md5ChecksumMandatory) {
596+ QCryptographicHash md5SumAlgorithm{QCryptographicHash::Algorithm::Md5};
597+
598+ md5SumAlgorithm.addData (onePartBody.toLatin1 ());
599+ const auto computedMd5Checksum = md5SumAlgorithm.result ().toHex ();
600+ Q_ASSERT (expectedMd5Checksum == computedMd5Checksum);
601+ }
602+
603+ QCryptographicHash standardSumAlgorithm{standardHashAlgorithm};
604+
605+ standardSumAlgorithm.addData (onePartBody.toLatin1 ());
606+ const auto computedStandardChecksum = standardSumAlgorithm.result ().toHex ();
607+ Q_ASSERT (standardChecksumComponents.at (1 ) == computedStandardChecksum);
608+
560609 FileInfo *fileInfo = remoteRootFileInfo.find (fileName);
561610 if (fileInfo) {
562611 fileInfo->size = onePartBody.size ();
@@ -1110,7 +1159,7 @@ QNetworkReply *FakeQNAM::createRequest(QNetworkAccessManager::Operation op, cons
11101159 reply = new FakeChunkMoveReply { info, _remoteRootFileInfo, op, newRequest, this };
11111160 } else if (verb == QLatin1String (" POST" ) || op == QNetworkAccessManager::PostOperation) {
11121161 if (contentType.startsWith (QStringLiteral (" multipart/related; boundary=" ))) {
1113- reply = new FakePutMultiFileReply { info, op, newRequest, contentType, outgoingData->readAll (), this };
1162+ reply = new FakePutMultiFileReply { info, op, newRequest, contentType, outgoingData->readAll (), _serverVersion, this };
11141163 }
11151164 } else if (verb == QLatin1String (" LOCK" ) || verb == QLatin1String (" UNLOCK" )) {
11161165 reply = new FakeFileLockReply{info, op, newRequest, this };
@@ -1135,6 +1184,11 @@ QNetworkReply * FakeQNAM::overrideReplyWithError(QString fileName, QNetworkAcces
11351184 return reply;
11361185}
11371186
1187+ void FakeQNAM::setServerVersion (const QString &version)
1188+ {
1189+ _serverVersion = version;
1190+ }
1191+
11381192FakeFolder::FakeFolder (const FileInfo &fileTemplate, const OCC::Optional<FileInfo> &localFileInfo, const QString &remotePath)
11391193 : _localModifier(_tempDir.path())
11401194{
@@ -1156,7 +1210,8 @@ FakeFolder::FakeFolder(const FileInfo &fileTemplate, const OCC::Optional<FileInf
11561210 _account->setUrl (QUrl (QStringLiteral (" http://admin:admin@localhost/owncloud" )));
11571211 _account->setCredentials (new FakeCredentials { _fakeQnam });
11581212 _account->setDavDisplayName (QStringLiteral (" fakename" ));
1159- _account->setServerVersion (QStringLiteral (" 10.0.0" ));
1213+ _account->setServerVersion (_serverVersion);
1214+ _fakeQnam->setServerVersion (_serverVersion);
11601215
11611216 _journalDb = std::make_unique<OCC::SyncJournalDb>(localPath () + QStringLiteral (" .sync_test.db" ));
11621217 _syncEngine = std::make_unique<OCC::SyncEngine>(_account, localPath (), OCC::SyncOptions{}, remotePath, _journalDb.get ());
@@ -1279,6 +1334,17 @@ void FakeFolder::enableEnforceWindowsFileNameCompatibility()
12791334 });
12801335}
12811336
1337+ void FakeFolder::setServerVersion (const QString &version)
1338+ {
1339+ if (_serverVersion == version) {
1340+ return ;
1341+ }
1342+
1343+ _serverVersion = version;
1344+ _account->setServerVersion (_serverVersion);
1345+ _fakeQnam->setServerVersion (_serverVersion);
1346+ }
1347+
12821348FileInfo FakeFolder::currentLocalState ()
12831349{
12841350 QDir rootDir { _tempDir.path () };
0 commit comments