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