Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsfiledownloader.cpp 3 : : -------------------------------------- 4 : : Date : November 2016 5 : : Copyright : (C) 2016 by Alessandro Pasotti 6 : : Email : apasotti at boundlessgeo dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgsfiledownloader.h" 17 : : #include "qgsnetworkaccessmanager.h" 18 : : #include "qgsapplication.h" 19 : : #include "qgsauthmanager.h" 20 : : 21 : : #include <QNetworkAccessManager> 22 : : #include <QNetworkRequest> 23 : : #include <QNetworkReply> 24 : : #ifndef QT_NO_SSL 25 : : #include <QSslError> 26 : : #endif 27 : : 28 : 0 : QgsFileDownloader::QgsFileDownloader( const QUrl &url, const QString &outputFileName, const QString &authcfg, bool delayStart ) 29 : 0 : : mUrl( url ) 30 : 0 : , mDownloadCanceled( false ) 31 : 0 : { 32 : 0 : mFile.setFileName( outputFileName ); 33 : 0 : mAuthCfg = authcfg; 34 : 0 : if ( !delayStart ) 35 : 0 : startDownload(); 36 : 0 : } 37 : : 38 : : 39 : 0 : QgsFileDownloader::~QgsFileDownloader() 40 : 0 : { 41 : 0 : if ( mReply ) 42 : : { 43 : 0 : mReply->abort(); 44 : 0 : mReply->deleteLater(); 45 : 0 : } 46 : 0 : } 47 : : 48 : 0 : void QgsFileDownloader::startDownload() 49 : : { 50 : 0 : QgsNetworkAccessManager *nam = QgsNetworkAccessManager::instance(); 51 : : 52 : 0 : QNetworkRequest request( mUrl ); 53 : 0 : QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsFileDownloader" ) ); 54 : 0 : if ( !mAuthCfg.isEmpty() ) 55 : : { 56 : 0 : QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ); 57 : 0 : } 58 : : 59 : 0 : if ( mReply ) 60 : : { 61 : 0 : disconnect( mReply, &QNetworkReply::readyRead, this, &QgsFileDownloader::onReadyRead ); 62 : 0 : disconnect( mReply, &QNetworkReply::finished, this, &QgsFileDownloader::onFinished ); 63 : 0 : disconnect( mReply, &QNetworkReply::downloadProgress, this, &QgsFileDownloader::onDownloadProgress ); 64 : 0 : mReply->abort(); 65 : 0 : mReply->deleteLater(); 66 : 0 : } 67 : : 68 : 0 : mReply = nam->get( request ); 69 : 0 : if ( !mAuthCfg.isEmpty() ) 70 : : { 71 : 0 : QgsApplication::authManager()->updateNetworkReply( mReply, mAuthCfg ); 72 : 0 : } 73 : : 74 : 0 : connect( mReply, &QNetworkReply::readyRead, this, &QgsFileDownloader::onReadyRead ); 75 : 0 : connect( mReply, &QNetworkReply::finished, this, &QgsFileDownloader::onFinished ); 76 : 0 : connect( mReply, &QNetworkReply::downloadProgress, this, &QgsFileDownloader::onDownloadProgress ); 77 : 0 : connect( nam, qOverload< QNetworkReply *>( &QgsNetworkAccessManager::requestTimedOut ), this, &QgsFileDownloader::onRequestTimedOut, Qt::UniqueConnection ); 78 : : #ifndef QT_NO_SSL 79 : 0 : connect( nam, &QgsNetworkAccessManager::sslErrors, this, &QgsFileDownloader::onSslErrors, Qt::UniqueConnection ); 80 : : #endif 81 : 0 : } 82 : : 83 : 0 : void QgsFileDownloader::cancelDownload() 84 : : { 85 : 0 : mDownloadCanceled = true; 86 : 0 : emit downloadCanceled(); 87 : 0 : onFinished(); 88 : 0 : } 89 : : 90 : 0 : void QgsFileDownloader::onRequestTimedOut( QNetworkReply *reply ) 91 : : { 92 : 0 : if ( reply == mReply ) 93 : 0 : error( tr( "Network request %1 timed out" ).arg( mUrl.toString() ) ); 94 : 0 : } 95 : : 96 : : #ifndef QT_NO_SSL 97 : 0 : void QgsFileDownloader::onSslErrors( QNetworkReply *reply, const QList<QSslError> &errors ) 98 : : { 99 : 0 : if ( reply == mReply ) 100 : : { 101 : 0 : QStringList errorMessages; 102 : 0 : errorMessages.reserve( errors.size() + 1 ); 103 : 0 : errorMessages << QStringLiteral( "SSL Errors: " ); 104 : : 105 : 0 : for ( const QSslError &error : errors ) 106 : 0 : errorMessages << error.errorString(); 107 : : 108 : 0 : error( errorMessages ); 109 : 0 : } 110 : 0 : } 111 : : #endif 112 : : 113 : : 114 : 0 : void QgsFileDownloader::error( const QStringList &errorMessages ) 115 : : { 116 : 0 : for ( const QString &error : errorMessages ) 117 : 0 : mErrors << error; 118 : : 119 : 0 : if ( mReply ) 120 : 0 : mReply->abort(); 121 : 0 : emit downloadError( mErrors ); 122 : 0 : } 123 : 0 : 124 : 0 : void QgsFileDownloader::error( const QString &errorMessage ) 125 : : { 126 : 0 : error( QStringList() << errorMessage ); 127 : 0 : } 128 : : 129 : 0 : void QgsFileDownloader::onReadyRead() 130 : : { 131 : : Q_ASSERT( mReply ); 132 : 0 : if ( mFile.fileName().isEmpty() ) 133 : : { 134 : 0 : error( tr( "No output filename specified" ) ); 135 : 0 : onFinished(); 136 : 0 : } 137 : 0 : else if ( ! mFile.isOpen() && ! mFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) 138 : : { 139 : 0 : error( tr( "Cannot open output file: %1" ).arg( mFile.fileName() ) ); 140 : 0 : onFinished(); 141 : 0 : } 142 : : else 143 : : { 144 : 0 : QByteArray data = mReply->readAll(); 145 : 0 : mFile.write( data ); 146 : 0 : } 147 : 0 : } 148 : : 149 : 0 : void QgsFileDownloader::onFinished() 150 : : { 151 : : // when canceled 152 : 0 : if ( ! mErrors.isEmpty() || mDownloadCanceled ) 153 : : { 154 : 0 : if ( mFile.isOpen() ) 155 : 0 : mFile.close(); 156 : 0 : if ( mFile.exists() ) 157 : 0 : mFile.remove(); 158 : 0 : } 159 : : else 160 : : { 161 : : // download finished normally 162 : 0 : if ( mFile.isOpen() ) 163 : : { 164 : 0 : mFile.flush(); 165 : 0 : mFile.close(); 166 : 0 : } 167 : : 168 : : // get redirection url 169 : 0 : QVariant redirectionTarget = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute ); 170 : 0 : if ( mReply->error() ) 171 : : { 172 : 0 : mFile.remove(); 173 : 0 : error( tr( "Download failed: %1" ).arg( mReply->errorString() ) ); 174 : 0 : } 175 : 0 : else if ( !redirectionTarget.isNull() ) 176 : : { 177 : 0 : QUrl newUrl = mUrl.resolved( redirectionTarget.toUrl() ); 178 : 0 : mUrl = newUrl; 179 : 0 : mReply->deleteLater(); 180 : 0 : if ( !mFile.open( QIODevice::WriteOnly ) ) 181 : : { 182 : 0 : mFile.remove(); 183 : 0 : error( tr( "Cannot open output file: %1" ).arg( mFile.fileName() ) ); 184 : 0 : } 185 : : else 186 : : { 187 : 0 : mFile.resize( 0 ); 188 : 0 : mFile.close(); 189 : 0 : startDownload(); 190 : : } 191 : : return; 192 : 0 : } 193 : : else 194 : : { 195 : 0 : emit downloadCompleted( mReply->url() ); 196 : : } 197 : 0 : } 198 : 0 : emit downloadExited(); 199 : 0 : this->deleteLater(); 200 : 0 : } 201 : : 202 : : 203 : 0 : void QgsFileDownloader::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal ) 204 : : { 205 : 0 : if ( mDownloadCanceled ) 206 : : { 207 : 0 : return; 208 : : } 209 : 0 : emit downloadProgress( bytesReceived, bytesTotal ); 210 : 0 : } 211 : :