37 #include <QNetworkReply> 38 #include <QThreadStorage> 39 #include <QAuthenticator> 42 #include <QSslConfiguration> 51 class QgsNetworkProxyFactory :
public QNetworkProxyFactory
54 QgsNetworkProxyFactory() =
default;
56 QList<QNetworkProxy> queryProxy(
const QNetworkProxyQuery &query = QNetworkProxyQuery() )
override 63 QList<QNetworkProxy> systemproxies = f->systemProxyForQuery( query );
64 if ( !systemproxies.isEmpty() )
67 QList<QNetworkProxy> proxies = f->queryProxy( query );
68 if ( !proxies.isEmpty() )
73 if ( query.queryType() != QNetworkProxyQuery::UrlRequest )
76 QString url = query.url().toString();
78 Q_FOREACH (
const QString &exclude, nam->
excludeList() )
80 if ( !exclude.trimmed().isEmpty() && url.startsWith( exclude ) )
82 QgsDebugMsgLevel( QStringLiteral(
"using default proxy for %1 [exclude %2]" ).arg( url, exclude ), 4 );
83 return QList<QNetworkProxy>() << QNetworkProxy();
89 QgsDebugMsgLevel( QStringLiteral(
"requesting system proxy for query %1" ).arg( url ), 4 );
90 QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery( query );
91 if ( !proxies.isEmpty() )
94 .arg( proxies.first().hostName() ).arg( proxies.first().port() ), 4 );
99 QgsDebugMsgLevel( QStringLiteral(
"using fallback proxy for %1" ).arg( url ), 4 );
110 static QThreadStorage<QgsNetworkAccessManager> sInstances;
113 if ( nam->thread() == qApp->thread() )
116 if ( !nam->mInitialized )
123 : QNetworkAccessManager( parent )
125 setProxyFactory(
new QgsNetworkProxyFactory() );
130 Q_ASSERT( sMainNAM ==
this );
131 mSslErrorHandler = std::move( handler );
136 Q_ASSERT( sMainNAM ==
this );
137 mAuthHandler = std::move( handler );
142 mProxyFactories.insert( 0, factory );
147 mProxyFactories.removeAll( factory );
152 return mProxyFactories;
157 return mExcludedURLs;
162 return mFallbackProxy;
167 QgsDebugMsgLevel( QStringLiteral(
"proxy settings: (type:%1 host: %2:%3, user:%4, password:%5" )
168 .arg( proxy.type() == QNetworkProxy::DefaultProxy ? QStringLiteral(
"DefaultProxy" ) :
169 proxy.type() == QNetworkProxy::Socks5Proxy ? QStringLiteral(
"Socks5Proxy" ) :
170 proxy.type() == QNetworkProxy::NoProxy ? QStringLiteral(
"NoProxy" ) :
171 proxy.type() == QNetworkProxy::HttpProxy ? QStringLiteral(
"HttpProxy" ) :
172 proxy.type() == QNetworkProxy::HttpCachingProxy ? QStringLiteral(
"HttpCachingProxy" ) :
173 proxy.type() == QNetworkProxy::FtpCachingProxy ? QStringLiteral(
"FtpCachingProxy" ) :
174 QStringLiteral(
"Undefined" ),
178 proxy.password().isEmpty() ? QStringLiteral(
"not set" ) : QStringLiteral(
"set" ) ), 4 );
180 mFallbackProxy = proxy;
181 mExcludedURLs = excludes;
183 mExcludedURLs.erase( std::remove_if( mExcludedURLs.begin(), mExcludedURLs.end(),
184 [](
const QString & url )
186 return url.trimmed().isEmpty();
187 } ), mExcludedURLs.end() );
195 QNetworkRequest *pReq( const_cast< QNetworkRequest * >( &req ) );
197 QString userAgent = s.
value( QStringLiteral(
"/qgis/networkAndProxy/userAgent" ),
"Mozilla/5.0" ).toString();
198 if ( !userAgent.isEmpty() )
201 pReq->setRawHeader(
"User-Agent", userAgent.toUtf8() );
204 bool ishttps = pReq->url().scheme().compare( QLatin1String(
"https" ), Qt::CaseInsensitive ) == 0;
207 QgsDebugMsgLevel( QStringLiteral(
"Adding trusted CA certs to request" ), 3 );
208 QSslConfiguration sslconfig( pReq->sslConfiguration() );
212 QString hostport( QStringLiteral(
"%1:%2" )
213 .arg( pReq->url().host().trimmed() )
214 .arg( pReq->url().port() != -1 ? pReq->url().port() : 443 ) );
216 if ( !servconfig.
isNull() )
218 QgsDebugMsg( QStringLiteral(
"Adding SSL custom config to request for %1" ).arg( hostport ) );
224 pReq->setSslConfiguration( sslconfig );
228 static QAtomicInt sRequestId = 0;
229 const int requestId = ++sRequestId;
231 if ( QBuffer *buffer = qobject_cast<QBuffer *>( outgoingData ) )
233 content = buffer->buffer();
240 QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
241 reply->setProperty(
"requestId", requestId );
247 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsNetworkAccessManager::onReplyDownloadProgress );
249 connect( reply, &QNetworkReply::sslErrors,
this, &QgsNetworkAccessManager::onReplySslErrors );
255 QTimer *timer =
new QTimer( reply );
256 timer->setObjectName( QStringLiteral(
"timeoutTimer" ) );
257 connect( timer, &QTimer::timeout,
this, &QgsNetworkAccessManager::abortRequest );
258 timer->setSingleShot(
true );
261 connect( reply, &QNetworkReply::downloadProgress, timer, [timer] { timer->start(); } );
262 connect( reply, &QNetworkReply::uploadProgress, timer, [timer] { timer->start(); } );
263 connect( reply, &QNetworkReply::finished, timer, &QTimer::stop );
264 QgsDebugMsgLevel( QStringLiteral(
"Created [reply:%1]" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ), 3 );
270 void QgsNetworkAccessManager::unlockAfterSslErrorHandled()
272 Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
273 mSslErrorWaitCondition.wakeOne();
277 void QgsNetworkAccessManager::abortRequest()
279 QTimer *timer = qobject_cast<QTimer *>( sender() );
282 QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
286 QgsDebugMsgLevel( QStringLiteral(
"Abort [reply:%1] %2" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ).arg( reply->url().toString() ), 3 );
293 void QgsNetworkAccessManager::onReplyFinished( QNetworkReply *reply )
298 void QgsNetworkAccessManager::onReplyDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
300 if ( QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() ) )
307 void QgsNetworkAccessManager::onReplySslErrors(
const QList<QSslError> &errors )
309 QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() );
311 Q_ASSERT( reply->manager() == this );
313 QgsDebugMsg( QStringLiteral(
"Stopping network reply timeout whilst SSL error is handled" ) );
314 pauseTimeout( reply );
320 emit sslErrorsOccurred( reply, errors );
321 if (
this != sMainNAM )
325 mSslErrorHandlerMutex.lock();
326 mSslErrorWaitCondition.wait( &mSslErrorHandlerMutex );
327 mSslErrorHandlerMutex.unlock();
328 afterSslErrorHandled( reply );
332 void QgsNetworkAccessManager::afterSslErrorHandled( QNetworkReply *reply )
334 if ( reply->manager() == this )
336 restartTimeout( reply );
337 emit sslErrorsHandled( reply );
339 else if (
this == sMainNAM )
346 void QgsNetworkAccessManager::unlockAfterAuthRequestHandled()
348 Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
349 mAuthRequestWaitCondition.wakeOne();
352 void QgsNetworkAccessManager::afterAuthRequestHandled( QNetworkReply *reply )
354 if ( reply->manager() == this )
356 restartTimeout( reply );
357 emit authRequestHandled( reply );
359 else if (
this == sMainNAM )
366 void QgsNetworkAccessManager::pauseTimeout( QNetworkReply *reply )
368 Q_ASSERT( reply->manager() == this );
370 QTimer *timer = reply->findChild<QTimer *>( QStringLiteral(
"timeoutTimer" ) );
371 if ( timer && timer->isActive() )
377 void QgsNetworkAccessManager::restartTimeout( QNetworkReply *reply )
379 Q_ASSERT( reply->manager() == this );
381 QTimer *timer = reply->findChild<QTimer *>( QStringLiteral(
"timeoutTimer" ) );
384 Q_ASSERT( !timer->isActive() );
385 QgsDebugMsg( QStringLiteral(
"Restarting network reply timeout" ) );
386 timer->setSingleShot(
true );
391 int QgsNetworkAccessManager::getRequestId( QNetworkReply *reply )
393 return reply->property(
"requestId" ).toInt();
396 void QgsNetworkAccessManager::handleSslErrors( QNetworkReply *reply,
const QList<QSslError> &errors )
398 mSslErrorHandler->handleSslErrors( reply, errors );
399 afterSslErrorHandled( reply );
404 void QgsNetworkAccessManager::onAuthRequired( QNetworkReply *reply, QAuthenticator *auth )
407 Q_ASSERT( reply->manager() == this );
409 QgsDebugMsg( QStringLiteral(
"Stopping network reply timeout whilst auth request is handled" ) );
410 pauseTimeout( reply );
416 emit authRequestOccurred( reply, auth );
417 if (
this != sMainNAM )
421 mAuthRequestHandlerMutex.lock();
422 mAuthRequestWaitCondition.wait( &mAuthRequestHandlerMutex );
423 mAuthRequestHandlerMutex.unlock();
424 afterAuthRequestHandled( reply );
428 void QgsNetworkAccessManager::handleAuthRequest( QNetworkReply *reply, QAuthenticator *auth )
430 mAuthHandler->handleAuthRequest( reply, auth );
434 afterAuthRequestHandled( reply );
441 case QNetworkRequest::AlwaysNetwork:
442 return QStringLiteral(
"AlwaysNetwork" );
443 case QNetworkRequest::PreferNetwork:
444 return QStringLiteral(
"PreferNetwork" );
445 case QNetworkRequest::PreferCache:
446 return QStringLiteral(
"PreferCache" );
447 case QNetworkRequest::AlwaysCache:
448 return QStringLiteral(
"AlwaysCache" );
450 return QStringLiteral(
"PreferNetwork" );
455 if ( name == QLatin1String(
"AlwaysNetwork" ) )
457 return QNetworkRequest::AlwaysNetwork;
459 else if ( name == QLatin1String(
"PreferNetwork" ) )
461 return QNetworkRequest::PreferNetwork;
463 else if ( name == QLatin1String(
"PreferCache" ) )
465 return QNetworkRequest::PreferCache;
467 else if ( name == QLatin1String(
"AlwaysCache" ) )
469 return QNetworkRequest::AlwaysCache;
471 return QNetworkRequest::PreferNetwork;
477 mUseSystemProxy =
false;
479 Q_ASSERT( sMainNAM );
481 if ( sMainNAM !=
this )
483 connect(
this, &QNetworkAccessManager::proxyAuthenticationRequired,
484 sMainNAM, &QNetworkAccessManager::proxyAuthenticationRequired,
502 connect(
this, &QNetworkAccessManager::sslErrors,
503 sMainNAM, &QNetworkAccessManager::sslErrors,
516 setAuthHandler( qgis::make_unique< QgsNetworkAuthenticationHandler>() );
519 connect(
this, &QgsNetworkAccessManager::sslErrorsOccurred, sMainNAM, &QgsNetworkAccessManager::handleSslErrors );
521 connect(
this, &QNetworkAccessManager::authenticationRequired,
this, &QgsNetworkAccessManager::onAuthRequired );
522 connect(
this, &QgsNetworkAccessManager::authRequestOccurred, sMainNAM, &QgsNetworkAccessManager::handleAuthRequest );
524 connect(
this, &QNetworkAccessManager::finished,
this, &QgsNetworkAccessManager::onReplyFinished );
529 QStringList excludes;
531 bool proxyEnabled = settings.
value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool();
534 excludes = settings.
value( QStringLiteral(
"proxy/proxyExcludedUrls" ), QStringList() ).toStringList();
537 QString proxyHost = settings.
value( QStringLiteral(
"proxy/proxyHost" ),
"" ).toString();
538 int proxyPort = settings.
value( QStringLiteral(
"proxy/proxyPort" ),
"" ).toString().toInt();
540 QString proxyUser = settings.
value( QStringLiteral(
"proxy/proxyUser" ),
"" ).toString();
541 QString proxyPassword = settings.
value( QStringLiteral(
"proxy/proxyPassword" ),
"" ).toString();
543 QString proxyTypeString = settings.
value( QStringLiteral(
"proxy/proxyType" ),
"" ).toString();
545 if ( proxyTypeString == QLatin1String(
"DefaultProxy" ) )
547 mUseSystemProxy =
true;
548 QNetworkProxyFactory::setUseSystemConfiguration(
true );
549 QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
550 if ( !proxies.isEmpty() )
552 proxy = proxies.first();
558 QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
559 if ( proxyTypeString == QLatin1String(
"Socks5Proxy" ) )
561 proxyType = QNetworkProxy::Socks5Proxy;
563 else if ( proxyTypeString == QLatin1String(
"HttpProxy" ) )
565 proxyType = QNetworkProxy::HttpProxy;
567 else if ( proxyTypeString == QLatin1String(
"HttpCachingProxy" ) )
569 proxyType = QNetworkProxy::HttpCachingProxy;
571 else if ( proxyTypeString == QLatin1String(
"FtpCachingProxy" ) )
573 proxyType = QNetworkProxy::FtpCachingProxy;
575 QgsDebugMsg( QStringLiteral(
"setting proxy %1 %2:%3 %4/%5" )
577 .arg( proxyHost ).arg( proxyPort )
578 .arg( proxyUser, proxyPassword )
580 proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
583 QString authcfg = settings.
value( QStringLiteral(
"proxy/authcfg" ),
"" ).toString();
584 if ( !authcfg.isEmpty( ) )
586 QgsDebugMsg( QStringLiteral(
"setting proxy from stored authentication configuration %1" ).arg( authcfg ) );
599 QString cacheDirectory = settings.
value( QStringLiteral(
"cache/directory" ) ).toString();
600 if ( cacheDirectory.isEmpty() )
602 qint64 cacheSize = settings.
value( QStringLiteral(
"cache/size" ), 50 * 1024 * 1024 ).toULongLong();
608 if ( cache() != newcache )
609 setCache( newcache );
614 return QgsSettings().
value( QStringLiteral(
"/qgis/networkAndProxy/networkTimeout" ), 60000 ).toInt();
626 br.
get( request, forceRefresh, feedback );
634 br.
post( request, data, forceRefresh, feedback );
644 : mOperation( operation )
645 , mRequest( request )
646 , mOriginatingThreadId( QStringLiteral(
"0x%2" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char(
'0' ) ) )
647 , mRequestId( requestId )
648 , mContent( content )
649 , mInitiatorClass( request.attribute( static_cast< QNetworkRequest::Attribute >(
QgsNetworkRequestParameters::AttributeInitiatorClass ) ).toString() )
650 , mInitiatorRequestId( request.attribute( static_cast< QNetworkRequest::Attribute >(
QgsNetworkRequestParameters::AttributeInitiatorRequestId ) ) )
662 QgsDebugMsg( QStringLiteral(
"SSL errors occurred accessing URL:\n%1" ).arg( reply->request().url().toString() ) );
672 QgsDebugMsg( QStringLiteral(
"Network reply required authentication, but no handler was in place to provide this authentication request while accessing the URL:\n%1" ).arg( reply->request().url().toString() ) );
virtual void handleSslErrors(QNetworkReply *reply, const QList< QSslError > &errors)
Called whenever SSL errors are encountered during a network reply.
bool isNull() const
Whether configuration is null (missing components)
static QList< QSslCertificate > casMerge(const QList< QSslCertificate > &bundle1, const QList< QSslCertificate > &bundle2)
casMerge merges two certificate bundles in a single one removing duplicates, the certificates from th...
static const QString QGIS_VERSION
Version string.
static QString cacheLoadControlName(QNetworkRequest::CacheLoadControl control)
Returns the name for QNetworkRequest::CacheLoadControl.
int sslPeerVerifyDepth() const
Number or SSL client's peer to verify in connections.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
Q_DECL_DEPRECATED void requestCreated(QNetworkReply *)
void requestTimedOut(QgsNetworkRequestParameters request)
Emitted when a network request has timed out.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkProxy with an authentication config.
void setCacheDirectory(const QString &cacheDir)
QgsNetworkRequestParameters()=default
Default constructor.
#define Q_NOWARN_DEPRECATED_PUSH
Configuration container for SSL server connection exceptions or overrides.
QStringList excludeList() const
Returns the proxy exclude list.
Encapsulates parameters and properties of a network request.
QSsl::SslProtocol sslProtocol() const
SSL server protocol to use in connections.
QNetworkReply * createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData=nullptr) override
static QNetworkRequest::CacheLoadControl cacheLoadControlFromName(const QString &name)
Returns QNetworkRequest::CacheLoadControl from a name.
QgsNetworkAccessManager(QObject *parent=nullptr)
QSslSocket::PeerVerifyMode sslPeerVerifyMode() const
SSL client's peer verify mode to use in connections.
virtual void handleAuthRequest(QNetworkReply *reply, QAuthenticator *auth)
Called whenever network authentication requests are encountered during a network reply.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
Base class for feedback objects to be used for cancelation of something running in a worker thread...
ErrorCode post(QNetworkRequest &request, const QByteArray &data, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "post" operation on the specified request, using the given data.
void finished(QgsNetworkReplyContent reply)
This signal is emitted whenever a pending network reply is finished.
#define QgsDebugMsgLevel(str, level)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
QString cacheDirectory() const
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get() or post() request has been made...
void removeProxyFactory(QNetworkProxyFactory *factory)
Removes a factory from the proxy factories list.
const QgsAuthConfigSslServer sslCertCustomConfigByHost(const QString &hostport)
sslCertCustomConfigByHost get an SSL certificate custom config by hostport (host:port) ...
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
void setSslErrorHandler(std::unique_ptr< QgsSslErrorHandler > handler)
Sets the application SSL error handler, which is used to respond to SSL errors encountered during net...
Q_DECL_DEPRECATED void requestAboutToBeCreated(QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice *)
void insertProxyFactory(QNetworkProxyFactory *factory)
Inserts a factory into the proxy factories list.
#define Q_NOWARN_DEPRECATED_POP
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
void requestAuthDetailsAdded(int requestId, const QString &realm, const QString &user, const QString &password)
Emitted when network authentication details have been added to a request.
void setupDefaultProxyAndCache(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Setup the QgsNetworkAccessManager (NAM) according to the user's settings.
void requestEncounteredSslErrors(int requestId, const QList< QSslError > &errors)
Emitted when a network request encounters SSL errors.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
qint64 maximumCacheSize() const
static int timeout()
Returns the network timeout length, in milliseconds.
const QNetworkProxy & fallbackProxy() const
Returns the fallback proxy used by the manager.
void downloadProgress(int requestId, qint64 bytesReceived, qint64 bytesTotal)
Emitted when a network reply receives a progress report.
bool useSystemProxy() const
Returns whether the system proxy should be used.
void setAuthHandler(std::unique_ptr< QgsNetworkAuthenticationHandler > handler)
Sets the application network authentication handler, which is used to respond to network authenticati...
static QgsNetworkReplyContent blockingPost(QNetworkRequest &request, const QByteArray &data, const QString &authCfg=QString(), bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Posts a POST request to obtain the contents of the target request, using the given data...
static QgsNetworkReplyContent blockingGet(QNetworkRequest &request, const QString &authCfg=QString(), bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Posts a GET request to obtain the contents of the target request and returns a new QgsNetworkReplyCon...
network access manager for QGISThis class implements the QGIS network access manager.
void setFallbackProxyAndExcludes(const QNetworkProxy &proxy, const QStringList &excludes)
Sets the fallback proxy and URLs which shouldn't use it.
void setMaximumCacheSize(qint64 size)
Wrapper implementation of QNetworkDiskCache with all methods guarded by a mutex soly for internal use...
void requestRequiresAuth(int requestId, const QString &realm)
Emitted when a network request prompts an authentication request.
static void setTimeout(int time)
Sets the maximum timeout time for network requests, in milliseconds.
const QList< QNetworkProxyFactory * > proxyFactories() const
Returns a list of proxy factories used by the manager.