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