QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgshttpexternalstorage.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgswebdavexternalstorage.cpp
3 --------------------------------------
4 Date : March 2021
5 Copyright : (C) 2021 by Julien Cabieces
6 Email : julien dot cabieces at oslandia 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
17
21#include "qgsapplication.h"
22#include "qgsfeedback.h"
23
24#include <QFile>
25#include <QPointer>
26#include <QFileInfo>
27#include <QCryptographicHash>
28
30
31QgsHttpExternalStorageStoreTask::QgsHttpExternalStorageStoreTask( const QUrl &url, const QString &filePath, const QString &authCfg )
32 : QgsTask( tr( "Storing %1" ).arg( QFileInfo( filePath ).baseName() ) )
33 , mUrl( url )
34 , mFilePath( filePath )
35 , mAuthCfg( authCfg )
36 , mFeedback( new QgsFeedback( this ) )
37{
38}
39
40bool QgsHttpExternalStorageStoreTask::run()
41{
43 request.setAuthCfg( mAuthCfg );
44
45 QNetworkRequest req( mUrl );
46 QgsSetRequestInitiatorClass( req, QStringLiteral( "QgsHttpExternalStorageStoreTask" ) );
47
48 QFile *f = new QFile( mFilePath );
49 f->open( QIODevice::ReadOnly );
50
51 if ( mPrepareRequestHandler )
52 mPrepareRequestHandler( req, f );
53
54 connect( &request, &QgsBlockingNetworkRequest::uploadProgress, this, [ = ]( qint64 bytesReceived, qint64 bytesTotal )
55 {
56 if ( !isCanceled() && bytesTotal > 0 )
57 {
58 const int progress = ( bytesReceived * 100 ) / bytesTotal;
59 setProgress( progress );
60 }
61 } );
62
63 QgsBlockingNetworkRequest::ErrorCode err = request.put( req, f, mFeedback.get() );
64
66 {
67 mErrorString = request.errorMessage();
68 }
69
70 return !isCanceled() && err == QgsBlockingNetworkRequest::NoError;
71}
72
73void QgsHttpExternalStorageStoreTask::cancel()
74{
75 mFeedback->cancel();
77}
78
79QString QgsHttpExternalStorageStoreTask::errorString() const
80{
81 return mErrorString;
82}
83
84void QgsHttpExternalStorageStoreTask::setPrepareRequestHandler( std::function< void( QNetworkRequest &request, QFile *f ) > handler )
85{
86 mPrepareRequestHandler = handler;
87}
88
89QgsHttpExternalStorageStoredContent::QgsHttpExternalStorageStoredContent( const QString &filePath, const QString &url, const QString &authcfg )
90{
91 QString storageUrl = url;
92 if ( storageUrl.endsWith( "/" ) )
93 storageUrl.append( QFileInfo( filePath ).fileName() );
94
95 mUploadTask = new QgsHttpExternalStorageStoreTask( storageUrl, filePath, authcfg );
96
97 connect( mUploadTask, &QgsTask::taskCompleted, this, [ = ]
98 {
99 mUrl = storageUrl;
101 emit stored();
102 } );
103
104 connect( mUploadTask, &QgsTask::taskTerminated, this, [ = ]
105 {
106 reportError( mUploadTask->errorString() );
107 } );
108
109 connect( mUploadTask, &QgsTask::progressChanged, this, [ = ]( double progress )
110 {
111 emit progressChanged( progress );
112 } );
113}
114
115void QgsHttpExternalStorageStoredContent::store()
116{
117 setStatus( Qgis::ContentStatus::Running );
118 QgsApplication::taskManager()->addTask( mUploadTask );
119}
120
121
122void QgsHttpExternalStorageStoredContent::cancel()
123{
124 if ( !mUploadTask )
125 return;
126
127 disconnect( mUploadTask, &QgsTask::taskTerminated, this, nullptr );
128 connect( mUploadTask, &QgsTask::taskTerminated, this, [ = ]
129 {
131 emit canceled();
132 } );
133
134 mUploadTask->cancel();
135}
136
137QString QgsHttpExternalStorageStoredContent::url() const
138{
139 return mUrl;
140}
141
142void QgsHttpExternalStorageStoredContent::setPrepareRequestHandler( std::function< void( QNetworkRequest &request, QFile *f ) > handler )
143{
144 mUploadTask->setPrepareRequestHandler( handler );
145}
146
147
148QgsHttpExternalStorageFetchedContent::QgsHttpExternalStorageFetchedContent( QgsFetchedContent *fetchedContent )
149 : mFetchedContent( fetchedContent )
150{
151 connect( mFetchedContent, &QgsFetchedContent::fetched, this, &QgsHttpExternalStorageFetchedContent::onFetched );
152 connect( mFetchedContent, &QgsFetchedContent::errorOccurred, this, [ = ]( QNetworkReply::NetworkError code, const QString & errorMsg )
153 {
154 Q_UNUSED( code );
155 reportError( errorMsg );
156 } );
157}
158
159void QgsHttpExternalStorageFetchedContent::fetch()
160{
161 if ( !mFetchedContent )
162 return;
163
164 setStatus( Qgis::ContentStatus::Running );
165 mFetchedContent->download();
166
167 // could be already fetched/cached
168 if ( mFetchedContent->status() == QgsFetchedContent::Finished )
169 {
171 emit fetched();
172 }
173}
174
175QString QgsHttpExternalStorageFetchedContent::filePath() const
176{
177 return mFetchedContent ? mFetchedContent->filePath() : QString();
178}
179
180void QgsHttpExternalStorageFetchedContent::onFetched()
181{
182 if ( !mFetchedContent )
183 return;
184
185 if ( mFetchedContent->status() == QgsFetchedContent::Finished )
186 {
188 emit fetched();
189 }
190}
191
192void QgsHttpExternalStorageFetchedContent::cancel()
193{
194 mFetchedContent->cancel();
195}
196
197
198// WEB DAV PROTOCOL
199
200QString QgsWebDavExternalStorage::type() const
201{
202 return QStringLiteral( "WebDAV" );
203};
204
205QString QgsWebDavExternalStorage::displayName() const
206{
207 return QObject::tr( "WebDAV Storage" );
208};
209
210QgsExternalStorageStoredContent *QgsWebDavExternalStorage::doStore( const QString &filePath, const QString &url, const QString &authcfg ) const
211{
212 return new QgsHttpExternalStorageStoredContent( filePath, url, authcfg );
213};
214
215QgsExternalStorageFetchedContent *QgsWebDavExternalStorage::doFetch( const QString &url, const QString &authConfig ) const
216{
217 QgsFetchedContent *fetchedContent = QgsApplication::networkContentFetcherRegistry()->fetch( url, Qgis::ActionStart::Deferred, authConfig );
218
219 return new QgsHttpExternalStorageFetchedContent( fetchedContent );
220}
221
222
223// AWS S3 PROTOCOL
224
225QString QgsAwsS3ExternalStorage::type() const
226{
227 return QStringLiteral( "AWSS3" );
228};
229
230QString QgsAwsS3ExternalStorage::displayName() const
231{
232 return QObject::tr( "AWS S3" );
233};
234
235QgsExternalStorageStoredContent *QgsAwsS3ExternalStorage::doStore( const QString &filePath, const QString &url, const QString &authcfg ) const
236{
237 std::unique_ptr<QgsHttpExternalStorageStoredContent> storedContent = std::make_unique<QgsHttpExternalStorageStoredContent>( filePath, url, authcfg );
238 storedContent->setPrepareRequestHandler( []( QNetworkRequest & request, QFile * f )
239 {
240 QCryptographicHash payloadCrypto( QCryptographicHash::Sha256 );
241 payloadCrypto.addData( f );
242 QByteArray payloadHash = payloadCrypto.result().toHex();
243 f->seek( 0 );
244 request.setRawHeader( QByteArray( "X-Amz-Content-SHA256" ), payloadHash );
245 } );
246
247 return storedContent.release();
248};
249
250QgsExternalStorageFetchedContent *QgsAwsS3ExternalStorage::doFetch( const QString &url, const QString &authConfig ) const
251{
252 QgsFetchedContent *fetchedContent = QgsApplication::networkContentFetcherRegistry()->fetch( url, Qgis::ActionStart::Deferred, authConfig );
253
254 return new QgsHttpExternalStorageFetchedContent( fetchedContent );
255}
@ Canceled
Content fetching/storing has been canceled.
@ Running
Content fetching/storing is in progress.
@ Finished
Content fetching/storing is finished and successful.
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode put(QNetworkRequest &request, QIODevice *data, QgsFeedback *feedback=nullptr)
Performs a "put" operation on the specified request, using the given data.
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
void uploadProgress(qint64, qint64)
Emitted when when data are sent during a request.
@ NoError
No error was encountered.
Class for QgsExternalStorage fetched content.
Class for QgsExternalStorage stored content.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
FetchedContent holds useful information about a network content being fetched.
void errorOccurred(QNetworkReply::NetworkError code, const QString &errorMsg)
Emitted when an error with code error occurred while processing the request errorMsg is a textual des...
@ Finished
Download finished and successful.
void fetched()
Emitted when the file is fetched and accessible.
QgsFetchedContent * fetch(const QString &url, Qgis::ActionStart fetchingMode=Qgis::ActionStart::Deferred, const QString &authConfig=QString())
Initialize a download for the given URL.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Abstract base class for long running background tasks.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
virtual void cancel()
Notifies the task that it should terminate.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
#define QgsSetRequestInitiatorClass(request, _class)