24 #include <QNetworkRequest>
25 #include <QNetworkReply>
27 #include <QWaitCondition>
28 #include <QNetworkCacheMetaData>
29 #include <QAuthenticator>
42 void QgsBlockingNetworkRequest::requestTimedOut( QNetworkReply *reply )
44 if (
reply == mReply )
60 return doRequest( Get, request, forceRefresh, feedback );
65 QByteArray ldata( data );
66 QBuffer buffer( &ldata );
67 buffer.open( QIODevice::ReadOnly );
68 return post( request, &buffer, forceRefresh, feedback );
74 return doRequest( Post, request, forceRefresh, feedback );
79 return doRequest( Head, request, forceRefresh, feedback );
84 QByteArray ldata( data );
85 QBuffer buffer( &ldata );
86 buffer.open( QIODevice::ReadOnly );
87 return put( request, &buffer, feedback );
93 return doRequest( Put, request,
true, feedback );
98 return doRequest( Delete, request,
true, feedback );
101 void QgsBlockingNetworkRequest::sendRequestToNetworkAccessManager(
const QNetworkRequest &request )
130 mFeedback = feedback;
135 mGotNonEmptyResponse =
false;
137 mErrorMessage.clear();
139 mForceRefresh = forceRefresh;
140 mReplyContent.
clear();
145 mErrorMessage = errorMessageFailedAuth();
150 QgsDebugMsgLevel( QStringLiteral(
"Calling: %1" ).arg( request.url().toString() ), 2 );
152 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, forceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
153 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
155 QWaitCondition authRequestBufferNotEmpty;
156 QMutex waitConditionMutex;
158 bool threadFinished =
false;
159 bool success =
false;
161 const bool requestMadeFromMainThread = QThread::currentThread() == QApplication::instance()->thread();
166 const std::function<void()> downloaderFunction = [
this, request, &waitConditionMutex, &authRequestBufferNotEmpty, &threadFinished, &success, requestMadeFromMainThread ]()
176 sendRequestToNetworkAccessManager( request );
184 mErrorMessage = errorMessageFailedAuth();
186 if ( requestMadeFromMainThread )
187 authRequestBufferNotEmpty.wakeAll();
195 connect( mReply, &QNetworkReply::finished,
this, &QgsBlockingNetworkRequest::replyFinished, Qt::DirectConnection );
196 connect( mReply, &QNetworkReply::downloadProgress,
this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
197 connect( mReply, &QNetworkReply::uploadProgress,
this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
199 auto resumeMainThread = [&waitConditionMutex, &authRequestBufferNotEmpty ]()
203 waitConditionMutex.lock();
204 authRequestBufferNotEmpty.wakeAll();
205 waitConditionMutex.unlock();
210 if ( requestMadeFromMainThread )
223 connect( qApp, &QCoreApplication::aboutToQuit, &loop, &QEventLoop::quit, Qt::DirectConnection );
228 if ( requestMadeFromMainThread )
230 waitConditionMutex.lock();
231 threadFinished =
true;
232 authRequestBufferNotEmpty.wakeAll();
233 waitConditionMutex.unlock();
237 if ( requestMadeFromMainThread )
239 std::unique_ptr<DownloaderThread> downloaderThread = std::make_unique<DownloaderThread>( downloaderFunction );
240 downloaderThread->start();
244 waitConditionMutex.lock();
245 if ( threadFinished )
247 waitConditionMutex.unlock();
250 authRequestBufferNotEmpty.wait( &waitConditionMutex );
256 if ( !threadFinished )
258 waitConditionMutex.unlock();
260 QgsApplication::processEvents();
266 waitConditionMutex.unlock();
270 downloaderThread->wait();
274 downloaderFunction();
284 mReply->deleteLater();
289 void QgsBlockingNetworkRequest::replyProgress( qint64 bytesReceived, qint64 bytesTotal )
291 QgsDebugMsgLevel( QStringLiteral(
"%1 of %2 bytes downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QStringLiteral(
"unknown number of" ) : QString::number( bytesTotal ) ), 2 );
293 if ( bytesReceived != 0 )
294 mGotNonEmptyResponse =
true;
296 if ( !mIsAborted && mReply && ( !mFeedback || !mFeedback->isCanceled() ) )
298 if ( mReply->error() == QNetworkReply::NoError )
300 const QVariant redirect = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
301 if ( !redirect.isNull() )
309 if ( mMethod == Put || mMethod == Post )
315 void QgsBlockingNetworkRequest::replyFinished()
317 if ( !mIsAborted && mReply )
320 if ( mReply->error() == QNetworkReply::NoError && ( !mFeedback || !mFeedback->isCanceled() ) )
323 const QVariant redirect = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
324 if ( !redirect.isNull() )
328 const QUrl &toUrl = redirect.toUrl();
330 if ( toUrl == mReply->url() )
332 mErrorMessage = tr(
"Redirect loop detected: %1" ).arg( toUrl.toString() );
334 mReplyContent.
clear();
338 QNetworkRequest request( toUrl );
342 mReplyContent.
clear();
343 mErrorMessage = errorMessageFailedAuth();
353 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache );
354 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
356 mReply->deleteLater();
359 QgsDebugMsgLevel( QStringLiteral(
"redirected: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ), 2 );
361 sendRequestToNetworkAccessManager( request );
368 mReplyContent.
clear();
369 mErrorMessage = errorMessageFailedAuth();
379 connect( mReply, &QNetworkReply::finished,
this, &QgsBlockingNetworkRequest::replyFinished, Qt::DirectConnection );
380 connect( mReply, &QNetworkReply::downloadProgress,
this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
381 connect( mReply, &QNetworkReply::uploadProgress,
this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
391 QNetworkCacheMetaData cmd = nam->cache()->metaData( mReply->request().url() );
393 QNetworkCacheMetaData::RawHeaderList hl;
394 const auto constRawHeaders = cmd.rawHeaders();
395 for (
const QNetworkCacheMetaData::RawHeader &h : constRawHeaders )
397 if ( h.first !=
"Cache-Control" )
400 cmd.setRawHeaders( hl );
402 QgsDebugMsgLevel( QStringLiteral(
"expirationDate:%1" ).arg( cmd.expirationDate().toString() ), 2 );
403 if ( cmd.expirationDate().isNull() )
405 cmd.setExpirationDate( QDateTime::currentDateTime().addSecs( mExpirationSec ) );
408 nam->cache()->updateMetaData( cmd );
416 const bool fromCache = mReply->attribute( QNetworkRequest::SourceIsFromCacheAttribute ).toBool();
417 QgsDebugMsgLevel( QStringLiteral(
"Reply was cached: %1" ).arg( fromCache ), 2 );
421 const QByteArray content = mReply->readAll();
422 if ( content.isEmpty() && !mGotNonEmptyResponse && mMethod == Get )
424 mErrorMessage = tr(
"empty response: %1" ).arg( mReply->errorString() );
433 if ( mReply->error() != QNetworkReply::OperationCanceledError )
435 mErrorMessage = mReply->errorString();
440 mReplyContent.
setContent( mReply->readAll() );
448 mReply->deleteLater();
458 QString QgsBlockingNetworkRequest::errorMessageFailedAuth()
460 return tr(
"network request update failed for authentication config" );