Skip to content

Commit c128a55

Browse files
committed
use individual network managers for threads (fixes #13721, fixes #14401, implements #14192)
(cherry picked from commit 2eb8243)
1 parent 03110c4 commit c128a55

18 files changed

+341
-271
lines changed

python/core/qgsnetworkaccessmanager.sip

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,10 @@ class QgsNetworkAccessManager : QNetworkAccessManager
6262

6363
bool useSystemProxy();
6464

65-
public slots:
66-
/** Send GET request, calls get().
67-
* Emits requestSent().
68-
* @param request request to be sent
69-
*/
70-
void sendGet( const QNetworkRequest & request );
71-
/** Abort and delete reply. This slot may be used to abort reply created by instance of this class
72-
* (and which was not moved to another thread) from a different thread. Such reply cannot
73-
* be aborted directly from a different thread. The reply must be also deleted
74-
* in this slot, otherwise it could happen that abort signal comes after the reply was deleted.
75-
* @param reply reply to be aborted.
76-
*/
77-
void deleteReply( QNetworkReply * reply );
78-
7965
signals:
8066
void requestAboutToBeCreated( QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice * );
8167
void requestCreated( QNetworkReply * );
8268
void requestTimedOut( QNetworkReply * );
83-
/** Emitted when request was sent by request()
84-
* @param reply request reply
85-
* @param sender the object which called request() slot.
86-
*/
87-
void requestSent( QNetworkReply * reply, QObject *sender );
8869

8970
protected:
9071
virtual QNetworkReply *createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData = 0 );

src/app/qgisapp.cpp

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
#include <QNetworkReply>
8080
#include <QNetworkProxy>
8181
#include <QAuthenticator>
82-
#include <QNetworkDiskCache>
8382

8483
//
8584
// Mac OS X Includes
@@ -398,7 +397,7 @@ static void setTitleBarText_( QWidget & qgisApp )
398397
*/
399398
static QgsMessageOutput *messageOutputViewer_()
400399
{
401-
if ( QThread::currentThread() == QApplication::instance()->thread() )
400+
if ( QThread::currentThread() == qApp->thread() )
402401
return new QgsMessageViewer( QgisApp::instance() );
403402
else
404403
return new QgsMessageOutputConsole();
@@ -10878,6 +10877,8 @@ void QgisApp::namSetup()
1087810877

1087910878
void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *auth )
1088010879
{
10880+
Q_ASSERT( qApp->thread() == QThread::currentThread() );
10881+
1088110882
QString username = auth->user();
1088210883
QString password = auth->password();
1088310884

@@ -10896,31 +10897,38 @@ void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *a
1089610897
}
1089710898
}
1089810899

10900+
for ( ;; )
1089910901
{
10900-
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10902+
bool ok;
1090110903

10902-
for ( ;; )
1090310904
{
10904-
bool ok = QgsCredentials::instance()->get(
10905-
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
10906-
username, password,
10907-
tr( "Authentication required" ) );
10908-
if ( !ok )
10909-
return;
10905+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10906+
ok = QgsCredentials::instance()->get(
10907+
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
10908+
username, password,
10909+
tr( "Authentication required" ) );
10910+
}
10911+
if ( !ok )
10912+
return;
1091010913

10911-
if ( reply->isFinished() )
10912-
return;
10914+
if ( reply->isFinished() )
10915+
return;
1091310916

10914-
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10915-
break;
10917+
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10918+
break;
1091610919

10917-
// credentials didn't change - stored ones probably wrong? clear password and retry
10920+
// credentials didn't change - stored ones probably wrong? clear password and retry
10921+
{
10922+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1091810923
QgsCredentials::instance()->put(
1091910924
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
1092010925
username, QString::null );
1092110926
}
10927+
}
1092210928

10923-
// save credentials
10929+
// save credentials
10930+
{
10931+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1092410932
QgsCredentials::instance()->put(
1092510933
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
1092610934
username, password
@@ -10944,27 +10952,34 @@ void QgisApp::namProxyAuthenticationRequired( const QNetworkProxy &proxy, QAuthe
1094410952
QString username = auth->user();
1094510953
QString password = auth->password();
1094610954

10955+
for ( ;; )
1094710956
{
10948-
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10957+
bool ok;
1094910958

10950-
for ( ;; )
1095110959
{
10952-
bool ok = QgsCredentials::instance()->get(
10953-
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
10954-
username, password,
10955-
tr( "Proxy authentication required" ) );
10956-
if ( !ok )
10957-
return;
10960+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10961+
ok = QgsCredentials::instance()->get(
10962+
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
10963+
username, password,
10964+
tr( "Proxy authentication required" ) );
10965+
}
10966+
if ( !ok )
10967+
return;
1095810968

10959-
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10960-
break;
10969+
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10970+
break;
1096110971

10962-
// credentials didn't change - stored ones probably wrong? clear password and retry
10972+
// credentials didn't change - stored ones probably wrong? clear password and retry
10973+
{
10974+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1096310975
QgsCredentials::instance()->put(
1096410976
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
1096510977
username, QString::null );
1096610978
}
10979+
}
1096710980

10981+
{
10982+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1096810983
QgsCredentials::instance()->put(
1096910984
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
1097010985
username, password

src/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ SET(QGIS_CORE_SRCS
149149
qgsmimedatautils.cpp
150150
qgsmultirenderchecker.cpp
151151
qgsnetworkaccessmanager.cpp
152+
qgsnetworkdiskcache.cpp
152153
qgsnetworkcontentfetcher.cpp
153154
qgsnetworkreplyparser.cpp
154155
qgsobjectcustomproperties.cpp
@@ -451,6 +452,7 @@ SET(QGIS_CORE_MOC_HDRS
451452
qgsmessagelog.h
452453
qgsmessageoutput.h
453454
qgsnetworkaccessmanager.h
455+
qgsnetworkdiskcache.h
454456
qgsnetworkcontentfetcher.h
455457
qgsnetworkreplyparser.h
456458
qgsofflineediting.h

src/core/qgsnetworkaccessmanager.cpp

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@
3030
#include <QSettings>
3131
#include <QTimer>
3232
#include <QNetworkReply>
33-
#include <QNetworkDiskCache>
33+
#include <QThreadStorage>
3434

3535
#ifndef QT_NO_OPENSSL
3636
#include <QSslConfiguration>
3737
#endif
3838

39+
#include "qgsnetworkdiskcache.h"
3940
#include "qgsauthmanager.h"
4041

42+
QgsNetworkAccessManager *QgsNetworkAccessManager::smMainNAM = 0;
43+
4144
/// @cond PRIVATE
4245
class QgsNetworkProxyFactory : public QNetworkProxyFactory
4346
{
@@ -99,13 +102,22 @@ class QgsNetworkProxyFactory : public QNetworkProxyFactory
99102
//
100103
QgsNetworkAccessManager* QgsNetworkAccessManager::instance()
101104
{
102-
static QgsNetworkAccessManager* sInstance( new QgsNetworkAccessManager( QApplication::instance() ) );
103-
return sInstance;
105+
static QThreadStorage<QgsNetworkAccessManager> sInstances;
106+
QgsNetworkAccessManager *nam = &sInstances.localData();
107+
108+
if ( nam->thread() == qApp->thread() )
109+
smMainNAM = nam;
110+
111+
if ( !nam->mInitialized )
112+
nam->setupDefaultProxyAndCache();
113+
114+
return nam;
104115
}
105116

106117
QgsNetworkAccessManager::QgsNetworkAccessManager( QObject *parent )
107118
: QNetworkAccessManager( parent )
108119
, mUseSystemProxy( false )
120+
, mInitialized( false )
109121
{
110122
setProxyFactory( new QgsNetworkProxyFactory() );
111123
}
@@ -221,6 +233,8 @@ void QgsNetworkAccessManager::abortRequest()
221233
QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
222234
Q_ASSERT( reply );
223235

236+
QgsDebugMsg( QString( "Abort [reply:%1]" ).arg(( qint64 ) reply, 0, 16 ) );
237+
224238
QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
225239

226240
if ( reply->isRunning() )
@@ -270,36 +284,36 @@ QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromN
270284

271285
void QgsNetworkAccessManager::setupDefaultProxyAndCache()
272286
{
273-
QNetworkProxy proxy;
274-
QStringList excludes;
275-
276-
QSettings settings;
277-
287+
mInitialized = true;
278288
mUseSystemProxy = false;
279289

280-
if ( this != instance() )
281-
{
282-
Qt::ConnectionType connectionType = thread() == instance()->thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection;
290+
Q_ASSERT( smMainNAM );
283291

292+
if ( smMainNAM != this )
293+
{
284294
connect( this, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
285-
instance(), SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
286-
connectionType );
295+
smMainNAM, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
296+
Qt::BlockingQueuedConnection );
287297

288298
connect( this, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
289-
instance(), SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
290-
connectionType );
299+
smMainNAM, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
300+
Qt::BlockingQueuedConnection );
291301

292302
connect( this, SIGNAL( requestTimedOut( QNetworkReply* ) ),
293-
instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ) );
303+
smMainNAM, SIGNAL( requestTimedOut( QNetworkReply* ) ) );
294304

295305
#ifndef QT_NO_OPENSSL
296306
connect( this, SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
297-
instance(), SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
298-
connectionType );
307+
smMainNAM, SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
308+
Qt::BlockingQueuedConnection );
299309
#endif
300310
}
301311

302312
// check if proxy is enabled
313+
QSettings settings;
314+
QNetworkProxy proxy;
315+
QStringList excludes;
316+
303317
bool proxyEnabled = settings.value( "proxy/proxyEnabled", false ).toBool();
304318
if ( proxyEnabled )
305319
{
@@ -354,9 +368,9 @@ void QgsNetworkAccessManager::setupDefaultProxyAndCache()
354368

355369
setFallbackProxyAndExcludes( proxy, excludes );
356370

357-
QNetworkDiskCache *newcache = qobject_cast<QNetworkDiskCache*>( cache() );
371+
QgsNetworkDiskCache *newcache = qobject_cast<QgsNetworkDiskCache*>( cache() );
358372
if ( !newcache )
359-
newcache = new QNetworkDiskCache( this );
373+
newcache = new QgsNetworkDiskCache( this );
360374

361375
QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString();
362376
qint64 cacheSize = settings.value( "cache/size", 50 * 1024 * 1024 ).toULongLong();
@@ -370,21 +384,3 @@ void QgsNetworkAccessManager::setupDefaultProxyAndCache()
370384
if ( cache() != newcache )
371385
setCache( newcache );
372386
}
373-
374-
void QgsNetworkAccessManager::sendGet( const QNetworkRequest & request )
375-
{
376-
QgsDebugMsg( "Entered" );
377-
QNetworkReply * reply = get( request );
378-
emit requestSent( reply, QObject::sender() );
379-
}
380-
381-
void QgsNetworkAccessManager::deleteReply( QNetworkReply * reply )
382-
{
383-
QgsDebugMsg( "Entered" );
384-
if ( !reply )
385-
{
386-
return;
387-
}
388-
reply->abort();
389-
reply->deleteLater();
390-
}

src/core/qgsnetworkaccessmanager.h

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,31 +82,13 @@ class CORE_EXPORT QgsNetworkAccessManager : public QNetworkAccessManager
8282
//! Setup the NAM according to the user's settings
8383
void setupDefaultProxyAndCache();
8484

85+
//! return whether the system proxy should be used
8586
bool useSystemProxy() { return mUseSystemProxy; }
8687

87-
public slots:
88-
/** Send GET request, calls get().
89-
* Emits requestSent().
90-
* @param request request to be sent
91-
*/
92-
void sendGet( const QNetworkRequest & request );
93-
/** Abort and delete reply. This slot may be used to abort reply created by instance of this class
94-
* (and which was not moved to another thread) from a different thread. Such reply cannot
95-
* be aborted directly from a different thread. The reply must be also deleted
96-
* in this slot, otherwise it could happen that abort signal comes after the reply was deleted.
97-
* @param reply reply to be aborted.
98-
*/
99-
void deleteReply( QNetworkReply * reply );
100-
10188
signals:
10289
void requestAboutToBeCreated( QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice * );
10390
void requestCreated( QNetworkReply * );
10491
void requestTimedOut( QNetworkReply * );
105-
/** Emitted when request was sent by request()
106-
* @param reply request reply
107-
* @param sender the object which called request() slot.
108-
*/
109-
void requestSent( QNetworkReply * reply, QObject *sender );
11092

11193
private slots:
11294
void abortRequest();
@@ -119,6 +101,8 @@ class CORE_EXPORT QgsNetworkAccessManager : public QNetworkAccessManager
119101
QNetworkProxy mFallbackProxy;
120102
QStringList mExcludedURLs;
121103
bool mUseSystemProxy;
104+
bool mInitialized;
105+
static QgsNetworkAccessManager *smMainNAM;
122106
};
123107

124108
#endif // QGSNETWORKACCESSMANAGER_H

0 commit comments

Comments
 (0)