37 #include <QNetworkReply>
38 #include <QThreadStorage>
39 #include <QAuthenticator>
40 #include <QStandardPaths>
43 #include <QSslConfiguration>
52 class QgsNetworkProxyFactory :
public QNetworkProxyFactory
55 QgsNetworkProxyFactory() =
default;
57 QList<QNetworkProxy> queryProxy(
const QNetworkProxyQuery &query = QNetworkProxyQuery() )
override
63 for ( QNetworkProxyFactory *f : constProxyFactories )
65 QList<QNetworkProxy> systemproxies = f->systemProxyForQuery( query );
66 if ( !systemproxies.isEmpty() )
69 QList<QNetworkProxy> proxies = f->queryProxy( query );
70 if ( !proxies.isEmpty() )
75 if ( query.queryType() != QNetworkProxyQuery::UrlRequest )
78 QString url = query.url().toString();
81 for (
const QString &noProxy : constNoProxyList )
83 if ( !noProxy.trimmed().isEmpty() && url.startsWith( noProxy ) )
85 QgsDebugMsgLevel( QStringLiteral(
"don't using any proxy for %1 [exclude %2]" ).arg( url, noProxy ), 4 );
86 return QList<QNetworkProxy>() << QNetworkProxy( QNetworkProxy::NoProxy );
91 for (
const QString &exclude : constExcludeList )
93 if ( !exclude.trimmed().isEmpty() && url.startsWith( exclude ) )
95 QgsDebugMsgLevel( QStringLiteral(
"using default proxy for %1 [exclude %2]" ).arg( url, exclude ), 4 );
96 return QList<QNetworkProxy>() << QNetworkProxy( QNetworkProxy::DefaultProxy );
102 QgsDebugMsgLevel( QStringLiteral(
"requesting system proxy for query %1" ).arg( url ), 4 );
103 QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery( query );
104 if ( !proxies.isEmpty() )
107 .arg( proxies.first().hostName() ).arg( proxies.first().port() ), 4 );
112 QgsDebugMsgLevel( QStringLiteral(
"using fallback proxy for %1" ).arg( url ), 4 );
123 static QThreadStorage<QgsNetworkAccessManager> sInstances;
126 if ( nam->thread() == qApp->thread() )
129 if ( !nam->mInitialized )
139 : QNetworkAccessManager( parent )
141 setProxyFactory(
new QgsNetworkProxyFactory() );
146 Q_ASSERT( sMainNAM ==
this );
147 mSslErrorHandler = std::move( handler );
152 Q_ASSERT( sMainNAM ==
this );
153 mAuthHandler = std::move( handler );
158 mProxyFactories.insert( 0, factory );
163 mProxyFactories.removeAll( factory );
168 return mProxyFactories;
173 return mExcludedURLs;
183 return mFallbackProxy;
188 QgsDebugMsgLevel( QStringLiteral(
"proxy settings: (type:%1 host: %2:%3, user:%4, password:%5" )
189 .arg( proxy.type() == QNetworkProxy::DefaultProxy ? QStringLiteral(
"DefaultProxy" ) :
190 proxy.type() == QNetworkProxy::Socks5Proxy ? QStringLiteral(
"Socks5Proxy" ) :
191 proxy.type() == QNetworkProxy::NoProxy ? QStringLiteral(
"NoProxy" ) :
192 proxy.type() == QNetworkProxy::HttpProxy ? QStringLiteral(
"HttpProxy" ) :
193 proxy.type() == QNetworkProxy::HttpCachingProxy ? QStringLiteral(
"HttpCachingProxy" ) :
194 proxy.type() == QNetworkProxy::FtpCachingProxy ? QStringLiteral(
"FtpCachingProxy" ) :
195 QStringLiteral(
"Undefined" ),
199 proxy.password().isEmpty() ? QStringLiteral(
"not set" ) : QStringLiteral(
"set" ) ), 4 );
201 mFallbackProxy = proxy;
202 mExcludedURLs = excludes;
204 mExcludedURLs.erase( std::remove_if( mExcludedURLs.begin(), mExcludedURLs.end(),
205 [](
const QString & url )
207 return url.trimmed().isEmpty();
208 } ), mExcludedURLs.end() );
210 mNoProxyURLs = noProxyURLs;
211 mNoProxyURLs.erase( std::remove_if( mNoProxyURLs.begin(), mNoProxyURLs.end(),
212 [](
const QString & url )
214 return url.trimmed().isEmpty();
215 } ), mNoProxyURLs.end() );
222 QNetworkRequest *pReq(
const_cast< QNetworkRequest *
>( &req ) );
224 QString userAgent = s.
value( QStringLiteral(
"/qgis/networkAndProxy/userAgent" ),
"Mozilla/5.0" ).toString();
225 if ( !userAgent.isEmpty() )
228 pReq->setRawHeader(
"User-Agent", userAgent.toLatin1() );
231 bool ishttps = pReq->url().scheme().compare( QLatin1String(
"https" ), Qt::CaseInsensitive ) == 0;
234 QgsDebugMsgLevel( QStringLiteral(
"Adding trusted CA certs to request" ), 3 );
235 QSslConfiguration sslconfig( pReq->sslConfiguration() );
239 QString hostport( QStringLiteral(
"%1:%2" )
240 .arg( pReq->url().host().trimmed() )
241 .arg( pReq->url().port() != -1 ? pReq->url().port() : 443 ) );
243 if ( !servconfig.
isNull() )
245 QgsDebugMsg( QStringLiteral(
"Adding SSL custom config to request for %1" ).arg( hostport ) );
251 pReq->setSslConfiguration( sslconfig );
255 if ( sMainNAM->mCacheDisabled )
258 pReq->setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
259 pReq->setAttribute( QNetworkRequest::CacheSaveControlAttribute,
false );
262 static QAtomicInt sRequestId = 0;
263 const int requestId = ++sRequestId;
265 if ( QBuffer *buffer = qobject_cast<QBuffer *>( outgoingData ) )
267 content = buffer->buffer();
274 QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
275 reply->setProperty(
"requestId", requestId );
281 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsNetworkAccessManager::onReplyDownloadProgress );
283 connect( reply, &QNetworkReply::sslErrors,
this, &QgsNetworkAccessManager::onReplySslErrors );
291 QTimer *timer =
new QTimer( reply );
292 timer->setObjectName( QStringLiteral(
"timeoutTimer" ) );
293 connect( timer, &QTimer::timeout,
this, &QgsNetworkAccessManager::abortRequest );
294 timer->setSingleShot(
true );
297 connect( reply, &QNetworkReply::downloadProgress, timer, [timer] { timer->start(); } );
298 connect( reply, &QNetworkReply::uploadProgress, timer, [timer] { timer->start(); } );
299 connect( reply, &QNetworkReply::finished, timer, &QTimer::stop );
301 QgsDebugMsgLevel( QStringLiteral(
"Created [reply:%1]" ).arg(
reinterpret_cast< qint64
>( reply ), 0, 16 ), 3 );
307 void QgsNetworkAccessManager::unlockAfterSslErrorHandled()
309 Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
310 mSslErrorWaitCondition.wakeOne();
314 void QgsNetworkAccessManager::abortRequest()
316 QTimer *timer = qobject_cast<QTimer *>( sender() );
319 QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
323 QgsDebugMsgLevel( QStringLiteral(
"Abort [reply:%1] %2" ).arg(
reinterpret_cast< qint64
>( reply ), 0, 16 ).arg( reply->url().toString() ), 3 );
330 void QgsNetworkAccessManager::onReplyFinished( QNetworkReply *reply )
335 void QgsNetworkAccessManager::onReplyDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
337 if ( QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() ) )
344 void QgsNetworkAccessManager::onReplySslErrors(
const QList<QSslError> &errors )
346 QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() );
348 Q_ASSERT( reply->manager() ==
this );
350 QgsDebugMsg( QStringLiteral(
"Stopping network reply timeout whilst SSL error is handled" ) );
351 pauseTimeout( reply );
357 emit sslErrorsOccurred( reply, errors );
358 if (
this != sMainNAM )
362 mSslErrorHandlerMutex.lock();
363 mSslErrorWaitCondition.wait( &mSslErrorHandlerMutex );
364 mSslErrorHandlerMutex.unlock();
365 afterSslErrorHandled( reply );
369 void QgsNetworkAccessManager::afterSslErrorHandled( QNetworkReply *reply )
371 if ( reply->manager() ==
this )
373 restartTimeout( reply );
374 emit sslErrorsHandled( reply );
376 else if (
this == sMainNAM )
379 qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterSslErrorHandled();
383 void QgsNetworkAccessManager::unlockAfterAuthRequestHandled()
385 Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
386 mAuthRequestWaitCondition.wakeOne();
389 void QgsNetworkAccessManager::afterAuthRequestHandled( QNetworkReply *reply )
391 if ( reply->manager() ==
this )
393 restartTimeout( reply );
394 emit authRequestHandled( reply );
396 else if (
this == sMainNAM )
399 qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterAuthRequestHandled();
403 void QgsNetworkAccessManager::pauseTimeout( QNetworkReply *reply )
405 Q_ASSERT( reply->manager() ==
this );
407 QTimer *timer = reply->findChild<QTimer *>( QStringLiteral(
"timeoutTimer" ) );
408 if ( timer && timer->isActive() )
414 void QgsNetworkAccessManager::restartTimeout( QNetworkReply *reply )
416 Q_ASSERT( reply->manager() ==
this );
418 QTimer *timer = reply->findChild<QTimer *>( QStringLiteral(
"timeoutTimer" ) );
421 Q_ASSERT( !timer->isActive() );
422 QgsDebugMsg( QStringLiteral(
"Restarting network reply timeout" ) );
423 timer->setSingleShot(
true );
428 int QgsNetworkAccessManager::getRequestId( QNetworkReply *reply )
430 return reply->property(
"requestId" ).toInt();
433 void QgsNetworkAccessManager::handleSslErrors( QNetworkReply *reply,
const QList<QSslError> &errors )
435 mSslErrorHandler->handleSslErrors( reply, errors );
436 afterSslErrorHandled( reply );
441 void QgsNetworkAccessManager::onAuthRequired( QNetworkReply *reply, QAuthenticator *auth )
444 Q_ASSERT( reply->manager() ==
this );
446 QgsDebugMsg( QStringLiteral(
"Stopping network reply timeout whilst auth request is handled" ) );
447 pauseTimeout( reply );
453 emit authRequestOccurred( reply, auth );
455 if (
this != sMainNAM )
459 mAuthRequestHandlerMutex.lock();
460 mAuthRequestWaitCondition.wait( &mAuthRequestHandlerMutex );
461 mAuthRequestHandlerMutex.unlock();
462 afterAuthRequestHandled( reply );
466 void QgsNetworkAccessManager::handleAuthRequest( QNetworkReply *reply, QAuthenticator *auth )
468 mAuthHandler->handleAuthRequest( reply, auth );
472 afterAuthRequestHandled( reply );
479 case QNetworkRequest::AlwaysNetwork:
480 return QStringLiteral(
"AlwaysNetwork" );
481 case QNetworkRequest::PreferNetwork:
482 return QStringLiteral(
"PreferNetwork" );
483 case QNetworkRequest::PreferCache:
484 return QStringLiteral(
"PreferCache" );
485 case QNetworkRequest::AlwaysCache:
486 return QStringLiteral(
"AlwaysCache" );
488 return QStringLiteral(
"PreferNetwork" );
493 if ( name == QLatin1String(
"AlwaysNetwork" ) )
495 return QNetworkRequest::AlwaysNetwork;
497 else if ( name == QLatin1String(
"PreferNetwork" ) )
499 return QNetworkRequest::PreferNetwork;
501 else if ( name == QLatin1String(
"PreferCache" ) )
503 return QNetworkRequest::PreferCache;
505 else if ( name == QLatin1String(
"AlwaysCache" ) )
507 return QNetworkRequest::AlwaysCache;
509 return QNetworkRequest::PreferNetwork;
515 mUseSystemProxy =
false;
517 Q_ASSERT( sMainNAM );
519 if ( sMainNAM !=
this )
521 connect(
this, &QNetworkAccessManager::proxyAuthenticationRequired,
522 sMainNAM, &QNetworkAccessManager::proxyAuthenticationRequired,
540 connect(
this, &QNetworkAccessManager::sslErrors,
541 sMainNAM, &QNetworkAccessManager::sslErrors,
554 setAuthHandler( qgis::make_unique< QgsNetworkAuthenticationHandler>() );
557 connect(
this, &QgsNetworkAccessManager::sslErrorsOccurred, sMainNAM, &QgsNetworkAccessManager::handleSslErrors );
559 connect(
this, &QNetworkAccessManager::authenticationRequired,
this, &QgsNetworkAccessManager::onAuthRequired );
560 connect(
this, &QgsNetworkAccessManager::authRequestOccurred, sMainNAM, &QgsNetworkAccessManager::handleAuthRequest );
562 connect(
this, &QNetworkAccessManager::finished,
this, &QgsNetworkAccessManager::onReplyFinished );
567 QStringList excludes;
568 QStringList noProxyURLs;
570 bool proxyEnabled = settings.
value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool();
575 excludes = settings.
value( QStringLiteral(
"proxy/proxyExcludedUrls" ), QStringList() ).toStringList();
577 noProxyURLs = settings.
value( QStringLiteral(
"proxy/noProxyUrls" ), QStringList() ).toStringList();
580 QString proxyHost = settings.
value( QStringLiteral(
"proxy/proxyHost" ),
"" ).toString();
581 int proxyPort = settings.
value( QStringLiteral(
"proxy/proxyPort" ),
"" ).toString().toInt();
583 QString proxyUser = settings.
value( QStringLiteral(
"proxy/proxyUser" ),
"" ).toString();
584 QString proxyPassword = settings.
value( QStringLiteral(
"proxy/proxyPassword" ),
"" ).toString();
586 QString proxyTypeString = settings.
value( QStringLiteral(
"proxy/proxyType" ),
"" ).toString();
588 if ( proxyTypeString == QLatin1String(
"DefaultProxy" ) )
590 mUseSystemProxy =
true;
591 QNetworkProxyFactory::setUseSystemConfiguration(
true );
592 QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
593 if ( !proxies.isEmpty() )
595 proxy = proxies.first();
601 QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
602 if ( proxyTypeString == QLatin1String(
"Socks5Proxy" ) )
604 proxyType = QNetworkProxy::Socks5Proxy;
606 else if ( proxyTypeString == QLatin1String(
"HttpProxy" ) )
608 proxyType = QNetworkProxy::HttpProxy;
610 else if ( proxyTypeString == QLatin1String(
"HttpCachingProxy" ) )
612 proxyType = QNetworkProxy::HttpCachingProxy;
614 else if ( proxyTypeString == QLatin1String(
"FtpCachingProxy" ) )
616 proxyType = QNetworkProxy::FtpCachingProxy;
618 QgsDebugMsg( QStringLiteral(
"setting proxy %1 %2:%3 %4/%5" )
620 .arg( proxyHost ).arg( proxyPort )
621 .arg( proxyUser, proxyPassword )
623 proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
626 QString authcfg = settings.
value( QStringLiteral(
"proxy/authcfg" ),
"" ).toString();
627 if ( !authcfg.isEmpty( ) )
629 QgsDebugMsg( QStringLiteral(
"setting proxy from stored authentication configuration %1" ).arg( authcfg ) );
642 QString cacheDirectory = settings.
value( QStringLiteral(
"cache/directory" ) ).toString();
643 if ( cacheDirectory.isEmpty() )
644 cacheDirectory = QStandardPaths::writableLocation( QStandardPaths::CacheLocation );
645 qint64 cacheSize = settings.
value( QStringLiteral(
"cache/size" ), 50 * 1024 * 1024 ).toLongLong();
651 if ( cache() != newcache )
652 setCache( newcache );
657 return QgsSettings().
value( QStringLiteral(
"/qgis/networkAndProxy/networkTimeout" ), 60000 ).toInt();
669 br.
get( request, forceRefresh, feedback );
677 br.
post( request, data, forceRefresh, feedback );
687 : mOperation( operation )
688 , mRequest( request )
689 , mOriginatingThreadId( QStringLiteral(
"0x%2" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char(
'0' ) ) )
690 , mRequestId( requestId )
691 , mContent( content )
692 , mInitiatorClass( request.attribute( static_cast< QNetworkRequest::Attribute >(
QgsNetworkRequestParameters::AttributeInitiatorClass ) ).toString() )
693 , mInitiatorRequestId( request.attribute( static_cast< QNetworkRequest::Attribute >(
QgsNetworkRequestParameters::AttributeInitiatorRequestId ) ) )
705 QgsDebugMsg( QStringLiteral(
"SSL errors occurred accessing URL:\n%1" ).arg( reply->request().url().toString() ) );
715 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() ) );
static int versionInt()
Version number used for comparing versions using the "Check QGIS Version" function.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
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...
Configuration container for SSL server connection exceptions or overrides.
QSsl::SslProtocol sslProtocol() const
SSL server protocol to use in connections.
int sslPeerVerifyDepth() const
Number or SSL client's peer to verify in connections.
bool isNull() const
Whether configuration is null (missing components)
QSslSocket::PeerVerifyMode sslPeerVerifyMode() const
SSL client's peer verify mode to use in connections.
bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkProxy with an authentication config.
const QgsAuthConfigSslServer sslCertCustomConfigByHost(const QString &hostport)
sslCertCustomConfigByHost get an SSL certificate custom config by hostport (host:port)
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
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.
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.
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).
network access manager for QGIS
QStringList noProxyList() const
Returns the no proxy list.
void finished(QgsNetworkReplyContent reply)
Emitted whenever a pending network reply is finished.
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...
void insertProxyFactory(QNetworkProxyFactory *factory)
Inserts a factory into the proxy factories list.
void setSslErrorHandler(std::unique_ptr< QgsSslErrorHandler > handler)
Sets the application SSL error handler, which is used to respond to SSL errors encountered during net...
void setCacheDisabled(bool disabled)
Sets whether all network caching should be disabled.
const QList< QNetworkProxyFactory * > proxyFactories() const
Returns a list of proxy factories used by the manager.
void downloadProgress(int requestId, qint64 bytesReceived, qint64 bytesTotal)
Emitted when a network reply receives a progress report.
void requestEncounteredSslErrors(int requestId, const QList< QSslError > &errors)
Emitted when a network request encounters SSL errors.
static QString cacheLoadControlName(QNetworkRequest::CacheLoadControl control)
Returns the name for QNetworkRequest::CacheLoadControl.
void requestAuthDetailsAdded(int requestId, const QString &realm, const QString &user, const QString &password)
Emitted when network authentication details have been added to a request.
static QNetworkRequest::CacheLoadControl cacheLoadControlFromName(const QString &name)
Returns QNetworkRequest::CacheLoadControl from a name.
bool cacheDisabled() const
Returns true if all network caching is disabled.
QgsNetworkAccessManager(QObject *parent=nullptr)
void requestRequiresAuth(int requestId, const QString &realm)
Emitted when a network request prompts an authentication request.
void setAuthHandler(std::unique_ptr< QgsNetworkAuthenticationHandler > handler)
Sets the application network authentication handler, which is used to respond to network authenticati...
static void setTimeout(int time)
Sets the maximum timeout time for network requests, in milliseconds.
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,...
const QNetworkProxy & fallbackProxy() const
Returns the fallback proxy used by the manager.
static int timeout()
Returns the network timeout length, in milliseconds.
void setupDefaultProxyAndCache(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Setup the QgsNetworkAccessManager (NAM) according to the user's settings.
void setFallbackProxyAndExcludes(const QNetworkProxy &proxy, const QStringList &excludes, const QStringList &noProxyURLs)
Sets the fallback proxy and URLs which shouldn't use it.
Q_DECL_DEPRECATED void requestCreated(QNetworkReply *)
Q_DECL_DEPRECATED void requestAboutToBeCreated(QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice *)
QStringList excludeList() const
Returns the proxy exclude list.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
void removeProxyFactory(QNetworkProxyFactory *factory)
Removes a factory from the proxy factories list.
void requestTimedOut(QgsNetworkRequestParameters request)
Emitted when a network request has timed out.
bool useSystemProxy() const
Returns whether the system proxy should be used.
QNetworkReply * createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData=nullptr) override
virtual void handleAuthRequest(QNetworkReply *reply, QAuthenticator *auth)
Called whenever network authentication requests are encountered during a network reply.
Wrapper implementation of QNetworkDiskCache with all methods guarded by a mutex soly for internal use...
void setCacheDirectory(const QString &cacheDir)
qint64 maximumCacheSize() const
void setMaximumCacheSize(qint64 size)
QString cacheDirectory() const
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
Encapsulates parameters and properties of a network request.
QgsNetworkRequestParameters()=default
Default constructor.
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.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
virtual void handleSslErrors(QNetworkReply *reply, const QList< QSslError > &errors)
Called whenever SSL errors are encountered during a network reply.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
#define QgsDebugMsgLevel(str, level)