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();
 
  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" );
 
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
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,...
void downloadProgress(qint64, qint64)
Emitted when when data arrives during a request.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
QgsBlockingNetworkRequest()
Constructor for QgsBlockingNetworkRequest.
ErrorCode put(QNetworkRequest &request, QIODevice *data, QgsFeedback *feedback=nullptr)
Performs a "put" operation on the specified request, using the given data.
~QgsBlockingNetworkRequest() override
ErrorCode head(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "head" operation on the specified request.
void abort()
Aborts the network request immediately.
Q_DECL_DEPRECATED void downloadFinished()
Emitted once a request has finished downloading.
ErrorCode post(QNetworkRequest &request, QIODevice *data, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "post" operation on the specified request, using the given data.
ErrorCode deleteResource(QNetworkRequest &request, QgsFeedback *feedback=nullptr)
Performs a "delete" operation on the specified request.
void finished()
Emitted once a request has finished.
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
QString authCfg() const
Returns the authentication config id which will be used during the request.
void uploadProgress(qint64, qint64)
Emitted when when data are sent during a request.
@ NetworkError
A network error occurred.
@ ServerExceptionError
An exception was raised by the server.
@ NoError
No error was encountered.
@ TimeoutError
Timeout was reached before a reply was received.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get() or post() request has been made.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
void canceled()
Internal routines can connect to this signal if they use event loop.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
network access manager for QGIS
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
void requestTimedOut(QgsNetworkRequestParameters request)
Emitted when a network request has timed out.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
void setContent(const QByteArray &content)
Sets the reply content.
void clear()
Clears the reply, resetting it back to a default, empty reply.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
#define QgsDebugMsgLevel(str, level)