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