Mercurial > trustbridge
view ui/downloader.cpp @ 633:6c090638b2b4
Use static buffer for module file name.
According to the msdn examle the return value of getmodulefilename
should be used to indicate success and not the size. And according
to comments on that function on Windows 8.1 it does not return
the needed size. So better be more robust and just use max_path
as a limit.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 23 Jun 2014 15:29:48 +0200 |
parents | cb044efdaf0d |
children | 13cf42dbe9bd |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "downloader.h" #ifndef DOWNLOAD_SERVER #define DOWNLOAD_SERVER "https://www.intevation.de" #endif #include <QFile> #include <QDir> #include <QDebug> #include <QStandardPaths> #include <QLocale> #include <QSaveFile> #include <polarssl/net.h> #include <polarssl/ssl.h> #include <polarssl/entropy.h> #include <polarssl/ctr_drbg.h> #include <polarssl/error.h> #include <polarssl/certs.h> #define MAX_SW_SIZE 10485760 #define MAX_LIST_SIZE 1048576 Downloader::Downloader(QObject* parent, const QString& url, const QByteArray& certificate, const QDateTime& newestSW, const QDateTime& newestList, const QString& resourceSW, const QString& resourceList, bool downloadSW): QThread(parent), mLastModSW(newestSW), mLastModList(newestList), mResourceSW(resourceSW), mResourceList(resourceList), mDownloadSW(downloadSW), mSSLConnection(url, certificate) { } Downloader::~Downloader() { } QString Downloader::getDataDirectory() { QString candidate = QStandardPaths::writableLocation(QStandardPaths::DataLocation); if (candidate.isEmpty()) { qDebug() << "Could not find writeable locaction for me"; return QString(); } QDir cDir(candidate); if (!cDir.exists()) { if (!cDir.mkpath(candidate)) { qDebug() << "Could not create path to: " << candidate; return QString(); } } return cDir.absolutePath(); } QMap<QString, QString> Downloader::parseHeaders(QByteArray *data) { int bodyStart = data->indexOf("\r\n\r\n"); QMap<QString, QString> retval; QByteArray headers; QString response(*data); if (bodyStart == -1) { qDebug() << "Could not find header end."; emit error(tr("Invalid response"), SSLConnection::InvalidResponse); return retval; } /* Take the headers with one additional line break */ headers = data->left(bodyStart + 2); /* Chop off the head */ foreach (const QString& line, response.split("\r\n")) { int sepPos = -1; sepPos = line.indexOf(": "); if (sepPos == -1) { continue; } QString key = line.left(sepPos); QString value = line.right(line.size() - sepPos - 2); retval.insert(key, value); } *data = data->right(data->size() - bodyStart - 4); return retval; } QDateTime Downloader::getLastModifiedHeader(const QString &resource) { int ret = -1; QByteArray response; QLocale cLocale = QLocale::c(); QMap<QString, QString> headers; QString headRequest = QString::fromLatin1("HEAD %1 HTTP/1.0\r\n\r\n").arg(resource); ret = mSSLConnection.write(headRequest.toUtf8()); if (ret != 0) { emit error (tr("Connection lost"), SSLConnection::ConnectionLost); return QDateTime(); } response = mSSLConnection.read(1024); qDebug() << "Response from server was: " << response; if (response.isNull()) { qDebug() << "No response"; emit error (tr("Connection lost"), SSLConnection::ConnectionLost); return QDateTime(); } headers = parseHeaders(&response); const QString lastModified = headers.value("Last-Modified"); if (!lastModified.isEmpty()) { QDateTime candidate = cLocale.toDateTime(lastModified, "ddd, dd MMM yyyy HH:mm:ss' GMT'"); if (candidate.isValid()) { return candidate; } } emit error (tr("Invalid response from the server"), SSLConnection::InvalidResponse); return QDateTime(); } bool Downloader::downloadFile(const QString &resource, const QString &fileName, size_t maxSize) { int ret = -1; size_t bytesRead = 0; QString getRequest = QString::fromLatin1("GET %1 HTTP/1.0\r\n\r\n").arg(resource); QSaveFile outputFile(fileName); ret = mSSLConnection.write(getRequest.toUtf8()); // Open / Create the file to write to. if (!outputFile.open(QIODevice::WriteOnly)) { qDebug() << "Failed to open file"; return false; } if (ret != 0) { emit error(tr("Connection lost"), SSLConnection::ConnectionLost); return false; } bool inBody = false; QMap <QString, QString> headers; do { /* Read the response in 8KiB chunks */ int responseSize = 0; QByteArray response = mSSLConnection.read(8192); if (response.isNull()) { qDebug() << "Error reading response"; emit error(tr("Connection lost"), SSLConnection::ConnectionLost); return false; } responseSize = response.size(); if (!inBody) { headers = parseHeaders(&response); inBody = true; } outputFile.write(response); bytesRead += responseSize; if (responseSize < 8192) { /* Nothing more to read */ break; } /* TODO Emit progress */ } while (bytesRead < maxSize); return outputFile.commit(); } void Downloader::run() { int ret; QDateTime remoteModList; QDateTime remoteModSW; if (!mSSLConnection.initialized()) { emit error(tr("Failed to initialize SSL Module."), SSLConnection::ErrUnknown); return; } ret = mSSLConnection.connect(); if (ret != 0) { emit error(tr("Failed to connect."), mSSLConnection.getLastError()); return; } emit progress(tr("Connected"), 1, -1); remoteModSW = getLastModifiedHeader(mResourceSW); emit lastModifiedDate(remoteModSW); if (!remoteModSW.isValid()) { qDebug() << "Could not parse headers for Software"; return; } if (!mLastModSW.isValid() || remoteModSW > mLastModSW) { QString dataDirectory = getDataDirectory(); if (dataDirectory.isEmpty()) { qDebug() << "Failed to get data directory"; return; } QString fileName = dataDirectory.append("/SW-") .append(remoteModSW.toString("yyyyMMddHHmmss")) .append(".exe"); qDebug() << "fileName: " << fileName; if (mDownloadSW) { if (!downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) { return; } } emit newSoftwareAvailable(fileName, remoteModSW); return; } remoteModList = getLastModifiedHeader(mResourceList); if (!remoteModList.isValid()) { qDebug() << "Could not parse headers for List"; return; } if (!mLastModList.isValid() || remoteModList > mLastModList) { QString dataDirectory = getDataDirectory(); if (dataDirectory.isEmpty()) { qDebug() << "Failed to get data directory"; return; } QString fileName = dataDirectory.append("/list-") .append(remoteModList.toString("yyyyMMddHHmmss")) .append(".txt"); qDebug() << "fileName: " << fileName; if (!downloadFile(mResourceList, fileName, MAX_LIST_SIZE)) { return; } emit newListAvailable(fileName, remoteModList); } emit progress(tr("Closing"), 1, -1); }