Skip to content

Commit 2eb8243

Browse files
committedMar 5, 2016
use individual network managers for threads (fixes #13721, fixes #14401, implements #14192)
1 parent 26d6195 commit 2eb8243

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();
@@ -10864,6 +10863,8 @@ void QgisApp::namSetup()
1086410863

1086510864
void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *auth )
1086610865
{
10866+
Q_ASSERT( qApp->thread() == QThread::currentThread() );
10867+
1086710868
QString username = auth->user();
1086810869
QString password = auth->password();
1086910870

@@ -10882,31 +10883,38 @@ void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *a
1088210883
}
1088310884
}
1088410885

10886+
for ( ;; )
1088510887
{
10886-
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10888+
bool ok;
1088710889

10888-
for ( ;; )
1088910890
{
10890-
bool ok = QgsCredentials::instance()->get(
10891-
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
10892-
username, password,
10893-
tr( "Authentication required" ) );
10894-
if ( !ok )
10895-
return;
10891+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10892+
ok = QgsCredentials::instance()->get(
10893+
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
10894+
username, password,
10895+
tr( "Authentication required" ) );
10896+
}
10897+
if ( !ok )
10898+
return;
1089610899

10897-
if ( reply->isFinished() )
10898-
return;
10900+
if ( reply->isFinished() )
10901+
return;
1089910902

10900-
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10901-
break;
10903+
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10904+
break;
1090210905

10903-
// credentials didn't change - stored ones probably wrong? clear password and retry
10906+
// credentials didn't change - stored ones probably wrong? clear password and retry
10907+
{
10908+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1090410909
QgsCredentials::instance()->put(
1090510910
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
1090610911
username, QString::null );
1090710912
}
10913+
}
1090810914

10909-
// save credentials
10915+
// save credentials
10916+
{
10917+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1091010918
QgsCredentials::instance()->put(
1091110919
QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ),
1091210920
username, password
@@ -10930,27 +10938,34 @@ void QgisApp::namProxyAuthenticationRequired( const QNetworkProxy &proxy, QAuthe
1093010938
QString username = auth->user();
1093110939
QString password = auth->password();
1093210940

10941+
for ( ;; )
1093310942
{
10934-
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10943+
bool ok;
1093510944

10936-
for ( ;; )
1093710945
{
10938-
bool ok = QgsCredentials::instance()->get(
10939-
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
10940-
username, password,
10941-
tr( "Proxy authentication required" ) );
10942-
if ( !ok )
10943-
return;
10946+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
10947+
ok = QgsCredentials::instance()->get(
10948+
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
10949+
username, password,
10950+
tr( "Proxy authentication required" ) );
10951+
}
10952+
if ( !ok )
10953+
return;
1094410954

10945-
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10946-
break;
10955+
if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) )
10956+
break;
1094710957

10948-
// credentials didn't change - stored ones probably wrong? clear password and retry
10958+
// credentials didn't change - stored ones probably wrong? clear password and retry
10959+
{
10960+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1094910961
QgsCredentials::instance()->put(
1095010962
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
1095110963
username, QString::null );
1095210964
}
10965+
}
1095310966

10967+
{
10968+
QMutexLocker lock( QgsCredentials::instance()->mutex() );
1095410969
QgsCredentials::instance()->put(
1095510970
QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ),
1095610971
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
@@ -452,6 +453,7 @@ SET(QGIS_CORE_MOC_HDRS
452453
qgsmessagelog.h
453454
qgsmessageoutput.h
454455
qgsnetworkaccessmanager.h
456+
qgsnetworkdiskcache.h
455457
qgsnetworkcontentfetcher.h
456458
qgsnetworkreplyparser.h
457459
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)
Failed to load comments.