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