QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
22#include "qgsapplication.h"
23#include "qgsfeedback.h"
24
25#include <QFile>
26#include <QPointer>
27#include <QFileInfo>
28#include <QCryptographicHash>
29
31
32QgsHttpExternalStorageStoreTask::QgsHttpExternalStorageStoreTask( const QUrl &url, const QString &filePath, const QString &authCfg )
33 : QgsTask( tr( "Storing %1" ).arg( QFileInfo( filePath ).baseName() ) )
34 , mUrl( url )
35 , mFilePath( filePath )
36 , mAuthCfg( authCfg )
37 , mFeedback( new QgsFeedback( this ) )
38{
39}
40
41bool QgsHttpExternalStorageStoreTask::run()
42{
44 request.setAuthCfg( mAuthCfg );
45
46 QNetworkRequest req( mUrl );
47 QgsSetRequestInitiatorClass( req, QStringLiteral( "QgsHttpExternalStorageStoreTask" ) );
48
49 QFile *f = new QFile( mFilePath );
50 f->open( QIODevice::ReadOnly );
51
52 if ( mPrepareRequestHandler )
53 mPrepareRequestHandler( req, f );
54
55 connect( &request, &QgsBlockingNetworkRequest::uploadProgress, this, [this]( qint64 bytesReceived, qint64 bytesTotal )
56 {
57 if ( !isCanceled() && bytesTotal > 0 )
58 {
59 const int progress = ( bytesReceived * 100 ) / bytesTotal;
60 setProgress( progress );
61 }
62 } );
63
64 QgsBlockingNetworkRequest::ErrorCode err = request.put( req, f, mFeedback.get() );
65
67 {
68 mErrorString = request.errorMessage();
69 }
70
71 return !isCanceled() && err == QgsBlockingNetworkRequest::NoError;
72}
73
74void QgsHttpExternalStorageStoreTask::cancel()
75{
76 mFeedback->cancel();
78}
79
80QString QgsHttpExternalStorageStoreTask::errorString() const
81{
82 return mErrorString;
83}
84
85void QgsHttpExternalStorageStoreTask::setPrepareRequestHandler( std::function< void( QNetworkRequest &request, QFile *f ) > handler )
86{
87 mPrepareRequestHandler = handler;
88}
89
90QgsHttpExternalStorageStoredContent::QgsHttpExternalStorageStoredContent( const QString &filePath, const QString &url, const QString &authcfg )
91{
92 QString storageUrl = url;
93 if ( storageUrl.endsWith( "/" ) )
94 storageUrl.append( QFileInfo( filePath ).fileName() );
95
96 mUploadTask = new QgsHttpExternalStorageStoreTask( storageUrl, filePath, authcfg );
97
98 connect( mUploadTask, &QgsTask::taskCompleted, this, [this, storageUrl]
99 {
100 mUrl = storageUrl;
102 emit stored();
103 } );
104
105 connect( mUploadTask, &QgsTask::taskTerminated, this, [this]
106 {
107 reportError( mUploadTask->errorString() );
108 } );
109
110 connect( mUploadTask, &QgsTask::progressChanged, this, [this]( double progress )
111 {
112 emit progressChanged( progress );
113 } );
114}
115
116void QgsHttpExternalStorageStoredContent::store()
117{
118 setStatus( Qgis::ContentStatus::Running );
119 QgsApplication::taskManager()->addTask( mUploadTask );
120}
121
122
123void QgsHttpExternalStorageStoredContent::cancel()
124{
125 if ( !mUploadTask )
126 return;
127
128 disconnect( mUploadTask, &QgsTask::taskTerminated, this, nullptr );
129 connect( mUploadTask, &QgsTask::taskTerminated, this, [this]
130 {
132 emit canceled();
133 } );
134
135 mUploadTask->cancel();
136}
137
138QString QgsHttpExternalStorageStoredContent::url() const
139{
140 return mUrl;
141}
142
143void QgsHttpExternalStorageStoredContent::setPrepareRequestHandler( std::function< void( QNetworkRequest &request, QFile *f ) > handler )
144{
145 mUploadTask->setPrepareRequestHandler( handler );
146}
147
148
149QgsHttpExternalStorageFetchedContent::QgsHttpExternalStorageFetchedContent( QgsFetchedContent *fetchedContent )
150 : mFetchedContent( fetchedContent )
151{
152 connect( mFetchedContent, &QgsFetchedContent::fetched, this, &QgsHttpExternalStorageFetchedContent::onFetched );
153 connect( mFetchedContent, &QgsFetchedContent::errorOccurred, this, [this]( QNetworkReply::NetworkError code, const QString & errorMsg )
154 {
155 Q_UNUSED( code );
156 reportError( errorMsg );
157 } );
158}
159
160void QgsHttpExternalStorageFetchedContent::fetch()
161{
162 if ( !mFetchedContent )
163 return;
164
165 setStatus( Qgis::ContentStatus::Running );
166 mFetchedContent->download();
167
168 // could be already fetched/cached
169 if ( mFetchedContent->status() == QgsFetchedContent::Finished )
170 {
172 emit fetched();
173 }
174}
175
176QString QgsHttpExternalStorageFetchedContent::filePath() const
177{
178 return mFetchedContent ? mFetchedContent->filePath() : QString();
179}
180
181void QgsHttpExternalStorageFetchedContent::onFetched()
182{
183 if ( !mFetchedContent )
184 return;
185
186 if ( mFetchedContent->status() == QgsFetchedContent::Finished )
187 {
189 emit fetched();
190 }
191}
192
193void QgsHttpExternalStorageFetchedContent::cancel()
194{
195 mFetchedContent->cancel();
196}
197
198
199// WEB DAV PROTOCOL
200
201QString QgsWebDavExternalStorage::type() const
202{
203 return QStringLiteral( "WebDAV" );
204};
205
206QString QgsWebDavExternalStorage::displayName() const
207{
208 return QObject::tr( "WebDAV Storage" );
209};
210
211QgsExternalStorageStoredContent *QgsWebDavExternalStorage::doStore( const QString &filePath, const QString &url, const QString &authcfg ) const
212{
213 return new QgsHttpExternalStorageStoredContent( filePath, url, authcfg );
214};
215
216QgsExternalStorageFetchedContent *QgsWebDavExternalStorage::doFetch( const QString &url, const QString &authConfig ) const
217{
219
220 return new QgsHttpExternalStorageFetchedContent( fetchedContent );
221}
222
223
224// AWS S3 PROTOCOL
225
226QString QgsAwsS3ExternalStorage::type() const
227{
228 return QStringLiteral( "AWSS3" );
229};
230
231QString QgsAwsS3ExternalStorage::displayName() const
232{
233 return QObject::tr( "AWS S3" );
234};
235
236QgsExternalStorageStoredContent *QgsAwsS3ExternalStorage::doStore( const QString &filePath, const QString &url, const QString &authcfg ) const
237{
238 std::unique_ptr<QgsHttpExternalStorageStoredContent> storedContent = std::make_unique<QgsHttpExternalStorageStoredContent>( filePath, url, authcfg );
239 storedContent->setPrepareRequestHandler( []( QNetworkRequest & request, QFile * f )
240 {
241 QCryptographicHash payloadCrypto( QCryptographicHash::Sha256 );
242 payloadCrypto.addData( f );
243 QByteArray payloadHash = payloadCrypto.result().toHex();
244 f->seek( 0 );
245 request.setRawHeader( QByteArray( "X-Amz-Content-SHA256" ), payloadHash );
246 } );
247
248 return storedContent.release();
249};
250
251QgsExternalStorageFetchedContent *QgsAwsS3ExternalStorage::doFetch( const QString &url, const QString &authConfig ) const
252{
254
255 return new QgsHttpExternalStorageFetchedContent( fetchedContent );
256}
@ Canceled
Content fetching/storing has been canceled.
@ Running
Content fetching/storing is in progress.
@ Finished
Content fetching/storing is finished and successful.
@ Deferred
Do not start immediately the action.
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:44
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)