diff options
author | kh1 <karsten.heimrich@nokia.com> | 2012-10-01 15:40:53 +0200 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@digia.com> | 2012-10-17 09:19:26 +0200 |
commit | b878ca377795e5e5bad16428683de711c3e60cdc (patch) | |
tree | c916da1b9620806c78050a073261a8b5c59a4a56 /src | |
parent | ba31ab511d9b1f5cfd581bf8ed2f35671dd26136 (diff) |
Add data to the cryptographic hash while downloading.
Task-number: QTIFW-10
Add the data on the fly, fixes re-reading the whole file to
compute the checksum.
Change-Id: I764019ab051e1faef2868d13cb17da101fad2fa8
Reviewed-by: Niels Weber <niels.weber@digia.com>
Reviewed-by: Tim Jenssen <tim.jenssen@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/installer/downloadarchivesjob.cpp | 46 | ||||
-rw-r--r-- | src/libs/kdtools/kdupdaterfiledownloader.cpp | 221 | ||||
-rw-r--r-- | src/libs/kdtools/kdupdaterfiledownloader.h | 11 | ||||
-rw-r--r-- | src/libs/kdtools/kdupdaterfiledownloader_p.h | 35 | ||||
-rw-r--r-- | src/libs/kdtools/kdupdaterupdate.cpp | 2 |
5 files changed, 114 insertions, 201 deletions
diff --git a/src/libs/installer/downloadarchivesjob.cpp b/src/libs/installer/downloadarchivesjob.cpp index 49abee339..f7aa2c896 100644 --- a/src/libs/installer/downloadarchivesjob.cpp +++ b/src/libs/installer/downloadarchivesjob.cpp @@ -217,31 +217,24 @@ void DownloadArchivesJob::registerFile() { Q_ASSERT(m_downloader != 0); - const QString tempFile = m_downloader->downloadedFileName(); - if (m_core->testChecksum()) { - QFile archiveFile(tempFile); - if (archiveFile.open(QFile::ReadOnly)) { - const QByteArray archiveHash = QInstaller::calculateHash(&archiveFile, QCryptographicHash::Sha1) - .toHex(); - if ((archiveHash != m_currentHash) && (!m_canceled)) { - //TODO: Maybe we should try to download the file again automatically - const QMessageBox::Button res = - MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("DownloadError"), tr("Download Error"), tr("Hash verification while " - "downloading failed. This is a temporary error, please retry."), - QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel); - - if (res == QMessageBox::Cancel) { - finishWithError(tr("Could not verify Hash")); - return; - } - - fetchNextArchiveHash(); - return; - } - } else { - finishWithError(tr("Could not open %1").arg(tempFile)); + if (m_canceled) + return; + + if (m_core->testChecksum() && m_currentHash != m_downloader->sha1Sum().toHex()) { + //TODO: Maybe we should try to download the file again automatically + const QMessageBox::Button res = + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("DownloadError"), tr("Download Error"), tr("Hash verification while " + "downloading failed. This is a temporary error, please retry."), + QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel); + + if (res == QMessageBox::Cancel) { + finishWithError(tr("Could not verify Hash")); + return; } + + fetchNextArchiveHash(); + return; } ++m_archivesDownloaded; @@ -251,9 +244,10 @@ void DownloadArchivesJob::registerFile() emit progressChanged(double(m_archivesDownloaded) / m_archivesToDownloadCount); } - m_temporaryFiles.insert(tempFile); + m_temporaryFiles.insert(m_downloader->downloadedFileName()); const QPair<QString, QString> pair = m_archivesToDownload.takeFirst(); - QInstallerCreator::BinaryFormatEngineHandler::instance()->registerArchive(pair.first, tempFile); + QInstallerCreator::BinaryFormatEngineHandler::instance()->registerArchive(pair.first, + m_downloader->downloadedFileName()); fetchNextArchiveHash(); } diff --git a/src/libs/kdtools/kdupdaterfiledownloader.cpp b/src/libs/kdtools/kdupdaterfiledownloader.cpp index ec2293a2c..e9adb42b3 100644 --- a/src/libs/kdtools/kdupdaterfiledownloader.cpp +++ b/src/libs/kdtools/kdupdaterfiledownloader.cpp @@ -50,93 +50,6 @@ static double calcProgress(qint32 done, qint32 total) } -// -- HashVerificationJob - -class HashVerificationJob::Private -{ -public: - Private() - : hash(QCryptographicHash::Sha1) - , error(HashVerificationJob::ReadError) - , timerId(-1) { } - - QPointer<QIODevice> device; - QByteArray sha1Sum; - QCryptographicHash hash; - HashVerificationJob::Error error; - int timerId; -}; - -HashVerificationJob::HashVerificationJob(QObject* parent) - : QObject(parent) - , d(new Private) -{ -} - -HashVerificationJob::~HashVerificationJob() -{ - delete d; -} - -void HashVerificationJob::setDevice(QIODevice* dev) -{ - d->device = dev; -} - -void HashVerificationJob::setSha1Sum(const QByteArray &sum) -{ - d->sha1Sum = sum; -} - -int HashVerificationJob::error() const -{ - return d->error; -} - -bool HashVerificationJob::hasError() const -{ - return d->error != NoError; -} - -void HashVerificationJob::start() -{ - Q_ASSERT(d->device); - d->timerId = startTimer(0); -} - -void HashVerificationJob::emitFinished() -{ - emit finished(this); - deleteLater(); -} - -void HashVerificationJob::timerEvent(QTimerEvent*) -{ - Q_ASSERT(d->timerId >= 0); - if (d->sha1Sum.isEmpty()) { - killTimer(d->timerId); - d->timerId = -1; - d->error = NoError; - d->device->close(); - emitFinished(); - return; - } - - QByteArray buf; - buf.resize(128 * 1024); - const qint64 read = d->device->read(buf.data(), buf.size()); - if (read > 0) { - d->hash.addData(buf.constData(), read); - return; - } - - d->error = d->hash.result() == d->sha1Sum ? NoError : SumsDifferError; - killTimer(d->timerId); - d->timerId = -1; - emitFinished(); -} - - // -- KDUpdater::FileDownloader /*! @@ -171,7 +84,9 @@ void HashVerificationJob::timerEvent(QTimerEvent*) struct KDUpdater::FileDownloader::Private { Private() - : autoRemove(true) + : m_hash(QCryptographicHash::Sha1) + , m_assumedSha1Sum("") + , autoRemove(true) , m_speedTimerInterval(100) , m_bytesReceived(0) , m_bytesToReceive(0) @@ -190,7 +105,10 @@ struct KDUpdater::FileDownloader::Private QUrl url; QString scheme; - QByteArray sha1Sum; + + QCryptographicHash m_hash; + QByteArray m_assumedSha1Sum; + QString errorString; bool autoRemove; bool followRedirect; @@ -233,14 +151,19 @@ QUrl KDUpdater::FileDownloader::url() const return d->url; } -void KDUpdater::FileDownloader::setSha1Sum(const QByteArray &sum) +QByteArray KDUpdater::FileDownloader::sha1Sum() const { - d->sha1Sum = sum; + return d->m_hash.result(); } -QByteArray KDUpdater::FileDownloader::sha1Sum() const +QByteArray KDUpdater::FileDownloader::assumedSha1Sum() const +{ + return d->m_assumedSha1Sum; +} + +void KDUpdater::FileDownloader::setAssumedSha1Sum(const QByteArray &sum) { - return d->sha1Sum; + d->m_assumedSha1Sum = sum; } QString FileDownloader::errorString() const @@ -255,24 +178,16 @@ void FileDownloader::setDownloadAborted(const QString &error) emit downloadAborted(error); } -void KDUpdater::FileDownloader::setDownloadCompleted(const QString &path) +void KDUpdater::FileDownloader::setDownloadCompleted() { - HashVerificationJob *job = new HashVerificationJob; - QFile *file = new QFile(path, job); - if (!file->open(QIODevice::ReadOnly)) { - emit downloadProgress(1); + if (d->m_assumedSha1Sum.isEmpty() || (d->m_assumedSha1Sum == sha1Sum())) { + onSuccess(); + emit downloadCompleted(); + emit downloadStatus(tr("Download finished.")); + } else { onError(); - setDownloadAborted(tr("Could not reopen downloaded file %1 for reading: %2").arg(path, - file->errorString())); - delete job; - return; + setDownloadAborted(tr("Cryptographic hashes do not match.")); } - - job->setDevice(file); - job->setSha1Sum(d->sha1Sum); - connect(job, SIGNAL(finished(KDUpdater::HashVerificationJob*)), this, - SLOT(sha1SumVerified(KDUpdater::HashVerificationJob*))); - job->start(); } void KDUpdater::FileDownloader::setDownloadCanceled() @@ -281,18 +196,6 @@ void KDUpdater::FileDownloader::setDownloadCanceled() emit downloadStatus(tr("Download canceled.")); } -void KDUpdater::FileDownloader::sha1SumVerified(KDUpdater::HashVerificationJob *job) -{ - if (job->hasError()) { - onError(); - setDownloadAborted(tr("Cryptographic hashes do not match.")); - } else { - onSuccess(); - emit downloadCompleted(); - emit downloadStatus(tr("Download finished.")); - } -} - QString KDUpdater::FileDownloader::scheme() const { return d->scheme; @@ -451,6 +354,16 @@ void KDUpdater::FileDownloader::emitEstimatedDownloadTime() emit estimatedDownloadTime((d->m_bytesToReceive - d->m_bytesReceived) / d->m_downloadSpeed); } +void KDUpdater::FileDownloader::addCheckSumData(const QByteArray &data) +{ + d->m_hash.addData(data); +} + +void KDUpdater::FileDownloader::addCheckSumData(const char *data, int length) +{ + d->m_hash.addData(data, length); +} + /*! Returns a copy of the proxy factory that this FileDownloader object is using to determine the proxies to be used for requests. @@ -649,6 +562,7 @@ void KDUpdater::LocalFileDownloader::timerEvent(QTimerEvent *event) toWrite -= numWritten; } addSample(numRead); + addCheckSumData(buffer.data(), numRead); if (numRead > 0) { setProgress(d->source->pos(), d->source->size()); @@ -661,7 +575,7 @@ void KDUpdater::LocalFileDownloader::timerEvent(QTimerEvent *event) killTimer(d->timerId); d->timerId = -1; - setDownloadCompleted(d->destination->fileName()); + setDownloadCompleted(); } else if (event->timerId() == downloadSpeedTimerId()) { emitDownloadSpeed(); emitDownloadStatus(); @@ -701,13 +615,13 @@ void LocalFileDownloader::onError() struct KDUpdater::ResourceFileDownloader::Private { Private() - : downloaded(false), - timerId(-1) + : timerId(-1) + , downloaded(false) {} - QString destFileName; - bool downloaded; int timerId; + QFile destFile; + bool downloaded; }; KDUpdater::ResourceFileDownloader::ResourceFileDownloader(QObject *parent) @@ -748,17 +662,18 @@ void KDUpdater::ResourceFileDownloader::doDownload() // Open source and destination files QUrl url = this->url(); url.setScheme(QString::fromLatin1("file")); - d->destFileName = QString::fromLatin1(":%1").arg(url.toLocalFile()); + d->destFile.setFileName(QString::fromLatin1(":%1").arg(url.toLocalFile())); - // Start a timer and kickoff the copy process - d->timerId = startTimer(0); // as fast as possible emit downloadStarted(); emit downloadProgress(0); + + d->destFile.open(QIODevice::ReadOnly); + d->timerId = startTimer(0); // start as fast as possible } QString KDUpdater::ResourceFileDownloader::downloadedFileName() const { - return d->destFileName; + return d->destFile.fileName(); } void KDUpdater::ResourceFileDownloader::setDownloadedFileName(const QString &/*name*/) @@ -782,21 +697,55 @@ void KDUpdater::ResourceFileDownloader::cancelDownload() setDownloadCanceled(); } -void KDUpdater::ResourceFileDownloader::timerEvent(QTimerEvent *) +void KDUpdater::ResourceFileDownloader::timerEvent(QTimerEvent *event) { - killTimer(d->timerId); - d->timerId = -1; - setDownloadCompleted(d->destFileName); + if (event->timerId() == d->timerId) { + if (!d->destFile.isOpen()) { + onError(); + killTimer(d->timerId); + emit downloadProgress(1); + setDownloadAborted(tr("Could not read resource file \"%1\". Reason:").arg(downloadedFileName(), + d->destFile.errorString())); + return; + } + + QByteArray buffer; + buffer.resize(32768); + const qint64 numRead = d->destFile.read(buffer.data(), buffer.size()); + + addSample(numRead); + addCheckSumData(buffer.data(), numRead); + + if (numRead > 0) { + setProgress(d->destFile.pos(), d->destFile.size()); + emit downloadProgress(calcProgress(d->destFile.pos(), d->destFile.size())); + return; + } + + killTimer(d->timerId); + d->timerId = -1; + setDownloadCompleted(); + } else if (event->timerId() == downloadSpeedTimerId()) { + emitDownloadSpeed(); + emitDownloadStatus(); + emitDownloadProgress(); + emitEstimatedDownloadTime(); + } } void KDUpdater::ResourceFileDownloader::onSuccess() { + d->destFile.close(); d->downloaded = true; + stopDownloadSpeedTimer(); } void KDUpdater::ResourceFileDownloader::onError() { + d->destFile.close(); d->downloaded = false; + stopDownloadSpeedTimer(); + d->destFile.setFileName(QString()); } @@ -939,7 +888,7 @@ void KDUpdater::FtpDownloader::ftpCmdFinished(int id, bool error) d->ftpCmdId = -1; d->destination->flush(); - setDownloadCompleted(d->destination->fileName()); + setDownloadCompleted(); } void FtpDownloader::onSuccess() @@ -1015,6 +964,7 @@ void KDUpdater::FtpDownloader::ftpReadyRead() written += numWritten; } addSample(written); + addCheckSumData(buffer.data(), read); } } @@ -1138,6 +1088,7 @@ void KDUpdater::HttpDownloader::httpReadyRead() written += numWritten; } addSample(written); + addCheckSumData(buffer.data(), read); } } @@ -1212,7 +1163,7 @@ void KDUpdater::HttpDownloader::httpReqFinished() httpReadyRead(); d->destination->flush(); - setDownloadCompleted(d->destination->fileName()); + setDownloadCompleted(); d->http->deleteLater(); d->http = 0; } diff --git a/src/libs/kdtools/kdupdaterfiledownloader.h b/src/libs/kdtools/kdupdaterfiledownloader.h index 6f6d03cc5..5c5fab459 100644 --- a/src/libs/kdtools/kdupdaterfiledownloader.h +++ b/src/libs/kdtools/kdupdaterfiledownloader.h @@ -23,7 +23,6 @@ #ifndef KD_UPDATER_FILE_DOWNLOADER_H #define KD_UPDATER_FILE_DOWNLOADER_H -#include "kdupdater.h" #include "kdtoolsglobal.h" #include <QtCore/QObject> @@ -51,7 +50,9 @@ public: void setUrl(const QUrl &url); QByteArray sha1Sum() const; - void setSha1Sum(const QByteArray &sha1); + + QByteArray assumedSha1Sum() const; + void setAssumedSha1Sum(const QByteArray &sha1); QString scheme() const; void setScheme(const QString &scheme); @@ -80,7 +81,6 @@ public: public Q_SLOTS: virtual void cancelDownload(); - void sha1SumVerified(KDUpdater::HashVerificationJob *job); protected: virtual void onError() = 0; @@ -105,7 +105,7 @@ private: protected: void setDownloadCanceled(); - void setDownloadCompleted(const QString &filepath); + void setDownloadCompleted(); void setDownloadAborted(const QString &error); void runDownloadSpeedTimer(); @@ -120,6 +120,9 @@ protected: void emitDownloadProgress(); void emitEstimatedDownloadTime(); + void addCheckSumData(const QByteArray &data); + void addCheckSumData(const char *data, int length); + private Q_SLOTS: virtual void doDownload() = 0; diff --git a/src/libs/kdtools/kdupdaterfiledownloader_p.h b/src/libs/kdtools/kdupdaterfiledownloader_p.h index c47663bd1..a8ceb65f6 100644 --- a/src/libs/kdtools/kdupdaterfiledownloader_p.h +++ b/src/libs/kdtools/kdupdaterfiledownloader_p.h @@ -31,41 +31,6 @@ namespace KDUpdater { -//TODO make it a KDJob once merged -class HashVerificationJob : public QObject -{ - Q_OBJECT - -public: - enum Error { - NoError = 0, - ReadError = 128, - SumsDifferError - }; - - explicit HashVerificationJob(QObject *parent = 0); - ~HashVerificationJob(); - - void setDevice(QIODevice *dev); - void setSha1Sum(const QByteArray &data); - - bool hasError() const; - int error() const; - - void start(); - -Q_SIGNALS: - void finished(KDUpdater::HashVerificationJob *); - -private: - void emitFinished(); - void timerEvent(QTimerEvent *te); - -private: - class Private; - Private *d; -}; - class LocalFileDownloader : public FileDownloader { Q_OBJECT diff --git a/src/libs/kdtools/kdupdaterupdate.cpp b/src/libs/kdtools/kdupdaterupdate.cpp index 3e560e0b4..0ae2ebfaf 100644 --- a/src/libs/kdtools/kdupdaterupdate.cpp +++ b/src/libs/kdtools/kdupdaterupdate.cpp @@ -95,7 +95,7 @@ Update::Update(Application *application, const UpdateSourceInfo &sourceInfo, d->fileDownloader = FileDownloaderFactory::instance().create(updateUrl.scheme(), this); if (d->fileDownloader) { d->fileDownloader->setUrl(d->updateUrl); - d->fileDownloader->setSha1Sum(d->sha1sum); + d->fileDownloader->setAssumedSha1Sum(d->sha1sum); connect(d->fileDownloader, SIGNAL(downloadProgress(double)), this, SLOT(downloadProgress(double))); connect(d->fileDownloader, SIGNAL(downloadCanceled()), this, SIGNAL(stopped())); connect(d->fileDownloader, SIGNAL(downloadCompleted()), this, SIGNAL(finished())); |