24 #include <QNetworkRequest> 25 #include <QNetworkReply> 27 #include <QWaitCondition> 28 #include <QNetworkCacheMetaData> 29 #include <QAuthenticator> 41 void QgsBlockingNetworkRequest::requestTimedOut( QNetworkReply *
reply )
43 if ( reply == mReply )
59 return doRequest( Get, request, forceRefresh, feedback );
65 return doRequest( Post, request, forceRefresh, feedback );
76 mGotNonEmptyResponse =
false;
78 mErrorMessage.clear();
80 mForceRefresh = forceRefresh;
81 mReplyContent.
clear();
86 mErrorMessage = errorMessageFailedAuth();
91 QgsDebugMsgLevel( QStringLiteral(
"Calling: %1" ).arg( request.url().toString() ), 2 );
93 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, forceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
94 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
96 QWaitCondition authRequestBufferNotEmpty;
97 QMutex waitConditionMutex;
99 bool threadFinished =
false;
100 bool success =
false;
102 const bool requestMadeFromMainThread = QThread::currentThread() == QApplication::instance()->thread();
107 std::function<void()> downloaderFunction = [
this, request, &waitConditionMutex, &authRequestBufferNotEmpty, &threadFinished, &success, requestMadeFromMainThread ]()
134 mErrorMessage = errorMessageFailedAuth();
136 if ( requestMadeFromMainThread )
137 authRequestBufferNotEmpty.wakeAll();
145 connect( mReply, &QNetworkReply::finished,
this, &QgsBlockingNetworkRequest::replyFinished, Qt::DirectConnection );
146 connect( mReply, &QNetworkReply::downloadProgress,
this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
148 auto resumeMainThread = [&waitConditionMutex, &authRequestBufferNotEmpty ]()
152 waitConditionMutex.lock();
153 authRequestBufferNotEmpty.wakeAll();
154 waitConditionMutex.unlock();
159 if ( requestMadeFromMainThread )
173 if ( requestMadeFromMainThread )
175 waitConditionMutex.lock();
176 threadFinished =
true;
177 authRequestBufferNotEmpty.wakeAll();
178 waitConditionMutex.unlock();
182 if ( requestMadeFromMainThread )
184 std::unique_ptr<DownloaderThread> downloaderThread = qgis::make_unique<DownloaderThread>( downloaderFunction );
185 downloaderThread->start();
189 waitConditionMutex.lock();
190 if ( threadFinished )
192 waitConditionMutex.unlock();
195 authRequestBufferNotEmpty.wait( &waitConditionMutex );
201 if ( !threadFinished )
203 waitConditionMutex.unlock();
211 waitConditionMutex.unlock();
215 downloaderThread->wait();
219 downloaderFunction();
229 mReply->deleteLater();
234 void QgsBlockingNetworkRequest::replyProgress( qint64 bytesReceived, qint64 bytesTotal )
236 QgsDebugMsgLevel( QStringLiteral(
"%1 of %2 bytes downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QStringLiteral(
"unknown number of" ) : QString::number( bytesTotal ) ), 2 );
238 if ( bytesReceived != 0 )
239 mGotNonEmptyResponse =
true;
241 if ( !mIsAborted && mReply && ( !mFeedback || !mFeedback->isCanceled() ) )
243 if ( mReply->error() == QNetworkReply::NoError )
245 QVariant redirect = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
246 if ( !redirect.isNull() )
257 void QgsBlockingNetworkRequest::replyFinished()
259 if ( !mIsAborted && mReply )
261 if ( mReply->error() == QNetworkReply::NoError && ( !mFeedback || !mFeedback->isCanceled() ) )
264 QVariant redirect = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
265 if ( !redirect.isNull() )
269 const QUrl &toUrl = redirect.toUrl();
271 if ( toUrl == mReply->url() )
273 mErrorMessage = tr(
"Redirect loop detected: %1" ).arg( toUrl.toString() );
275 mReplyContent.
clear();
279 QNetworkRequest request( toUrl );
283 mReplyContent.
clear();
284 mErrorMessage = errorMessageFailedAuth();
291 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
292 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
294 mReply->deleteLater();
297 QgsDebugMsgLevel( QStringLiteral(
"redirected: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ), 2 );
314 mReplyContent.
clear();
315 mErrorMessage = errorMessageFailedAuth();
322 connect( mReply, &QNetworkReply::finished,
this, &QgsBlockingNetworkRequest::replyFinished, Qt::DirectConnection );
323 connect( mReply, &QNetworkReply::downloadProgress,
this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
333 QNetworkCacheMetaData cmd = nam->cache()->metaData( mReply->request().url() );
335 QNetworkCacheMetaData::RawHeaderList hl;
336 const auto constRawHeaders = cmd.rawHeaders();
337 for (
const QNetworkCacheMetaData::RawHeader &h : constRawHeaders )
339 if ( h.first !=
"Cache-Control" )
342 cmd.setRawHeaders( hl );
344 QgsDebugMsgLevel( QStringLiteral(
"expirationDate:%1" ).arg( cmd.expirationDate().toString() ), 2 );
345 if ( cmd.expirationDate().isNull() )
347 cmd.setExpirationDate( QDateTime::currentDateTime().addSecs( mExpirationSec ) );
350 nam->cache()->updateMetaData( cmd );
358 bool fromCache = mReply->attribute( QNetworkRequest::SourceIsFromCacheAttribute ).toBool();
359 QgsDebugMsgLevel( QStringLiteral(
"Reply was cached: %1" ).arg( fromCache ), 2 );
363 const QByteArray content = mReply->readAll();
364 if ( content.isEmpty() && !mGotNonEmptyResponse )
366 mErrorMessage = tr(
"empty response: %1" ).arg( mReply->errorString() );
375 if ( mReply->error() != QNetworkReply::OperationCanceledError )
377 mErrorMessage = mReply->errorString();
389 mReply->deleteLater();
396 QString QgsBlockingNetworkRequest::errorMessageFailedAuth()
398 return tr(
"network request update failed for authentication config" );
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
void requestTimedOut(QgsNetworkRequestParameters request)
Emitted when a network request has timed out.
~QgsBlockingNetworkRequest() override
void canceled()
Internal routines can connect to this signal if they use event loop.
void abort()
Aborts the network request immediately.
Timeout was reached before a reply was received.
QString authCfg() const
Returns the authentication config id which will be used during the request.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
QgsBlockingNetworkRequest()
Constructor for QgsBlockingNetworkRequest.
Base class for feedback objects to be used for cancellation of something running in a worker thread...
ErrorCode post(QNetworkRequest &request, const QByteArray &data, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "post" operation on the specified request, using the given data.
#define QgsDebugMsgLevel(str, level)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
void downloadProgress(qint64, qint64)
Emitted when when data arrives during a request.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get() or post() request has been made...
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
void setContent(const QByteArray &content)
Sets the reply content.
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
void downloadFinished()
Emitted once a request has finished downloading.
void clear()
Clears the reply, resetting it back to a default, empty reply.
A network error occurred.
No error was encountered.
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...
network access manager for QGISThis class implements the QGIS network access manager.
An exception was raised by the server.