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