|
24 | 24 | #include <QEventLoop> |
25 | 25 | #include <QNetworkCacheMetaData> |
26 | 26 | #include <QCryptographicHash> // just for testin file:// fake_qgis_http_endpoint hack |
| 27 | +#include <QFuture> |
| 28 | +#include <QtConcurrent> |
27 | 29 |
|
28 | 30 | const qint64 READ_BUFFER_SIZE_HINT = 1024 * 1024; |
29 | 31 |
|
@@ -126,26 +128,95 @@ bool QgsWfsRequest::sendGET( const QUrl &url, bool synchronous, bool forceRefres |
126 | 128 | request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); |
127 | 129 | } |
128 | 130 |
|
129 | | - mReply = QgsNetworkAccessManager::instance()->get( request ); |
130 | | - mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT ); |
131 | | - if ( !mUri.auth().setAuthorizationReply( mReply ) ) |
| 131 | + QWaitCondition waitCondition; |
| 132 | + QMutex waitConditionMutex; |
| 133 | + |
| 134 | + std::function<bool()> downloaderFunction = [ this, request, synchronous, &waitConditionMutex, &waitCondition ]() |
132 | 135 | { |
133 | | - mErrorCode = QgsWfsRequest::NetworkError; |
134 | | - mErrorMessage = errorMessageFailedAuth(); |
135 | | - QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); |
136 | | - return false; |
137 | | - } |
138 | | - connect( mReply, &QNetworkReply::finished, this, &QgsWfsRequest::replyFinished ); |
139 | | - connect( mReply, &QNetworkReply::downloadProgress, this, &QgsWfsRequest::replyProgress ); |
| 136 | + if ( QThread::currentThread() != QgsApplication::instance()->thread() ) |
| 137 | + QgsNetworkAccessManager::instance( Qt::DirectConnection ); |
140 | 138 |
|
141 | | - if ( !synchronous ) |
142 | | - return true; |
| 139 | + bool success = true; |
| 140 | + mReply = QgsNetworkAccessManager::instance()->get( request ); |
143 | 141 |
|
144 | | - QEventLoop loop; |
145 | | - connect( this, &QgsWfsRequest::downloadFinished, &loop, &QEventLoop::quit ); |
146 | | - loop.exec( QEventLoop::ExcludeUserInputEvents ); |
| 142 | + mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT ); |
| 143 | + if ( !mUri.auth().setAuthorizationReply( mReply ) ) |
| 144 | + { |
| 145 | + mErrorCode = QgsWfsRequest::NetworkError; |
| 146 | + mErrorMessage = errorMessageFailedAuth(); |
| 147 | + QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); |
| 148 | + waitCondition.wakeAll(); |
| 149 | + success = false; |
| 150 | + } |
| 151 | + else |
| 152 | + { |
| 153 | + // We are able to use direct connection here, because we |
| 154 | + // * either run on the thread mReply lives in, so DirectConnection is standard and safe anyway |
| 155 | + // * or the owner thread of mReply is currently not doing anything because it's blocked in future.waitForFinished() (if it is the main thread) |
| 156 | + connect( mReply, &QNetworkReply::finished, this, &QgsWfsRequest::replyFinished, Qt::DirectConnection ); |
| 157 | + connect( mReply, &QNetworkReply::downloadProgress, this, &QgsWfsRequest::replyProgress, Qt::DirectConnection ); |
147 | 158 |
|
148 | | - return mErrorMessage.isEmpty(); |
| 159 | + if ( synchronous ) |
| 160 | + { |
| 161 | + auto resumeMainThread = [&waitConditionMutex, &waitCondition]() |
| 162 | + { |
| 163 | + waitConditionMutex.lock(); |
| 164 | + waitCondition.wakeAll(); |
| 165 | + waitConditionMutex.unlock(); |
| 166 | + |
| 167 | + waitConditionMutex.lock(); |
| 168 | + waitCondition.wait( &waitConditionMutex ); |
| 169 | + waitConditionMutex.unlock(); |
| 170 | + }; |
| 171 | + |
| 172 | + connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::authenticationRequired, this, resumeMainThread, Qt::DirectConnection ); |
| 173 | + connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::proxyAuthenticationRequired, this, resumeMainThread, Qt::DirectConnection ); |
| 174 | + |
| 175 | +#ifndef QT_NO_SSL |
| 176 | + connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::sslErrors, this, resumeMainThread, Qt::DirectConnection ); |
| 177 | +#endif |
| 178 | + QEventLoop loop; |
| 179 | + connect( this, &QgsWfsRequest::downloadFinished, &loop, &QEventLoop::quit, Qt::DirectConnection ); |
| 180 | + loop.exec(); |
| 181 | + } |
| 182 | + } |
| 183 | + waitCondition.wakeAll(); |
| 184 | + return success; |
| 185 | + }; |
| 186 | + |
| 187 | + bool success; |
| 188 | + |
| 189 | + if ( synchronous && QThread::currentThread() == QApplication::instance()->thread() ) |
| 190 | + { |
| 191 | + std::unique_ptr<DownloaderThread> downloaderThread = qgis::make_unique<DownloaderThread>( downloaderFunction ); |
| 192 | + downloaderThread->start(); |
| 193 | + |
| 194 | + while ( !downloaderThread->isFinished() ) |
| 195 | + { |
| 196 | + waitConditionMutex.lock(); |
| 197 | + waitCondition.wait( &waitConditionMutex ); |
| 198 | + waitConditionMutex.unlock(); |
| 199 | + |
| 200 | + // If the downloader thread wakes us (the main thread) up and is not yet finished |
| 201 | + // he needs the authentication to run. |
| 202 | + // The processEvents() call gives the auth manager the chance to show a dialog and |
| 203 | + // once done with that, we can wake the downloaderThread again and continue the download. |
| 204 | + if ( !downloaderThread->isFinished() ) |
| 205 | + { |
| 206 | + QgsApplication::instance()->processEvents(); |
| 207 | + waitConditionMutex.lock(); |
| 208 | + waitCondition.wakeAll(); |
| 209 | + waitConditionMutex.unlock(); |
| 210 | + } |
| 211 | + } |
| 212 | + |
| 213 | + success = downloaderThread->success(); |
| 214 | + } |
| 215 | + else |
| 216 | + { |
| 217 | + success = downloaderFunction(); |
| 218 | + } |
| 219 | + return success && mErrorMessage.isEmpty(); |
149 | 220 | } |
150 | 221 |
|
151 | 222 | bool QgsWfsRequest::sendPOST( const QUrl &url, const QString &contentTypeHeader, const QByteArray &data ) |
|
0 commit comments