Skip to content
Snippets Groups Projects
QGCFileDownload.cc 4.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • /****************************************************************************
     *
    
    Gus Grubba's avatar
    Gus Grubba committed
     * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
    
     *
     * QGroundControl is licensed according to the terms in the file
     * COPYING.md in the root of the source code directory.
     *
     ****************************************************************************/
    
    Don Gagne's avatar
    Don Gagne committed
    
    
    #include "QGCFileDownload.h"
    
    #include <QFileInfo>
    #include <QStandardPaths>
    
    #include <QNetworkProxy>
    
    Don Gagne's avatar
    Don Gagne committed
    
    QGCFileDownload::QGCFileDownload(QObject* parent)
        : QNetworkAccessManager(parent)
    {
    
    }
    
    
    bool QGCFileDownload::download(const QString& remoteFile, bool redirect)
    
    Don Gagne's avatar
    Don Gagne committed
    {
    
        if (!redirect) {
            _originalRemoteFile = remoteFile;
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
        if (remoteFile.isEmpty()) {
            qWarning() << "downloadFile empty";
            return false;
        }
        
        // Split out filename from path
        QString remoteFileName = QFileInfo(remoteFile).fileName();
        if (remoteFileName.isEmpty()) {
            qWarning() << "Unabled to parse filename from downloadFile" << remoteFile;
            return false;
        }
    
    
        // Strip out parameters from remote filename
        int parameterIndex = remoteFileName.indexOf("?");
        if (parameterIndex != -1) {
            remoteFileName  = remoteFileName.left(parameterIndex);
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
        // Determine location to download file to
        QString localFile = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
        if (localFile.isEmpty()) {
            localFile = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
            if (localFile.isEmpty()) {
                qDebug() << "Unabled to find writable download location. Tried downloads and temp directory.";
                return false;
            }
        }
        localFile += "/"  + remoteFileName;
    
        QUrl remoteUrl;
    
    Don Gagne's avatar
    Don Gagne committed
        if (remoteFile.startsWith("http:") || remoteFile.startsWith("https:")) {
    
    Don Gagne's avatar
    Don Gagne committed
            remoteUrl.setUrl(remoteFile);
        } else {
            remoteUrl = QUrl::fromLocalFile(remoteFile);
        }
        if (!remoteUrl.isValid()) {
            qWarning() << "Remote URL is invalid" << remoteFile;
            return false;
        }
        
        QNetworkRequest networkRequest(remoteUrl);
    
    
        QNetworkProxy tProxy;
        tProxy.setType(QNetworkProxy::DefaultProxy);
        setProxy(tProxy);
    
    Don Gagne's avatar
    Don Gagne committed
        
        // Store local file location in user attribute so we can retrieve when the download finishes
        networkRequest.setAttribute(QNetworkRequest::User, localFile);
    
    Don Gagne's avatar
    Don Gagne committed
        QNetworkReply* networkReply = get(networkRequest);
        if (!networkReply) {
            qWarning() << "QNetworkAccessManager::get failed";
            return false;
        }
    
        connect(networkReply, &QNetworkReply::downloadProgress, this, &QGCFileDownload::downloadProgress);
        connect(networkReply, &QNetworkReply::finished, this, &QGCFileDownload::_downloadFinished);
    
        connect(networkReply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
                this, &QGCFileDownload::_downloadError);
    
    Don Gagne's avatar
    Don Gagne committed
    
        return true;
    }
    
    void QGCFileDownload::_downloadFinished(void)
    {
        QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
        
        // When an error occurs or the user cancels the download, we still end up here. So bail out in
        // those cases.
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        if (reply->error() != QNetworkReply::NoError) {        
            reply->deleteLater();
    
    Don Gagne's avatar
    Don Gagne committed
            return;
        }
    
    
        // Check for redirection
        QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
        if (!redirectionTarget.isNull()) {
            QUrl redirectUrl = reply->url().resolved(redirectionTarget.toUrl());
            download(redirectUrl.toString(), true /* redirect */);
            reply->deleteLater();
            return;
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
        // Download file location is in user attribute
        QString downloadFilename = reply->request().attribute(QNetworkRequest::User).toString();
    
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        if (!downloadFilename.isEmpty()) {
            // Store downloaded file in download location
            QFile file(downloadFilename);
            if (!file.open(QIODevice::WriteOnly)) {
    
                emit error(tr("Could not save downloaded file to %1. Error: %2").arg(downloadFilename).arg(file.errorString()));
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                return;
            }
    
            file.write(reply->readAll());
            file.close();
    
            emit downloadFinished(_originalRemoteFile, downloadFilename);
        } else {
            QString errorMsg = "Internal error";
            qWarning() << errorMsg;
            emit error(errorMsg);
        }
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
    
        reply->deleteLater();
    
    Don Gagne's avatar
    Don Gagne committed
    }
    
    /// @brief Called when an error occurs during download
    void QGCFileDownload::_downloadError(QNetworkReply::NetworkError code)
    {
        QString errorMsg;
        
        if (code == QNetworkReply::OperationCanceledError) {
    
            errorMsg = tr("Download cancelled");
    
    
        } else if (code == QNetworkReply::ContentNotFoundError) {
    
            errorMsg = tr("Error: File Not Found");
    
    Don Gagne's avatar
    Don Gagne committed
        } else {
    
            errorMsg = tr("Error during download. Error: %1").arg(code);
    
    Don Gagne's avatar
    Don Gagne committed
        }
    
        emit error(errorMsg);
    }