QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsnetworkaccessmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsnetworkaccessmanager.cpp
3  This class implements a QNetworkManager with the ability to chain in
4  own proxy factories.
5 
6  -------------------
7  begin : 2010-05-08
8  copyright : (C) 2010 by Juergen E. Fischer
9  email : jef at norbit dot de
10 
11 ***************************************************************************/
12 
13 /***************************************************************************
14  * *
15  * This program is free software; you can redistribute it and/or modify *
16  * it under the terms of the GNU General Public License as published by *
17  * the Free Software Foundation; either version 2 of the License, or *
18  * (at your option) any later version. *
19  * *
20  ***************************************************************************/
21 
23 
24 #include "qgsapplication.h"
25 #include "qgsmessagelog.h"
26 #include "qgslogger.h"
27 #include "qgis.h"
28 #include "qgssettings.h"
29 #include "qgsnetworkdiskcache.h"
30 #include "qgsauthmanager.h"
31 #include "qgsnetworkreply.h"
33 
34 #include <QUrl>
35 #include <QTimer>
36 #include <QBuffer>
37 #include <QNetworkReply>
38 #include <QThreadStorage>
39 #include <QAuthenticator>
40 #include <QStandardPaths>
41 
42 #ifndef QT_NO_SSL
43 #include <QSslConfiguration>
44 #endif
45 
46 #include "qgsnetworkdiskcache.h"
47 #include "qgsauthmanager.h"
48 
49 QgsNetworkAccessManager *QgsNetworkAccessManager::sMainNAM = nullptr;
50 
52 class QgsNetworkProxyFactory : public QNetworkProxyFactory
53 {
54  public:
55  QgsNetworkProxyFactory() = default;
56 
57  QList<QNetworkProxy> queryProxy( const QNetworkProxyQuery &query = QNetworkProxyQuery() ) override
58  {
60 
61  // iterate proxies factories and take first non empty list
62  const auto constProxyFactories = nam->proxyFactories();
63  for ( QNetworkProxyFactory *f : constProxyFactories )
64  {
65  QList<QNetworkProxy> systemproxies = f->systemProxyForQuery( query );
66  if ( !systemproxies.isEmpty() )
67  return systemproxies;
68 
69  QList<QNetworkProxy> proxies = f->queryProxy( query );
70  if ( !proxies.isEmpty() )
71  return proxies;
72  }
73 
74  // no proxies from the proxy factory list check for excludes
75  if ( query.queryType() != QNetworkProxyQuery::UrlRequest )
76  return QList<QNetworkProxy>() << nam->fallbackProxy();
77 
78  QString url = query.url().toString();
79 
80  const auto constNoProxyList = nam->noProxyList();
81  for ( const QString &noProxy : constNoProxyList )
82  {
83  if ( !noProxy.trimmed().isEmpty() && url.startsWith( noProxy ) )
84  {
85  QgsDebugMsgLevel( QStringLiteral( "don't using any proxy for %1 [exclude %2]" ).arg( url, noProxy ), 4 );
86  return QList<QNetworkProxy>() << QNetworkProxy( QNetworkProxy::NoProxy );
87  }
88  }
89 
90  const auto constExcludeList = nam->excludeList();
91  for ( const QString &exclude : constExcludeList )
92  {
93  if ( !exclude.trimmed().isEmpty() && url.startsWith( exclude ) )
94  {
95  QgsDebugMsgLevel( QStringLiteral( "using default proxy for %1 [exclude %2]" ).arg( url, exclude ), 4 );
96  return QList<QNetworkProxy>() << QNetworkProxy( QNetworkProxy::DefaultProxy );
97  }
98  }
99 
100  if ( nam->useSystemProxy() )
101  {
102  QgsDebugMsgLevel( QStringLiteral( "requesting system proxy for query %1" ).arg( url ), 4 );
103  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery( query );
104  if ( !proxies.isEmpty() )
105  {
106  QgsDebugMsgLevel( QStringLiteral( "using system proxy %1:%2 for query" )
107  .arg( proxies.first().hostName() ).arg( proxies.first().port() ), 4 );
108  return proxies;
109  }
110  }
111 
112  QgsDebugMsgLevel( QStringLiteral( "using fallback proxy for %1" ).arg( url ), 4 );
113  return QList<QNetworkProxy>() << nam->fallbackProxy();
114  }
115 };
117 
118 //
119 // Static calls to enforce singleton behavior
120 //
121 QgsNetworkAccessManager *QgsNetworkAccessManager::instance( Qt::ConnectionType connectionType )
122 {
123  static QThreadStorage<QgsNetworkAccessManager> sInstances;
124  QgsNetworkAccessManager *nam = &sInstances.localData();
125 
126  if ( nam->thread() == qApp->thread() )
127  sMainNAM = nam;
128 
129  if ( !nam->mInitialized )
130  nam->setupDefaultProxyAndCache( connectionType );
131 
132  return nam;
133 }
134 
136  : QNetworkAccessManager( parent )
137 {
138  setProxyFactory( new QgsNetworkProxyFactory() );
139 }
140 
141 void QgsNetworkAccessManager::setSslErrorHandler( std::unique_ptr<QgsSslErrorHandler> handler )
142 {
143  Q_ASSERT( sMainNAM == this );
144  mSslErrorHandler = std::move( handler );
145 }
146 
147 void QgsNetworkAccessManager::setAuthHandler( std::unique_ptr<QgsNetworkAuthenticationHandler> handler )
148 {
149  Q_ASSERT( sMainNAM == this );
150  mAuthHandler = std::move( handler );
151 }
152 
153 void QgsNetworkAccessManager::insertProxyFactory( QNetworkProxyFactory *factory )
154 {
155  mProxyFactories.insert( 0, factory );
156 }
157 
158 void QgsNetworkAccessManager::removeProxyFactory( QNetworkProxyFactory *factory )
159 {
160  mProxyFactories.removeAll( factory );
161 }
162 
163 const QList<QNetworkProxyFactory *> QgsNetworkAccessManager::proxyFactories() const
164 {
165  return mProxyFactories;
166 }
167 
169 {
170  return mExcludedURLs;
171 }
172 
174 {
175  return mNoProxyURLs;
176 }
177 
178 const QNetworkProxy &QgsNetworkAccessManager::fallbackProxy() const
179 {
180  return mFallbackProxy;
181 }
182 
183 void QgsNetworkAccessManager::setFallbackProxyAndExcludes( const QNetworkProxy &proxy, const QStringList &excludes, const QStringList &noProxyURLs )
184 {
185  QgsDebugMsgLevel( QStringLiteral( "proxy settings: (type:%1 host: %2:%3, user:%4, password:%5" )
186  .arg( proxy.type() == QNetworkProxy::DefaultProxy ? QStringLiteral( "DefaultProxy" ) :
187  proxy.type() == QNetworkProxy::Socks5Proxy ? QStringLiteral( "Socks5Proxy" ) :
188  proxy.type() == QNetworkProxy::NoProxy ? QStringLiteral( "NoProxy" ) :
189  proxy.type() == QNetworkProxy::HttpProxy ? QStringLiteral( "HttpProxy" ) :
190  proxy.type() == QNetworkProxy::HttpCachingProxy ? QStringLiteral( "HttpCachingProxy" ) :
191  proxy.type() == QNetworkProxy::FtpCachingProxy ? QStringLiteral( "FtpCachingProxy" ) :
192  QStringLiteral( "Undefined" ),
193  proxy.hostName() )
194  .arg( proxy.port() )
195  .arg( proxy.user(),
196  proxy.password().isEmpty() ? QStringLiteral( "not set" ) : QStringLiteral( "set" ) ), 4 );
197 
198  mFallbackProxy = proxy;
199  mExcludedURLs = excludes;
200  // remove empty records from excludes list -- these would otherwise match ANY url, so the proxy would always be skipped!
201  mExcludedURLs.erase( std::remove_if( mExcludedURLs.begin(), mExcludedURLs.end(), // clazy:exclude=detaching-member
202  []( const QString & url )
203  {
204  return url.trimmed().isEmpty();
205  } ), mExcludedURLs.end() ); // clazy:exclude=detaching-member
206 
207  mNoProxyURLs = noProxyURLs;
208  mNoProxyURLs.erase( std::remove_if( mNoProxyURLs.begin(), mNoProxyURLs.end(), // clazy:exclude=detaching-member
209  []( const QString & url )
210  {
211  return url.trimmed().isEmpty();
212  } ), mNoProxyURLs.end() ); // clazy:exclude=detaching-member
213 }
214 
215 QNetworkReply *QgsNetworkAccessManager::createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData )
216 {
217  QgsSettings s;
218 
219  QNetworkRequest *pReq( const_cast< QNetworkRequest * >( &req ) ); // hack user agent
220 
221  QString userAgent = s.value( QStringLiteral( "/qgis/networkAndProxy/userAgent" ), "Mozilla/5.0" ).toString();
222  if ( !userAgent.isEmpty() )
223  userAgent += ' ';
224  userAgent += QStringLiteral( "QGIS/%1" ).arg( Qgis::versionInt() );
225  pReq->setRawHeader( "User-Agent", userAgent.toLatin1() );
226 
227 #ifndef QT_NO_SSL
228  bool ishttps = pReq->url().scheme().compare( QLatin1String( "https" ), Qt::CaseInsensitive ) == 0;
229  if ( ishttps && !QgsApplication::authManager()->isDisabled() )
230  {
231  QgsDebugMsgLevel( QStringLiteral( "Adding trusted CA certs to request" ), 3 );
232  QSslConfiguration sslconfig( pReq->sslConfiguration() );
233  // Merge trusted CAs with any additional CAs added by the authentication methods
234  sslconfig.setCaCertificates( QgsAuthCertUtils::casMerge( QgsApplication::authManager()->trustedCaCertsCache(), sslconfig.caCertificates( ) ) );
235  // check for SSL cert custom config
236  QString hostport( QStringLiteral( "%1:%2" )
237  .arg( pReq->url().host().trimmed() )
238  .arg( pReq->url().port() != -1 ? pReq->url().port() : 443 ) );
240  if ( !servconfig.isNull() )
241  {
242  QgsDebugMsg( QStringLiteral( "Adding SSL custom config to request for %1" ).arg( hostport ) );
243  sslconfig.setProtocol( servconfig.sslProtocol() );
244  sslconfig.setPeerVerifyMode( servconfig.sslPeerVerifyMode() );
245  sslconfig.setPeerVerifyDepth( servconfig.sslPeerVerifyDepth() );
246  }
247 
248  pReq->setSslConfiguration( sslconfig );
249  }
250 #endif
251 
252  static QAtomicInt sRequestId = 0;
253  const int requestId = ++sRequestId;
254  QByteArray content;
255  if ( QBuffer *buffer = qobject_cast<QBuffer *>( outgoingData ) )
256  {
257  content = buffer->buffer();
258  }
259 
260  emit requestAboutToBeCreated( QgsNetworkRequestParameters( op, req, requestId, content ) );
262  emit requestAboutToBeCreated( op, req, outgoingData );
264  QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
265  reply->setProperty( "requestId", requestId );
266 
268  emit requestCreated( reply );
270 
271  connect( reply, &QNetworkReply::downloadProgress, this, &QgsNetworkAccessManager::onReplyDownloadProgress );
272 #ifndef QT_NO_SSL
273  connect( reply, &QNetworkReply::sslErrors, this, &QgsNetworkAccessManager::onReplySslErrors );
274 #endif
275 
276  // The timer will call abortRequest slot to abort the connection if needed.
277  // The timer is stopped by the finished signal and is restarted on downloadProgress and
278  // uploadProgress.
279  QTimer *timer = new QTimer( reply );
280  timer->setObjectName( QStringLiteral( "timeoutTimer" ) );
281  connect( timer, &QTimer::timeout, this, &QgsNetworkAccessManager::abortRequest );
282  timer->setSingleShot( true );
283  timer->start( timeout() );
284 
285  connect( reply, &QNetworkReply::downloadProgress, timer, [timer] { timer->start(); } );
286  connect( reply, &QNetworkReply::uploadProgress, timer, [timer] { timer->start(); } );
287  connect( reply, &QNetworkReply::finished, timer, &QTimer::stop );
288  QgsDebugMsgLevel( QStringLiteral( "Created [reply:%1]" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ), 3 );
289 
290  return reply;
291 }
292 
293 #ifndef QT_NO_SSL
294 void QgsNetworkAccessManager::unlockAfterSslErrorHandled()
295 {
296  Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
297  mSslErrorWaitCondition.wakeOne();
298 }
299 #endif
300 
301 void QgsNetworkAccessManager::abortRequest()
302 {
303  QTimer *timer = qobject_cast<QTimer *>( sender() );
304  Q_ASSERT( timer );
305 
306  QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
307  Q_ASSERT( reply );
308 
309  reply->abort();
310  QgsDebugMsgLevel( QStringLiteral( "Abort [reply:%1] %2" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ).arg( reply->url().toString() ), 3 );
311  QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
312  // Notify the application
313  emit requestTimedOut( QgsNetworkRequestParameters( reply->operation(), reply->request(), getRequestId( reply ) ) );
314  emit requestTimedOut( reply );
315 }
316 
317 void QgsNetworkAccessManager::onReplyFinished( QNetworkReply *reply )
318 {
319  emit finished( QgsNetworkReplyContent( reply ) );
320 }
321 
322 void QgsNetworkAccessManager::onReplyDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
323 {
324  if ( QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() ) )
325  {
326  emit downloadProgress( getRequestId( reply ), bytesReceived, bytesTotal );
327  }
328 }
329 
330 #ifndef QT_NO_SSL
331 void QgsNetworkAccessManager::onReplySslErrors( const QList<QSslError> &errors )
332 {
333  QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() );
334  Q_ASSERT( reply );
335  Q_ASSERT( reply->manager() == this );
336 
337  QgsDebugMsg( QStringLiteral( "Stopping network reply timeout whilst SSL error is handled" ) );
338  pauseTimeout( reply );
339 
340  emit requestEncounteredSslErrors( getRequestId( reply ), errors );
341 
342  // in main thread this will trigger SSL error handler immediately and return once the errors are handled,
343  // while in worker thread the signal will be queued (and return immediately) -- hence the need to lock the thread in the next block
344  emit sslErrorsOccurred( reply, errors );
345  if ( this != sMainNAM )
346  {
347  // lock thread and wait till error is handled. If we return from this slot now, then the reply will resume
348  // without actually giving the main thread the chance to act on the ssl error and possibly ignore it.
349  mSslErrorHandlerMutex.lock();
350  mSslErrorWaitCondition.wait( &mSslErrorHandlerMutex );
351  mSslErrorHandlerMutex.unlock();
352  afterSslErrorHandled( reply );
353  }
354 }
355 
356 void QgsNetworkAccessManager::afterSslErrorHandled( QNetworkReply *reply )
357 {
358  if ( reply->manager() == this )
359  {
360  restartTimeout( reply );
361  emit sslErrorsHandled( reply );
362  }
363  else if ( this == sMainNAM )
364  {
365  // notify other threads to allow them to handle the reply
366  qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterSslErrorHandled(); // safe to call directly - the other thread will be stuck waiting for us
367  }
368 }
369 
370 void QgsNetworkAccessManager::unlockAfterAuthRequestHandled()
371 {
372  Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
373  mAuthRequestWaitCondition.wakeOne();
374 }
375 
376 void QgsNetworkAccessManager::afterAuthRequestHandled( QNetworkReply *reply )
377 {
378  if ( reply->manager() == this )
379  {
380  restartTimeout( reply );
381  emit authRequestHandled( reply );
382  }
383  else if ( this == sMainNAM )
384  {
385  // notify other threads to allow them to handle the reply
386  qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterAuthRequestHandled(); // safe to call directly - the other thread will be stuck waiting for us
387  }
388 }
389 
390 void QgsNetworkAccessManager::pauseTimeout( QNetworkReply *reply )
391 {
392  Q_ASSERT( reply->manager() == this );
393 
394  QTimer *timer = reply->findChild<QTimer *>( QStringLiteral( "timeoutTimer" ) );
395  if ( timer && timer->isActive() )
396  {
397  timer->stop();
398  }
399 }
400 
401 void QgsNetworkAccessManager::restartTimeout( QNetworkReply *reply )
402 {
403  Q_ASSERT( reply->manager() == this );
404  // restart reply timeout
405  QTimer *timer = reply->findChild<QTimer *>( QStringLiteral( "timeoutTimer" ) );
406  if ( timer )
407  {
408  Q_ASSERT( !timer->isActive() );
409  QgsDebugMsg( QStringLiteral( "Restarting network reply timeout" ) );
410  timer->setSingleShot( true );
411  timer->start( timeout() );
412  }
413 }
414 
415 int QgsNetworkAccessManager::getRequestId( QNetworkReply *reply )
416 {
417  return reply->property( "requestId" ).toInt();
418 }
419 
420 void QgsNetworkAccessManager::handleSslErrors( QNetworkReply *reply, const QList<QSslError> &errors )
421 {
422  mSslErrorHandler->handleSslErrors( reply, errors );
423  afterSslErrorHandled( reply );
424 }
425 
426 #endif
427 
428 void QgsNetworkAccessManager::onAuthRequired( QNetworkReply *reply, QAuthenticator *auth )
429 {
430  Q_ASSERT( reply );
431  Q_ASSERT( reply->manager() == this );
432 
433  QgsDebugMsg( QStringLiteral( "Stopping network reply timeout whilst auth request is handled" ) );
434  pauseTimeout( reply );
435 
436  emit requestRequiresAuth( getRequestId( reply ), auth->realm() );
437 
438  // in main thread this will trigger auth handler immediately and return once the request is satisfied,
439  // while in worker thread the signal will be queued (and return immediately) -- hence the need to lock the thread in the next block
440  emit authRequestOccurred( reply, auth );
441 
442  if ( this != sMainNAM )
443  {
444  // lock thread and wait till error is handled. If we return from this slot now, then the reply will resume
445  // without actually giving the main thread the chance to act on the ssl error and possibly ignore it.
446  mAuthRequestHandlerMutex.lock();
447  mAuthRequestWaitCondition.wait( &mAuthRequestHandlerMutex );
448  mAuthRequestHandlerMutex.unlock();
449  afterAuthRequestHandled( reply );
450  }
451 }
452 
453 void QgsNetworkAccessManager::handleAuthRequest( QNetworkReply *reply, QAuthenticator *auth )
454 {
455  mAuthHandler->handleAuthRequest( reply, auth );
456 
457  emit requestAuthDetailsAdded( getRequestId( reply ), auth->realm(), auth->user(), auth->password() );
458 
459  afterAuthRequestHandled( reply );
460 }
461 
462 QString QgsNetworkAccessManager::cacheLoadControlName( QNetworkRequest::CacheLoadControl control )
463 {
464  switch ( control )
465  {
466  case QNetworkRequest::AlwaysNetwork:
467  return QStringLiteral( "AlwaysNetwork" );
468  case QNetworkRequest::PreferNetwork:
469  return QStringLiteral( "PreferNetwork" );
470  case QNetworkRequest::PreferCache:
471  return QStringLiteral( "PreferCache" );
472  case QNetworkRequest::AlwaysCache:
473  return QStringLiteral( "AlwaysCache" );
474  }
475  return QStringLiteral( "PreferNetwork" );
476 }
477 
478 QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromName( const QString &name )
479 {
480  if ( name == QLatin1String( "AlwaysNetwork" ) )
481  {
482  return QNetworkRequest::AlwaysNetwork;
483  }
484  else if ( name == QLatin1String( "PreferNetwork" ) )
485  {
486  return QNetworkRequest::PreferNetwork;
487  }
488  else if ( name == QLatin1String( "PreferCache" ) )
489  {
490  return QNetworkRequest::PreferCache;
491  }
492  else if ( name == QLatin1String( "AlwaysCache" ) )
493  {
494  return QNetworkRequest::AlwaysCache;
495  }
496  return QNetworkRequest::PreferNetwork;
497 }
498 
499 void QgsNetworkAccessManager::setupDefaultProxyAndCache( Qt::ConnectionType connectionType )
500 {
501  mInitialized = true;
502  mUseSystemProxy = false;
503 
504  Q_ASSERT( sMainNAM );
505 
506  if ( sMainNAM != this )
507  {
508  connect( this, &QNetworkAccessManager::proxyAuthenticationRequired,
509  sMainNAM, &QNetworkAccessManager::proxyAuthenticationRequired,
510  connectionType );
511 
512  connect( this, qgis::overload< QNetworkReply *>::of( &QgsNetworkAccessManager::requestTimedOut ),
513  sMainNAM, qgis::overload< QNetworkReply *>::of( &QgsNetworkAccessManager::requestTimedOut ) );
514 
515  connect( this, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestTimedOut ),
516  sMainNAM, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestTimedOut ) );
517 
518  connect( this, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestAboutToBeCreated ),
519  sMainNAM, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestAboutToBeCreated ) );
520 
521  connect( this, qgis::overload< QgsNetworkReplyContent >::of( &QgsNetworkAccessManager::finished ),
522  sMainNAM, qgis::overload< QgsNetworkReplyContent >::of( &QgsNetworkAccessManager::finished ) );
523 
525 
526 #ifndef QT_NO_SSL
527  connect( this, &QNetworkAccessManager::sslErrors,
528  sMainNAM, &QNetworkAccessManager::sslErrors,
529  connectionType );
530 
532 #endif
533 
535  }
536  else
537  {
538 #ifndef QT_NO_SSL
539  setSslErrorHandler( qgis::make_unique< QgsSslErrorHandler >() );
540 #endif
541  setAuthHandler( qgis::make_unique< QgsNetworkAuthenticationHandler>() );
542  }
543 #ifndef QT_NO_SSL
544  connect( this, &QgsNetworkAccessManager::sslErrorsOccurred, sMainNAM, &QgsNetworkAccessManager::handleSslErrors );
545 #endif
546  connect( this, &QNetworkAccessManager::authenticationRequired, this, &QgsNetworkAccessManager::onAuthRequired );
547  connect( this, &QgsNetworkAccessManager::authRequestOccurred, sMainNAM, &QgsNetworkAccessManager::handleAuthRequest );
548 
549  connect( this, &QNetworkAccessManager::finished, this, &QgsNetworkAccessManager::onReplyFinished );
550 
551  // check if proxy is enabled
552  QgsSettings settings;
553  QNetworkProxy proxy;
554  QStringList excludes;
555  QStringList noProxyURLs;
556 
557  bool proxyEnabled = settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool();
558  if ( proxyEnabled )
559  {
560  // This settings is keep for retrocompatibility, the returned proxy for these URL is the default one,
561  // meaning the system one
562  excludes = settings.value( QStringLiteral( "proxy/proxyExcludedUrls" ), QStringList() ).toStringList();
563 
564  noProxyURLs = settings.value( QStringLiteral( "proxy/noProxyUrls" ), QStringList() ).toStringList();
565 
566  //read type, host, port, user, passw from settings
567  QString proxyHost = settings.value( QStringLiteral( "proxy/proxyHost" ), "" ).toString();
568  int proxyPort = settings.value( QStringLiteral( "proxy/proxyPort" ), "" ).toString().toInt();
569 
570  QString proxyUser = settings.value( QStringLiteral( "proxy/proxyUser" ), "" ).toString();
571  QString proxyPassword = settings.value( QStringLiteral( "proxy/proxyPassword" ), "" ).toString();
572 
573  QString proxyTypeString = settings.value( QStringLiteral( "proxy/proxyType" ), "" ).toString();
574 
575  if ( proxyTypeString == QLatin1String( "DefaultProxy" ) )
576  {
577  mUseSystemProxy = true;
578  QNetworkProxyFactory::setUseSystemConfiguration( true );
579  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
580  if ( !proxies.isEmpty() )
581  {
582  proxy = proxies.first();
583  }
584  QgsDebugMsgLevel( QStringLiteral( "setting default proxy" ), 4 );
585  }
586  else
587  {
588  QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
589  if ( proxyTypeString == QLatin1String( "Socks5Proxy" ) )
590  {
591  proxyType = QNetworkProxy::Socks5Proxy;
592  }
593  else if ( proxyTypeString == QLatin1String( "HttpProxy" ) )
594  {
595  proxyType = QNetworkProxy::HttpProxy;
596  }
597  else if ( proxyTypeString == QLatin1String( "HttpCachingProxy" ) )
598  {
599  proxyType = QNetworkProxy::HttpCachingProxy;
600  }
601  else if ( proxyTypeString == QLatin1String( "FtpCachingProxy" ) )
602  {
603  proxyType = QNetworkProxy::FtpCachingProxy;
604  }
605  QgsDebugMsg( QStringLiteral( "setting proxy %1 %2:%3 %4/%5" )
606  .arg( proxyType )
607  .arg( proxyHost ).arg( proxyPort )
608  .arg( proxyUser, proxyPassword )
609  );
610  proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
611  }
612  // Setup network proxy authentication configuration
613  QString authcfg = settings.value( QStringLiteral( "proxy/authcfg" ), "" ).toString();
614  if ( !authcfg.isEmpty( ) )
615  {
616  QgsDebugMsg( QStringLiteral( "setting proxy from stored authentication configuration %1" ).arg( authcfg ) );
617  // Never crash! Never.
619  QgsApplication::authManager()->updateNetworkProxy( proxy, authcfg );
620  }
621  }
622 
623  setFallbackProxyAndExcludes( proxy, excludes, noProxyURLs );
624 
625  QgsNetworkDiskCache *newcache = qobject_cast<QgsNetworkDiskCache *>( cache() );
626  if ( !newcache )
627  newcache = new QgsNetworkDiskCache( this );
628 
629  QString cacheDirectory = settings.value( QStringLiteral( "cache/directory" ) ).toString();
630  if ( cacheDirectory.isEmpty() )
631  cacheDirectory = QStandardPaths::writableLocation( QStandardPaths::CacheLocation );
632  qint64 cacheSize = settings.value( QStringLiteral( "cache/size" ), 50 * 1024 * 1024 ).toLongLong();
633  newcache->setCacheDirectory( cacheDirectory );
634  newcache->setMaximumCacheSize( cacheSize );
635  QgsDebugMsgLevel( QStringLiteral( "cacheDirectory: %1" ).arg( newcache->cacheDirectory() ), 4 );
636  QgsDebugMsgLevel( QStringLiteral( "maximumCacheSize: %1" ).arg( newcache->maximumCacheSize() ), 4 );
637 
638  if ( cache() != newcache )
639  setCache( newcache );
640 }
641 
643 {
644  return QgsSettings().value( QStringLiteral( "/qgis/networkAndProxy/networkTimeout" ), 60000 ).toInt();
645 }
646 
648 {
649  QgsSettings().setValue( QStringLiteral( "/qgis/networkAndProxy/networkTimeout" ), time );
650 }
651 
652 QgsNetworkReplyContent QgsNetworkAccessManager::blockingGet( QNetworkRequest &request, const QString &authCfg, bool forceRefresh, QgsFeedback *feedback )
653 {
655  br.setAuthCfg( authCfg );
656  br.get( request, forceRefresh, feedback );
657  return br.reply();
658 }
659 
660 QgsNetworkReplyContent QgsNetworkAccessManager::blockingPost( QNetworkRequest &request, const QByteArray &data, const QString &authCfg, bool forceRefresh, QgsFeedback *feedback )
661 {
663  br.setAuthCfg( authCfg );
664  br.post( request, data, forceRefresh, feedback );
665  return br.reply();
666 }
667 
668 
669 //
670 // QgsNetworkRequestParameters
671 //
672 
673 QgsNetworkRequestParameters::QgsNetworkRequestParameters( QNetworkAccessManager::Operation operation, const QNetworkRequest &request, int requestId, const QByteArray &content )
674  : mOperation( operation )
675  , mRequest( request )
676  , mOriginatingThreadId( QStringLiteral( "0x%2" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char( '0' ) ) )
677  , mRequestId( requestId )
678  , mContent( content )
679  , mInitiatorClass( request.attribute( static_cast< QNetworkRequest::Attribute >( QgsNetworkRequestParameters::AttributeInitiatorClass ) ).toString() )
680  , mInitiatorRequestId( request.attribute( static_cast< QNetworkRequest::Attribute >( QgsNetworkRequestParameters::AttributeInitiatorRequestId ) ) )
681 {
682 }
683 
684 
685 //
686 // QgsSslErrorHandler
687 //
688 
689 void QgsSslErrorHandler::handleSslErrors( QNetworkReply *reply, const QList<QSslError> & )
690 {
691  Q_UNUSED( reply )
692  QgsDebugMsg( QStringLiteral( "SSL errors occurred accessing URL:\n%1" ).arg( reply->request().url().toString() ) );
693 }
694 
695 //
696 // QgsNetworkAuthenticationHandler
697 //
698 
699 void QgsNetworkAuthenticationHandler::handleAuthRequest( QNetworkReply *reply, QAuthenticator * )
700 {
701  Q_UNUSED( reply )
702  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() ) );
703 }
QgsNetworkAccessManager::setTimeout
static void setTimeout(int time)
Sets the maximum timeout time for network requests, in milliseconds.
Definition: qgsnetworkaccessmanager.cpp:647
QgsNetworkAccessManager::requestTimedOut
void requestTimedOut(QgsNetworkRequestParameters request)
Emitted when a network request has timed out.
QgsNetworkDiskCache
Wrapper implementation of QNetworkDiskCache with all methods guarded by a mutex soly for internal use...
Definition: qgsnetworkdiskcache.h:49
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsNetworkAuthenticationHandler::handleAuthRequest
virtual void handleAuthRequest(QNetworkReply *reply, QAuthenticator *auth)
Called whenever network authentication requests are encountered during a network reply.
Definition: qgsnetworkaccessmanager.cpp:699
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsNetworkAccessManager::cacheLoadControlName
static QString cacheLoadControlName(QNetworkRequest::CacheLoadControl control)
Returns the name for QNetworkRequest::CacheLoadControl.
Definition: qgsnetworkaccessmanager.cpp:462
QgsSslErrorHandler::handleSslErrors
virtual void handleSslErrors(QNetworkReply *reply, const QList< QSslError > &errors)
Called whenever SSL errors are encountered during a network reply.
Definition: qgsnetworkaccessmanager.cpp:689
qgsauthmanager.h
qgsblockingnetworkrequest.h
QgsNetworkAccessManager::requestCreated
Q_DECL_DEPRECATED void requestCreated(QNetworkReply *)
QgsBlockingNetworkRequest::reply
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get() or post() request has been made.
Definition: qgsblockingnetworkrequest.h:117
QgsNetworkDiskCache::cacheDirectory
QString cacheDirectory() const
Definition: qgsnetworkdiskcache.cpp:31
QgsNetworkAccessManager::excludeList
QStringList excludeList() const
Returns the proxy exclude list.
Definition: qgsnetworkaccessmanager.cpp:168
qgis.h
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsNetworkRequestParameters::QgsNetworkRequestParameters
QgsNetworkRequestParameters()=default
Default constructor.
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsNetworkAccessManager::QgsNetworkAccessManager
QgsNetworkAccessManager(QObject *parent=nullptr)
Definition: qgsnetworkaccessmanager.cpp:135
QgsApplication::authManager
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
Definition: qgsapplication.cpp:1282
QgsNetworkAccessManager::createRequest
QNetworkReply * createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData=nullptr) override
Definition: qgsnetworkaccessmanager.cpp:215
qgsapplication.h
QgsNetworkAccessManager::cacheLoadControlFromName
static QNetworkRequest::CacheLoadControl cacheLoadControlFromName(const QString &name)
Returns QNetworkRequest::CacheLoadControl from a name.
Definition: qgsnetworkaccessmanager.cpp:478
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:797
QgsNetworkRequestParameters
Encapsulates parameters and properties of a network request.
Definition: qgsnetworkaccessmanager.h:52
QgsNetworkAccessManager::finished
void finished(QgsNetworkReplyContent reply)
Emitted whenever a pending network reply is finished.
QgsNetworkDiskCache::setMaximumCacheSize
void setMaximumCacheSize(qint64 size)
Definition: qgsnetworkdiskcache.cpp:49
QgsAuthConfigSslServer::sslPeerVerifyDepth
int sslPeerVerifyDepth() const
Number or SSL client's peer to verify in connections.
Definition: qgsauthconfig.h:408
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsAuthCertUtils::casMerge
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...
Definition: qgsauthcertutils.cpp:156
qgsnetworkaccessmanager.h
QgsNetworkDiskCache::setCacheDirectory
void setCacheDirectory(const QString &cacheDir)
Definition: qgsnetworkdiskcache.cpp:37
QgsBlockingNetworkRequest::setAuthCfg
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
Definition: qgsblockingnetworkrequest.cpp:52
QgsAuthManager::sslCertCustomConfigByHost
const QgsAuthConfigSslServer sslCertCustomConfigByHost(const QString &hostport)
sslCertCustomConfigByHost get an SSL certificate custom config by hostport (host:port)
Definition: qgsauthmanager.cpp:2066
QgsNetworkAccessManager::insertProxyFactory
void insertProxyFactory(QNetworkProxyFactory *factory)
Inserts a factory into the proxy factories list.
Definition: qgsnetworkaccessmanager.cpp:153
QgsNetworkAccessManager::requestAboutToBeCreated
Q_DECL_DEPRECATED void requestAboutToBeCreated(QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice *)
QgsNetworkAccessManager::removeProxyFactory
void removeProxyFactory(QNetworkProxyFactory *factory)
Removes a factory from the proxy factories list.
Definition: qgsnetworkaccessmanager.cpp:158
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsNetworkAccessManager::setFallbackProxyAndExcludes
void setFallbackProxyAndExcludes(const QNetworkProxy &proxy, const QStringList &excludes, const QStringList &noProxyURLs)
Sets the fallback proxy and URLs which shouldn't use it.
Definition: qgsnetworkaccessmanager.cpp:183
QgsNetworkAccessManager
network access manager for QGIS
Definition: qgsnetworkaccessmanager.h:252
QgsNetworkAccessManager::requestAuthDetailsAdded
void requestAuthDetailsAdded(int requestId, const QString &realm, const QString &user, const QString &password)
Emitted when network authentication details have been added to a request.
QgsNetworkAccessManager::instance
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Definition: qgsnetworkaccessmanager.cpp:121
QgsNetworkDiskCache::maximumCacheSize
qint64 maximumCacheSize() const
Definition: qgsnetworkdiskcache.cpp:43
QgsNetworkAccessManager::setupDefaultProxyAndCache
void setupDefaultProxyAndCache(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Setup the QgsNetworkAccessManager (NAM) according to the user's settings.
Definition: qgsnetworkaccessmanager.cpp:499
QgsNetworkAccessManager::requestEncounteredSslErrors
void requestEncounteredSslErrors(int requestId, const QList< QSslError > &errors)
Emitted when a network request encounters SSL errors.
QgsNetworkAccessManager::setSslErrorHandler
void setSslErrorHandler(std::unique_ptr< QgsSslErrorHandler > handler)
Sets the application SSL error handler, which is used to respond to SSL errors encountered during net...
Definition: qgsnetworkaccessmanager.cpp:141
QgsBlockingNetworkRequest::get
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
Definition: qgsblockingnetworkrequest.cpp:57
qgsnetworkdiskcache.h
qgsnetworkreply.h
QgsBlockingNetworkRequest::post
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.
Definition: qgsblockingnetworkrequest.cpp:62
qgssettings.h
QgsAuthConfigSslServer::isNull
bool isNull() const
Whether configuration is null (missing components)
Definition: qgsauthconfig.cpp:386
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
QgsAuthConfigSslServer::sslPeerVerifyMode
QSslSocket::PeerVerifyMode sslPeerVerifyMode() const
SSL client's peer verify mode to use in connections.
Definition: qgsauthconfig.h:400
QgsAuthConfigSslServer
Configuration container for SSL server connection exceptions or overrides.
Definition: qgsauthconfig.h:372
QgsNetworkAccessManager::timeout
static int timeout()
Returns the network timeout length, in milliseconds.
Definition: qgsnetworkaccessmanager.cpp:642
QgsNetworkReplyContent
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
Definition: qgsnetworkreply.h:29
QgsNetworkAccessManager::fallbackProxy
const QNetworkProxy & fallbackProxy() const
Returns the fallback proxy used by the manager.
Definition: qgsnetworkaccessmanager.cpp:178
QgsNetworkAccessManager::setAuthHandler
void setAuthHandler(std::unique_ptr< QgsNetworkAuthenticationHandler > handler)
Sets the application network authentication handler, which is used to respond to network authenticati...
Definition: qgsnetworkaccessmanager.cpp:147
QgsAuthConfigSslServer::sslProtocol
QSsl::SslProtocol sslProtocol() const
SSL server protocol to use in connections.
Definition: qgsauthconfig.h:388
QgsNetworkAccessManager::downloadProgress
void downloadProgress(int requestId, qint64 bytesReceived, qint64 bytesTotal)
Emitted when a network reply receives a progress report.
qgslogger.h
QgsNetworkAccessManager::blockingGet
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...
Definition: qgsnetworkaccessmanager.cpp:652
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:796
QgsNetworkAccessManager::useSystemProxy
bool useSystemProxy() const
Returns whether the system proxy should be used.
Definition: qgsnetworkaccessmanager.h:415
Qgis::versionInt
static int versionInt()
Version number used for comparing versions using the "Check QGIS Version" function.
Definition: qgis.cpp:281
QgsNetworkAccessManager::requestRequiresAuth
void requestRequiresAuth(int requestId, const QString &realm)
Emitted when a network request prompts an authentication request.
QgsNetworkAccessManager::blockingPost
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,...
Definition: qgsnetworkaccessmanager.cpp:660
QgsBlockingNetworkRequest
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
Definition: qgsblockingnetworkrequest.h:47
QgsNetworkAccessManager::proxyFactories
const QList< QNetworkProxyFactory * > proxyFactories() const
Returns a list of proxy factories used by the manager.
Definition: qgsnetworkaccessmanager.cpp:163
QgsNetworkAccessManager::noProxyList
QStringList noProxyList() const
Returns the no proxy list.
Definition: qgsnetworkaccessmanager.cpp:173
qgsmessagelog.h
QgsAuthManager::updateNetworkProxy
bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkProxy with an authentication config.
Definition: qgsauthmanager.cpp:1535