QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsfiledownloader.cpp
Go to the documentation of this file.
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"
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 QgsFileDownloader::QgsFileDownloader( const QUrl &url, const QString &outputFileName, const QString &authcfg, bool delayStart )
29  : mUrl( url )
30  , mDownloadCanceled( false )
31 {
32  mFile.setFileName( outputFileName );
33  mAuthCfg = authcfg;
34  if ( !delayStart )
35  startDownload();
36 }
37 
38 
40 {
41  if ( mReply )
42  {
43  mReply->abort();
44  mReply->deleteLater();
45  }
46 }
47 
48 
50 {
52 
53  QNetworkRequest request( mUrl );
54  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsFileDownloader" ) );
55  if ( !mAuthCfg.isEmpty() )
56  {
57  QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg );
58  }
59 
60  if ( mReply )
61  {
62  disconnect( mReply, &QNetworkReply::readyRead, this, &QgsFileDownloader::onReadyRead );
63  disconnect( mReply, &QNetworkReply::finished, this, &QgsFileDownloader::onFinished );
64  disconnect( mReply, &QNetworkReply::downloadProgress, this, &QgsFileDownloader::onDownloadProgress );
65  mReply->abort();
66  mReply->deleteLater();
67  }
68 
69  mReply = nam->get( request );
70  if ( !mAuthCfg.isEmpty() )
71  {
72  QgsApplication::authManager()->updateNetworkReply( mReply, mAuthCfg );
73  }
74 
75  connect( mReply, &QNetworkReply::readyRead, this, &QgsFileDownloader::onReadyRead );
76  connect( mReply, &QNetworkReply::finished, this, &QgsFileDownloader::onFinished );
77  connect( mReply, &QNetworkReply::downloadProgress, this, &QgsFileDownloader::onDownloadProgress );
78  connect( nam, qgis::overload< QNetworkReply *>::of( &QgsNetworkAccessManager::requestTimedOut ), this, &QgsFileDownloader::onRequestTimedOut, Qt::UniqueConnection );
79 #ifndef QT_NO_SSL
80  connect( nam, &QgsNetworkAccessManager::sslErrors, this, &QgsFileDownloader::onSslErrors, Qt::UniqueConnection );
81 #endif
82 }
83 
85 {
86  mDownloadCanceled = true;
87  emit downloadCanceled();
88  onFinished();
89 }
90 
91 void QgsFileDownloader::onRequestTimedOut( QNetworkReply *reply )
92 {
93  if ( reply == mReply )
94  error( tr( "Network request %1 timed out" ).arg( mUrl.toString() ) );
95 }
96 
97 #ifndef QT_NO_SSL
98 void QgsFileDownloader::onSslErrors( QNetworkReply *reply, const QList<QSslError> &errors )
99 {
100  if ( reply == mReply )
101  {
102  QStringList errorMessages;
103  errorMessages.reserve( errors.size() + 1 );
104  errorMessages << QStringLiteral( "SSL Errors: " );
105  for ( auto end = errors.size(), i = 0; i != end; ++i )
106  {
107  errorMessages << errors[i].errorString();
108  }
109  error( errorMessages );
110  }
111 }
112 #endif
113 
114 
115 void QgsFileDownloader::error( const QStringList &errorMessages )
116 {
117  for ( auto end = errorMessages.size(), i = 0; i != end; ++i )
118  {
119  mErrors << errorMessages[i];
120  }
121  if ( mReply )
122  mReply->abort();
123  emit downloadError( mErrors );
124 }
125 
126 void QgsFileDownloader::error( const QString &errorMessage )
127 {
128  error( QStringList() << errorMessage );
129 }
130 
131 void QgsFileDownloader::onReadyRead()
132 {
133  Q_ASSERT( mReply );
134  if ( mFile.fileName().isEmpty() )
135  {
136  error( tr( "No output filename specified" ) );
137  onFinished();
138  }
139  else if ( ! mFile.isOpen() && ! mFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
140  {
141  error( tr( "Cannot open output file: %1" ).arg( mFile.fileName() ) );
142  onFinished();
143  }
144  else
145  {
146  QByteArray data = mReply->readAll();
147  mFile.write( data );
148  }
149 }
150 
151 void QgsFileDownloader::onFinished()
152 {
153  // when canceled
154  if ( ! mErrors.isEmpty() || mDownloadCanceled )
155  {
156  if ( mFile.isOpen() )
157  mFile.close();
158  if ( mFile.exists() )
159  mFile.remove();
160  }
161  else
162  {
163  // download finished normally
164  if ( mFile.isOpen() )
165  {
166  mFile.flush();
167  mFile.close();
168  }
169 
170  // get redirection url
171  QVariant redirectionTarget = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
172  if ( mReply->error() )
173  {
174  mFile.remove();
175  error( tr( "Download failed: %1" ).arg( mReply->errorString() ) );
176  }
177  else if ( !redirectionTarget.isNull() )
178  {
179  QUrl newUrl = mUrl.resolved( redirectionTarget.toUrl() );
180  mUrl = newUrl;
181  mReply->deleteLater();
182  if ( !mFile.open( QIODevice::WriteOnly ) )
183  {
184  mFile.remove();
185  error( tr( "Cannot open output file: %1" ).arg( mFile.fileName() ) );
186  }
187  else
188  {
189  mFile.resize( 0 );
190  mFile.close();
191  startDownload();
192  }
193  return;
194  }
195  else
196  {
197  emit downloadCompleted();
198  }
199  }
200  emit downloadExited();
201  this->deleteLater();
202 }
203 
204 
205 void QgsFileDownloader::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
206 {
207  if ( mDownloadCanceled )
208  {
209  return;
210  }
211  emit downloadProgress( bytesReceived, bytesTotal );
212 }
213 
QgsNetworkAccessManager::requestTimedOut
void requestTimedOut(QgsNetworkRequestParameters request)
Emitted when a network request has timed out.
QgsFileDownloader::startDownload
void startDownload()
Called to start the download.
Definition: qgsfiledownloader.cpp:49
QgsFileDownloader::downloadExited
void downloadExited()
Emitted always when the downloader exits.
qgsauthmanager.h
QgsAuthManager::updateNetworkReply
bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkReply with an authentication config (used to skip known SSL errors,...
Definition: qgsauthmanager.cpp:1465
QgsSetRequestInitiatorClass
#define QgsSetRequestInitiatorClass(request, _class)
Definition: qgsnetworkaccessmanager.h:41
QgsApplication::authManager
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
Definition: qgsapplication.cpp:1263
qgsapplication.h
QgsFileDownloader::~QgsFileDownloader
~QgsFileDownloader() override
Definition: qgsfiledownloader.cpp:39
qgsnetworkaccessmanager.h
QgsFileDownloader::downloadProgress
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
Emitted when data are ready to be processed.
QgsNetworkAccessManager
network access manager for QGIS
Definition: qgsnetworkaccessmanager.h:251
QgsNetworkAccessManager::instance
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Definition: qgsnetworkaccessmanager.cpp:121
QgsFileDownloader::downloadCanceled
void downloadCanceled()
Emitted when the download was canceled by the user.
QgsFileDownloader::downloadError
void downloadError(QStringList errorMessages)
Emitted when an error makes the download fail.
QgsAuthManager::updateNetworkRequest
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
Definition: qgsauthmanager.cpp:1440
QgsFileDownloader::QgsFileDownloader
QgsFileDownloader(const QUrl &url, const QString &outputFileName, const QString &authcfg=QString(), bool delayStart=false)
QgsFileDownloader.
Definition: qgsfiledownloader.cpp:28
QgsFileDownloader::downloadCompleted
void downloadCompleted()
Emitted when the download has completed successfully.
QgsFileDownloader::cancelDownload
void cancelDownload()
Call to abort the download and delete this object after the cancellation has been processed.
Definition: qgsfiledownloader.cpp:84
qgsfiledownloader.h