QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgsnetworkcontentfetcherregistry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsnetworkcontentfetcherregistry.cpp
3 -------------------
4 begin : April, 2018
5 copyright : (C) 2018 by Denis Rouzaud
7
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
20
21#include "qgsapplication.h"
22
23#include <QDir>
24#include <QFileInfo>
25#include <QMimeDatabase>
26#include <QMimeType>
27#include <QString>
28#include <QUrl>
29
30#include "moc_qgsnetworkcontentfetcherregistry.cpp"
31
32using namespace Qt::StringLiterals;
33
35{
36 QMap<QString, QgsFetchedContent *>::const_iterator it = mFileRegistry.constBegin();
37 for ( ; it != mFileRegistry.constEnd(); ++it )
38 {
39 delete it.value();
40 }
41 mFileRegistry.clear();
42}
43
44QgsFetchedContent *QgsNetworkContentFetcherRegistry::fetch( const QString &url, const Qgis::ActionStart fetchingMode, const QString &authConfig, const QgsHttpHeaders &headers )
45{
46
47 if ( mFileRegistry.contains( url ) )
48 {
49 return mFileRegistry.value( url );
50 }
51
52 QgsFetchedContent *content = new QgsFetchedContent( url, nullptr, QgsFetchedContent::NotStarted, authConfig, headers );
53
54 mFileRegistry.insert( url, content );
55
56 if ( fetchingMode == Qgis::ActionStart::Immediate )
57 content->download();
58
59
60 return content;
61}
62
63QFile *QgsNetworkContentFetcherRegistry::localFile( const QString &filePathOrUrl )
64{
65 QFile *file = nullptr;
66 const QString path = filePathOrUrl;
67
68 if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
69 {
70 if ( mFileRegistry.contains( path ) )
71 {
72 const QgsFetchedContent *content = mFileRegistry.value( path );
73 if ( content && content->status() == QgsFetchedContent::Finished && content->file() )
74 {
75 file = content->file();
76 }
77 else
78 {
79 // if the file is not downloaded yet or has failed, return nullptr
80 }
81 }
82 else
83 {
84 // if registry doesn't contain the URL, return nullptr
85 }
86 }
87 else
88 {
89 file = new QFile( filePathOrUrl );
90 }
91 return file;
92}
93
94QString QgsNetworkContentFetcherRegistry::localPath( const QString &filePathOrUrl )
95{
96 QString path = filePathOrUrl;
97
98 if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
99 {
100 auto it = mFileRegistry.constFind( path );
101 if ( it != mFileRegistry.constEnd() )
102 {
103 const QgsFetchedContent *content = it.value();
104 if ( content->status() == QgsFetchedContent::Finished && !content->filePath().isEmpty() )
105 {
106 path = content->filePath();
107 }
108 else
109 {
110 // if the file is not downloaded yet or has failed, return empty string
111 path = QString();
112 }
113 }
114 else
115 {
116 // if registry doesn't contain the URL, keep path unchanged
117 }
118 }
119 return path;
120}
121
122
123
124
125void QgsFetchedContent::download( bool redownload )
126{
127
128 if ( redownload && status() == QgsFetchedContent::Downloading )
129 {
130 {
131 if ( mFetchingTask )
132 disconnect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
133 }
134 cancel();
135 }
136 if ( redownload ||
139 {
140 mFetchingTask = new QgsNetworkContentFetcherTask( mUrl, mAuthConfig, QgsTask::CanCancel, QString(), mHeaders );
141 // use taskCompleted which is main thread rather than fetched signal in worker thread
142 connect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
143 connect( mFetchingTask, &QgsNetworkContentFetcherTask::taskTerminated, this, &QgsFetchedContent::taskCompleted );
145 QgsApplication::taskManager()->addTask( mFetchingTask );
147 }
148
149}
150
152{
153 if ( mFetchingTask && mFetchingTask->canCancel() )
154 {
155 mFetchingTask->cancel();
157 }
158}
159
160
161void QgsFetchedContent::taskCompleted()
162{
163 if ( !mFetchingTask || !mFetchingTask->reply() )
164 {
165 // if no reply, it has been canceled
167 mError = QNetworkReply::OperationCanceledError;
168 mFilePath = QString();
169 }
170 else
171 {
172 QNetworkReply *reply = mFetchingTask->reply();
173 if ( reply->error() == QNetworkReply::NoError )
174 {
175
176 // keep or guess extension, it can be useful when guessing file content
177 // (when loading this file in a Qt WebView for instance)
178
179 // extension from file name
180 QString extension = QFileInfo( reply->request().url().fileName() ).completeSuffix();
181
182 // extension from contentType header if not found from file name
183 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
184 if ( extension.isEmpty() && !contentType.isEmpty() )
185 {
186 const QList<QMimeType> mimeTypes = QMimeDatabase().allMimeTypes();
187 auto it = std::find_if( mimeTypes.constBegin(), mimeTypes.constEnd(), [contentType]( QMimeType mimeType )
188 {
189 return mimeType.name() == contentType;
190 } );
191 if ( it != mimeTypes.constEnd() )
192 {
193 extension = ( *it ).preferredSuffix();
194 }
195 }
196
197 mFile = std::make_unique<QTemporaryFile>( extension.isEmpty() ? QString( "XXXXXX" ) :
198 QString( "%1/XXXXXX.%2" ).arg( QDir::tempPath(), extension ) );
199 if ( !mFile->open() )
200 {
201 QgsDebugError( u"Can't open temporary file %1"_s.arg( mFile->fileName() ) );
203 return;
204 }
205 mFile->write( reply->readAll() );
206 // Qt docs notes that on some system if fileName is not called before close, file might get deleted
207 mFilePath = mFile->fileName();
208 mFile->close();
210 }
211 else
212 {
214 mError = reply->error();
215 mFilePath = QString();
216 }
217 }
218
219 emit fetched();
220}
ActionStart
Enum to determine when an operation would begin.
Definition qgis.h:1162
@ Immediate
Action will start immediately.
Definition qgis.h:1164
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
Holds information about fetched network content.
QFile * file() const
Returns a pointer to the local file, or nullptr if the file is not accessible yet.
ContentStatus status() const
Returns the status of the download.
void download(bool redownload=false)
Start the download.
const QString filePath() const
Returns the path to the local file, an empty string if the file is not accessible yet.
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.
@ NotStarted
No download started for such URL.
@ Downloading
Currently downloading.
void fetched()
Emitted when the file is fetched and accessible.
void cancel()
Cancel the download operation.
Implements simple HTTP header management.
QString localPath(const QString &filePathOrUrl)
Returns the path to a local file or to a temporary file previously fetched by the registry.
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.
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry.
Handles HTTP network content fetching in a background task.
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...
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
@ CanCancel
Task can be canceled.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
#define QgsDebugError(str)
Definition qgslogger.h:59