QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  {
131  nam->setupDefaultProxyAndCache( connectionType );
132  nam->setCacheDisabled( sMainNAM->cacheDisabled() );
133  }
134 
135  return nam;
136 }
137 
139  : QNetworkAccessManager( parent )
140 {
141  setProxyFactory( new QgsNetworkProxyFactory() );
142 }
143 
144 void QgsNetworkAccessManager::setSslErrorHandler( std::unique_ptr<QgsSslErrorHandler> handler )
145 {
146  Q_ASSERT( sMainNAM == this );
147  mSslErrorHandler = std::move( handler );
148 }
149 
150 void QgsNetworkAccessManager::setAuthHandler( std::unique_ptr<QgsNetworkAuthenticationHandler> handler )
151 {
152  Q_ASSERT( sMainNAM == this );
153  mAuthHandler = std::move( handler );
154 }
155 
156 void QgsNetworkAccessManager::insertProxyFactory( QNetworkProxyFactory *factory )
157 {
158  mProxyFactories.insert( 0, factory );
159 }
160 
161 void QgsNetworkAccessManager::removeProxyFactory( QNetworkProxyFactory *factory )
162 {
163  mProxyFactories.removeAll( factory );
164 }
165 
166 const QList<QNetworkProxyFactory *> QgsNetworkAccessManager::proxyFactories() const
167 {
168  return mProxyFactories;
169 }
170 
172 {
173  return mExcludedURLs;
174 }
175 
177 {
178  return mNoProxyURLs;
179 }
180 
181 const QNetworkProxy &QgsNetworkAccessManager::fallbackProxy() const
182 {
183  return mFallbackProxy;
184 }
185 
186 void QgsNetworkAccessManager::setFallbackProxyAndExcludes( const QNetworkProxy &proxy, const QStringList &excludes, const QStringList &noProxyURLs )
187 {
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" ),
196  proxy.hostName() )
197  .arg( proxy.port() )
198  .arg( proxy.user(),
199  proxy.password().isEmpty() ? QStringLiteral( "not set" ) : QStringLiteral( "set" ) ), 4 );
200 
201  mFallbackProxy = proxy;
202  mExcludedURLs = excludes;
203  // remove empty records from excludes list -- these would otherwise match ANY url, so the proxy would always be skipped!
204  mExcludedURLs.erase( std::remove_if( mExcludedURLs.begin(), mExcludedURLs.end(), // clazy:exclude=detaching-member
205  []( const QString & url )
206  {
207  return url.trimmed().isEmpty();
208  } ), mExcludedURLs.end() ); // clazy:exclude=detaching-member
209 
210  mNoProxyURLs = noProxyURLs;
211  mNoProxyURLs.erase( std::remove_if( mNoProxyURLs.begin(), mNoProxyURLs.end(), // clazy:exclude=detaching-member
212  []( const QString & url )
213  {
214  return url.trimmed().isEmpty();
215  } ), mNoProxyURLs.end() ); // clazy:exclude=detaching-member
216 }
217 
218 QNetworkReply *QgsNetworkAccessManager::createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData )
219 {
220  QgsSettings s;
221 
222  QNetworkRequest *pReq( const_cast< QNetworkRequest * >( &req ) ); // hack user agent
223 
224  QString userAgent = s.value( QStringLiteral( "/qgis/networkAndProxy/userAgent" ), "Mozilla/5.0" ).toString();
225  if ( !userAgent.isEmpty() )
226  userAgent += ' ';
227  userAgent += QStringLiteral( "QGIS/%1" ).arg( Qgis::versionInt() );
228  pReq->setRawHeader( "User-Agent", userAgent.toLatin1() );
229 
230 #ifndef QT_NO_SSL
231  bool ishttps = pReq->url().scheme().compare( QLatin1String( "https" ), Qt::CaseInsensitive ) == 0;
232  if ( ishttps && !QgsApplication::authManager()->isDisabled() )
233  {
234  QgsDebugMsgLevel( QStringLiteral( "Adding trusted CA certs to request" ), 3 );
235  QSslConfiguration sslconfig( pReq->sslConfiguration() );
236  // Merge trusted CAs with any additional CAs added by the authentication methods
237  sslconfig.setCaCertificates( QgsAuthCertUtils::casMerge( QgsApplication::authManager()->trustedCaCertsCache(), sslconfig.caCertificates( ) ) );
238  // check for SSL cert custom config
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() )
244  {
245  QgsDebugMsg( QStringLiteral( "Adding SSL custom config to request for %1" ).arg( hostport ) );
246  sslconfig.setProtocol( servconfig.sslProtocol() );
247  sslconfig.setPeerVerifyMode( servconfig.sslPeerVerifyMode() );
248  sslconfig.setPeerVerifyDepth( servconfig.sslPeerVerifyDepth() );
249  }
250 
251  pReq->setSslConfiguration( sslconfig );
252  }
253 #endif
254 
255  if ( sMainNAM->mCacheDisabled )
256  {
257  // if caching is disabled then we override whatever the request actually has set!
258  pReq->setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
259  pReq->setAttribute( QNetworkRequest::CacheSaveControlAttribute, false );
260  }
261 
262  static QAtomicInt sRequestId = 0;
263  const int requestId = ++sRequestId;
264  QByteArray content;
265  if ( QBuffer *buffer = qobject_cast<QBuffer *>( outgoingData ) )
266  {
267  content = buffer->buffer();
268  }
269 
270  emit requestAboutToBeCreated( QgsNetworkRequestParameters( op, req, requestId, content ) );
272  emit requestAboutToBeCreated( op, req, outgoingData );
274  QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
275  reply->setProperty( "requestId", requestId );
276 
278  emit requestCreated( reply );
280 
281  connect( reply, &QNetworkReply::downloadProgress, this, &QgsNetworkAccessManager::onReplyDownloadProgress );
282 #ifndef QT_NO_SSL
283  connect( reply, &QNetworkReply::sslErrors, this, &QgsNetworkAccessManager::onReplySslErrors );
284 #endif
285 
286  // The timer will call abortRequest slot to abort the connection if needed.
287  // The timer is stopped by the finished signal and is restarted on downloadProgress and
288  // uploadProgress.
289  if ( timeout() )
290  {
291  QTimer *timer = new QTimer( reply );
292  timer->setObjectName( QStringLiteral( "timeoutTimer" ) );
293  connect( timer, &QTimer::timeout, this, &QgsNetworkAccessManager::abortRequest );
294  timer->setSingleShot( true );
295  timer->start( timeout() );
296 
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 );
300  }
301  QgsDebugMsgLevel( QStringLiteral( "Created [reply:%1]" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ), 3 );
302 
303  return reply;
304 }
305 
306 #ifndef QT_NO_SSL
307 void QgsNetworkAccessManager::unlockAfterSslErrorHandled()
308 {
309  Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
310  mSslErrorWaitCondition.wakeOne();
311 }
312 #endif
313 
314 void QgsNetworkAccessManager::abortRequest()
315 {
316  QTimer *timer = qobject_cast<QTimer *>( sender() );
317  Q_ASSERT( timer );
318 
319  QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
320  Q_ASSERT( reply );
321 
322  reply->abort();
323  QgsDebugMsgLevel( QStringLiteral( "Abort [reply:%1] %2" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ).arg( reply->url().toString() ), 3 );
324  QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
325  // Notify the application
326  emit requestTimedOut( QgsNetworkRequestParameters( reply->operation(), reply->request(), getRequestId( reply ) ) );
327  emit requestTimedOut( reply );
328 }
329 
330 void QgsNetworkAccessManager::onReplyFinished( QNetworkReply *reply )
331 {
332  emit finished( QgsNetworkReplyContent( reply ) );
333 }
334 
335 void QgsNetworkAccessManager::onReplyDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
336 {
337  if ( QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() ) )
338  {
339  emit downloadProgress( getRequestId( reply ), bytesReceived, bytesTotal );
340  }
341 }
342 
343 #ifndef QT_NO_SSL
344 void QgsNetworkAccessManager::onReplySslErrors( const QList<QSslError> &errors )
345 {
346  QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() );
347  Q_ASSERT( reply );
348  Q_ASSERT( reply->manager() == this );
349 
350  QgsDebugMsg( QStringLiteral( "Stopping network reply timeout whilst SSL error is handled" ) );
351  pauseTimeout( reply );
352 
353  emit requestEncounteredSslErrors( getRequestId( reply ), errors );
354 
355  // in main thread this will trigger SSL error handler immediately and return once the errors are handled,
356  // while in worker thread the signal will be queued (and return immediately) -- hence the need to lock the thread in the next block
357  emit sslErrorsOccurred( reply, errors );
358  if ( this != sMainNAM )
359  {
360  // lock thread and wait till error is handled. If we return from this slot now, then the reply will resume
361  // without actually giving the main thread the chance to act on the ssl error and possibly ignore it.
362  mSslErrorHandlerMutex.lock();
363  mSslErrorWaitCondition.wait( &mSslErrorHandlerMutex );
364  mSslErrorHandlerMutex.unlock();
365  afterSslErrorHandled( reply );
366  }
367 }
368 
369 void QgsNetworkAccessManager::afterSslErrorHandled( QNetworkReply *reply )
370 {
371  if ( reply->manager() == this )
372  {
373  restartTimeout( reply );
374  emit sslErrorsHandled( reply );
375  }
376  else if ( this == sMainNAM )
377  {
378  // notify other threads to allow them to handle the reply
379  qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterSslErrorHandled(); // safe to call directly - the other thread will be stuck waiting for us
380  }
381 }
382 
383 void QgsNetworkAccessManager::unlockAfterAuthRequestHandled()
384 {
385  Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
386  mAuthRequestWaitCondition.wakeOne();
387 }
388 
389 void QgsNetworkAccessManager::afterAuthRequestHandled( QNetworkReply *reply )
390 {
391  if ( reply->manager() == this )
392  {
393  restartTimeout( reply );
394  emit authRequestHandled( reply );
395  }
396  else if ( this == sMainNAM )
397  {
398  // notify other threads to allow them to handle the reply
399  qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterAuthRequestHandled(); // safe to call directly - the other thread will be stuck waiting for us
400  }
401 }
402 
403 void QgsNetworkAccessManager::pauseTimeout( QNetworkReply *reply )
404 {
405  Q_ASSERT( reply->manager() == this );
406 
407  QTimer *timer = reply->findChild<QTimer *>( QStringLiteral( "timeoutTimer" ) );
408  if ( timer && timer->isActive() )
409  {
410  timer->stop();
411  }
412 }
413 
414 void QgsNetworkAccessManager::restartTimeout( QNetworkReply *reply )
415 {
416  Q_ASSERT( reply->manager() == this );
417  // restart reply timeout
418  QTimer *timer = reply->findChild<QTimer *>( QStringLiteral( "timeoutTimer" ) );
419  if ( timer )
420  {
421  Q_ASSERT( !timer->isActive() );
422  QgsDebugMsg( QStringLiteral( "Restarting network reply timeout" ) );
423  timer->setSingleShot( true );
424  timer->start( timeout() );
425  }
426 }
427 
428 int QgsNetworkAccessManager::getRequestId( QNetworkReply *reply )
429 {
430  return reply->property( "requestId" ).toInt();
431 }
432 
433 void QgsNetworkAccessManager::handleSslErrors( QNetworkReply *reply, const QList<QSslError> &errors )
434 {
435  mSslErrorHandler->handleSslErrors( reply, errors );
436  afterSslErrorHandled( reply );
437 }
438 
439 #endif
440 
441 void QgsNetworkAccessManager::onAuthRequired( QNetworkReply *reply, QAuthenticator *auth )
442 {
443  Q_ASSERT( reply );
444  Q_ASSERT( reply->manager() == this );
445 
446  QgsDebugMsg( QStringLiteral( "Stopping network reply timeout whilst auth request is handled" ) );
447  pauseTimeout( reply );
448 
449  emit requestRequiresAuth( getRequestId( reply ), auth->realm() );
450 
451  // in main thread this will trigger auth handler immediately and return once the request is satisfied,
452  // while in worker thread the signal will be queued (and return immediately) -- hence the need to lock the thread in the next block
453  emit authRequestOccurred( reply, auth );
454 
455  if ( this != sMainNAM )
456  {
457  // lock thread and wait till error is handled. If we return from this slot now, then the reply will resume
458  // without actually giving the main thread the chance to act on the ssl error and possibly ignore it.
459  mAuthRequestHandlerMutex.lock();
460  mAuthRequestWaitCondition.wait( &mAuthRequestHandlerMutex );
461  mAuthRequestHandlerMutex.unlock();
462  afterAuthRequestHandled( reply );
463  }
464 }
465 
466 void QgsNetworkAccessManager::handleAuthRequest( QNetworkReply *reply, QAuthenticator *auth )
467 {
468  mAuthHandler->handleAuthRequest( reply, auth );
469 
470  emit requestAuthDetailsAdded( getRequestId( reply ), auth->realm(), auth->user(), auth->password() );
471 
472  afterAuthRequestHandled( reply );
473 }
474 
475 QString QgsNetworkAccessManager::cacheLoadControlName( QNetworkRequest::CacheLoadControl control )
476 {
477  switch ( control )
478  {
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" );
487  }
488  return QStringLiteral( "PreferNetwork" );
489 }
490 
491 QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromName( const QString &name )
492 {
493  if ( name == QLatin1String( "AlwaysNetwork" ) )
494  {
495  return QNetworkRequest::AlwaysNetwork;
496  }
497  else if ( name == QLatin1String( "PreferNetwork" ) )
498  {
499  return QNetworkRequest::PreferNetwork;
500  }
501  else if ( name == QLatin1String( "PreferCache" ) )
502  {
503  return QNetworkRequest::PreferCache;
504  }
505  else if ( name == QLatin1String( "AlwaysCache" ) )
506  {
507  return QNetworkRequest::AlwaysCache;
508  }
509  return QNetworkRequest::PreferNetwork;
510 }
511 
512 void QgsNetworkAccessManager::setupDefaultProxyAndCache( Qt::ConnectionType connectionType )
513 {
514  mInitialized = true;
515  mUseSystemProxy = false;
516 
517  Q_ASSERT( sMainNAM );
518 
519  if ( sMainNAM != this )
520  {
521  connect( this, &QNetworkAccessManager::proxyAuthenticationRequired,
522  sMainNAM, &QNetworkAccessManager::proxyAuthenticationRequired,
523  connectionType );
524 
525  connect( this, qgis::overload< QNetworkReply *>::of( &QgsNetworkAccessManager::requestTimedOut ),
526  sMainNAM, qgis::overload< QNetworkReply *>::of( &QgsNetworkAccessManager::requestTimedOut ) );
527 
528  connect( this, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestTimedOut ),
529  sMainNAM, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestTimedOut ) );
530 
531  connect( this, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestAboutToBeCreated ),
532  sMainNAM, qgis::overload< QgsNetworkRequestParameters >::of( &QgsNetworkAccessManager::requestAboutToBeCreated ) );
533 
534  connect( this, qgis::overload< QgsNetworkReplyContent >::of( &QgsNetworkAccessManager::finished ),
535  sMainNAM, qgis::overload< QgsNetworkReplyContent >::of( &QgsNetworkAccessManager::finished ) );
536 
538 
539 #ifndef QT_NO_SSL
540  connect( this, &QNetworkAccessManager::sslErrors,
541  sMainNAM, &QNetworkAccessManager::sslErrors,
542  connectionType );
543 
545 #endif
546 
548  }
549  else
550  {
551 #ifndef QT_NO_SSL
552  setSslErrorHandler( qgis::make_unique< QgsSslErrorHandler >() );
553 #endif
554  setAuthHandler( qgis::make_unique< QgsNetworkAuthenticationHandler>() );
555  }
556 #ifndef QT_NO_SSL
557  connect( this, &QgsNetworkAccessManager::sslErrorsOccurred, sMainNAM, &QgsNetworkAccessManager::handleSslErrors );
558 #endif
559  connect( this, &QNetworkAccessManager::authenticationRequired, this, &QgsNetworkAccessManager::onAuthRequired );
560  connect( this, &QgsNetworkAccessManager::authRequestOccurred, sMainNAM, &QgsNetworkAccessManager::handleAuthRequest );
561 
562  connect( this, &QNetworkAccessManager::finished, this, &QgsNetworkAccessManager::onReplyFinished );
563 
564  // check if proxy is enabled
565  QgsSettings settings;
566  QNetworkProxy proxy;
567  QStringList excludes;
568  QStringList noProxyURLs;
569 
570  bool proxyEnabled = settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool();
571  if ( proxyEnabled )
572  {
573  // This settings is keep for retrocompatibility, the returned proxy for these URL is the default one,
574  // meaning the system one
575  excludes = settings.value( QStringLiteral( "proxy/proxyExcludedUrls" ), QStringList() ).toStringList();
576 
577  noProxyURLs = settings.value( QStringLiteral( "proxy/noProxyUrls" ), QStringList() ).toStringList();
578 
579  //read type, host, port, user, passw from settings
580  QString proxyHost = settings.value( QStringLiteral( "proxy/proxyHost" ), "" ).toString();
581  int proxyPort = settings.value( QStringLiteral( "proxy/proxyPort" ), "" ).toString().toInt();
582 
583  QString proxyUser = settings.value( QStringLiteral( "proxy/proxyUser" ), "" ).toString();
584  QString proxyPassword = settings.value( QStringLiteral( "proxy/proxyPassword" ), "" ).toString();
585 
586  QString proxyTypeString = settings.value( QStringLiteral( "proxy/proxyType" ), "" ).toString();
587 
588  if ( proxyTypeString == QLatin1String( "DefaultProxy" ) )
589  {
590  mUseSystemProxy = true;
591  QNetworkProxyFactory::setUseSystemConfiguration( true );
592  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
593  if ( !proxies.isEmpty() )
594  {
595  proxy = proxies.first();
596  }
597  QgsDebugMsgLevel( QStringLiteral( "setting default proxy" ), 4 );
598  }
599  else
600  {
601  QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
602  if ( proxyTypeString == QLatin1String( "Socks5Proxy" ) )
603  {
604  proxyType = QNetworkProxy::Socks5Proxy;
605  }
606  else if ( proxyTypeString == QLatin1String( "HttpProxy" ) )
607  {
608  proxyType = QNetworkProxy::HttpProxy;
609  }
610  else if ( proxyTypeString == QLatin1String( "HttpCachingProxy" ) )
611  {
612  proxyType = QNetworkProxy::HttpCachingProxy;
613  }
614  else if ( proxyTypeString == QLatin1String( "FtpCachingProxy" ) )
615  {
616  proxyType = QNetworkProxy::FtpCachingProxy;
617  }
618  QgsDebugMsg( QStringLiteral( "setting proxy %1 %2:%3 %4/%5" )
619  .arg( proxyType )
620  .arg( proxyHost ).arg( proxyPort )
621  .arg( proxyUser, proxyPassword )
622  );
623  proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
624  }
625  // Setup network proxy authentication configuration
626  QString authcfg = settings.value( QStringLiteral( "proxy/authcfg" ), "" ).toString();
627  if ( !authcfg.isEmpty( ) )
628  {
629  QgsDebugMsg( QStringLiteral( "setting proxy from stored authentication configuration %1" ).arg( authcfg ) );
630  // Never crash! Never.
632  QgsApplication::authManager()->updateNetworkProxy( proxy, authcfg );
633  }
634  }
635 
636  setFallbackProxyAndExcludes( proxy, excludes, noProxyURLs );
637 
638  QgsNetworkDiskCache *newcache = qobject_cast<QgsNetworkDiskCache *>( cache() );
639  if ( !newcache )
640  newcache = new QgsNetworkDiskCache( this );
641 
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();
646  newcache->setCacheDirectory( cacheDirectory );
647  newcache->setMaximumCacheSize( cacheSize );
648  QgsDebugMsgLevel( QStringLiteral( "cacheDirectory: %1" ).arg( newcache->cacheDirectory() ), 4 );
649  QgsDebugMsgLevel( QStringLiteral( "maximumCacheSize: %1" ).arg( newcache->maximumCacheSize() ), 4 );
650 
651  if ( cache() != newcache )
652  setCache( newcache );
653 }
654 
656 {
657  return QgsSettings().value( QStringLiteral( "/qgis/networkAndProxy/networkTimeout" ), 60000 ).toInt();
658 }
659 
661 {
662  QgsSettings().setValue( QStringLiteral( "/qgis/networkAndProxy/networkTimeout" ), time );
663 }
664 
665 QgsNetworkReplyContent QgsNetworkAccessManager::blockingGet( QNetworkRequest &request, const QString &authCfg, bool forceRefresh, QgsFeedback *feedback )
666 {
668  br.setAuthCfg( authCfg );
669  br.get( request, forceRefresh, feedback );
670  return br.reply();
671 }
672 
673 QgsNetworkReplyContent QgsNetworkAccessManager::blockingPost( QNetworkRequest &request, const QByteArray &data, const QString &authCfg, bool forceRefresh, QgsFeedback *feedback )
674 {
676  br.setAuthCfg( authCfg );
677  br.post( request, data, forceRefresh, feedback );
678  return br.reply();
679 }
680 
681 
682 //
683 // QgsNetworkRequestParameters
684 //
685 
686 QgsNetworkRequestParameters::QgsNetworkRequestParameters( QNetworkAccessManager::Operation operation, const QNetworkRequest &request, int requestId, const QByteArray &content )
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 ) ) )
694 {
695 }
696 
697 
698 //
699 // QgsSslErrorHandler
700 //
701 
702 void QgsSslErrorHandler::handleSslErrors( QNetworkReply *reply, const QList<QSslError> & )
703 {
704  Q_UNUSED( reply )
705  QgsDebugMsg( QStringLiteral( "SSL errors occurred accessing URL:\n%1" ).arg( reply->request().url().toString() ) );
706 }
707 
708 //
709 // QgsNetworkAuthenticationHandler
710 //
711 
712 void QgsNetworkAuthenticationHandler::handleAuthRequest( QNetworkReply *reply, QAuthenticator * )
713 {
714  Q_UNUSED( reply )
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() ) );
716 }
static int versionInt()
Version number used for comparing versions using the "Check QGIS Version" function.
Definition: qgis.cpp:281
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.
Definition: qgsfeedback.h:45
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:
Definition: qgssettings.h:62
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
Definition: qgis.h:798
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:797
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38