QGCFileDownload.cc 4.92 KB
Newer Older
1 2
/****************************************************************************
 *
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8
 *
 * 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
9 10 11 12 13 14


#include "QGCFileDownload.h"

#include <QFileInfo>
#include <QStandardPaths>
15
#include <QNetworkProxy>
Don Gagne's avatar
Don Gagne committed
16 17 18 19 20 21 22

QGCFileDownload::QGCFileDownload(QObject* parent)
    : QNetworkAccessManager(parent)
{

}

23
bool QGCFileDownload::download(const QString& remoteFile, bool redirect)
Don Gagne's avatar
Don Gagne committed
24
{
25 26 27 28
    if (!redirect) {
        _originalRemoteFile = remoteFile;
    }

Don Gagne's avatar
Don Gagne committed
29 30 31 32 33 34 35
    if (remoteFile.isEmpty()) {
        qWarning() << "downloadFile empty";
        return false;
    }
    

    QUrl remoteUrl;
Don Gagne's avatar
Don Gagne committed
36
    if (remoteFile.startsWith("http:") || remoteFile.startsWith("https:")) {
Don Gagne's avatar
Don Gagne committed
37 38 39 40 41 42 43 44 45 46
        remoteUrl.setUrl(remoteFile);
    } else {
        remoteUrl = QUrl::fromLocalFile(remoteFile);
    }
    if (!remoteUrl.isValid()) {
        qWarning() << "Remote URL is invalid" << remoteFile;
        return false;
    }
    
    QNetworkRequest networkRequest(remoteUrl);
47 48 49 50

    QNetworkProxy tProxy;
    tProxy.setType(QNetworkProxy::DefaultProxy);
    setProxy(tProxy);
Don Gagne's avatar
Don Gagne committed
51 52 53 54 55 56 57 58 59
    
    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);
60 61 62 63 64
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
    connect(networkReply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &QGCFileDownload::_downloadError);
#else
    connect(networkReply, &QNetworkReply::errorOccurred, this, &QGCFileDownload::_downloadError);
#endif
Don Gagne's avatar
Don Gagne committed
65 66 67 68 69 70
    return true;
}

void QGCFileDownload::_downloadFinished(void)
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
71

Don Gagne's avatar
Don Gagne committed
72 73
    // When an error occurs or the user cancels the download, we still end up here. So bail out in
    // those cases.
74
    if (reply->error() != QNetworkReply::NoError) {
DonLakeFlyer's avatar
DonLakeFlyer committed
75
        reply->deleteLater();
Don Gagne's avatar
Don Gagne committed
76 77
        return;
    }
78 79 80 81 82 83 84 85 86 87

    // 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;
    }

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    // Split out filename from path
    QString remoteFileName = QFileInfo(reply->url().toString()).fileName();
    if (remoteFileName.isEmpty()) {
        qWarning() << "Unabled to parse filename from remote url" << reply->url().toString();
        remoteFileName = "DownloadedFile";
    }

    // Strip out http parameters from remote filename
    int parameterIndex = remoteFileName.indexOf("?");
    if (parameterIndex != -1) {
        remoteFileName  = remoteFileName.left(parameterIndex);
    }

    // Determine location to download file to
    QString downloadFilename = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
    if (downloadFilename.isEmpty()) {
        downloadFilename = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
        if (downloadFilename.isEmpty()) {
            emit downloadComplete(_originalRemoteFile, QString(), tr("Unabled to find writable download location. Tried downloads and temp directory."));
            return;
        }
    }
    downloadFilename += "/"  + remoteFileName;
Don Gagne's avatar
Don Gagne committed
111

DonLakeFlyer's avatar
DonLakeFlyer committed
112 113 114
    if (!downloadFilename.isEmpty()) {
        // Store downloaded file in download location
        QFile file(downloadFilename);
115 116
        if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
            emit downloadComplete(_originalRemoteFile, downloadFilename, tr("Could not save downloaded file to %1. Error: %2").arg(downloadFilename).arg(file.errorString()));
DonLakeFlyer's avatar
DonLakeFlyer committed
117 118 119 120 121 122
            return;
        }

        file.write(reply->readAll());
        file.close();

123
        emit downloadComplete(_originalRemoteFile, downloadFilename, QString());
DonLakeFlyer's avatar
DonLakeFlyer committed
124 125 126
    } else {
        QString errorMsg = "Internal error";
        qWarning() << errorMsg;
127
        emit downloadComplete(_originalRemoteFile, downloadFilename, errorMsg);
DonLakeFlyer's avatar
DonLakeFlyer committed
128
    }
DonLakeFlyer's avatar
DonLakeFlyer committed
129 130

    reply->deleteLater();
Don Gagne's avatar
Don Gagne committed
131 132 133 134 135 136 137 138
}

/// @brief Called when an error occurs during download
void QGCFileDownload::_downloadError(QNetworkReply::NetworkError code)
{
    QString errorMsg;
    
    if (code == QNetworkReply::OperationCanceledError) {
139
        errorMsg = tr("Download cancelled");
140 141

    } else if (code == QNetworkReply::ContentNotFoundError) {
142
        errorMsg = tr("Error: File Not Found");
143

Don Gagne's avatar
Don Gagne committed
144
    } else {
145
        errorMsg = tr("Error during download. Error: %1").arg(code);
Don Gagne's avatar
Don Gagne committed
146 147
    }

148
    emit downloadComplete(_originalRemoteFile, QString(), errorMsg);
Don Gagne's avatar
Don Gagne committed
149
}