Branch data Line data Source code
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 : :
22 : : #include "qgsnetworkaccessmanager.h"
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"
32 : : #include "qgsblockingnetworkrequest.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 : :
51 : : /// @cond PRIVATE
52 : 6 : class QgsNetworkProxyFactory : public QNetworkProxyFactory
53 : : {
54 : : public:
55 : 3 : QgsNetworkProxyFactory() = default;
56 : :
57 : 0 : QList<QNetworkProxy> queryProxy( const QNetworkProxyQuery &query = QNetworkProxyQuery() ) override
58 : : {
59 : 0 : QgsNetworkAccessManager *nam = QgsNetworkAccessManager::instance();
60 : :
61 : : // iterate proxies factories and take first non empty list
62 : 0 : const auto constProxyFactories = nam->proxyFactories();
63 : 0 : for ( QNetworkProxyFactory *f : constProxyFactories )
64 : : {
65 : 0 : QList<QNetworkProxy> systemproxies = f->systemProxyForQuery( query );
66 : 0 : if ( !systemproxies.isEmpty() )
67 : 0 : return systemproxies;
68 : :
69 : 0 : QList<QNetworkProxy> proxies = f->queryProxy( query );
70 : 0 : if ( !proxies.isEmpty() )
71 : 0 : return proxies;
72 : 0 : }
73 : :
74 : : // no proxies from the proxy factory list check for excludes
75 : 0 : if ( query.queryType() != QNetworkProxyQuery::UrlRequest )
76 : 0 : return QList<QNetworkProxy>() << nam->fallbackProxy();
77 : :
78 : 0 : QString url = query.url().toString();
79 : :
80 : 0 : const auto constNoProxyList = nam->noProxyList();
81 : 0 : for ( const QString &noProxy : constNoProxyList )
82 : : {
83 : 0 : if ( !noProxy.trimmed().isEmpty() && url.startsWith( noProxy ) )
84 : : {
85 : 0 : QgsDebugMsgLevel( QStringLiteral( "don't using any proxy for %1 [exclude %2]" ).arg( url, noProxy ), 4 );
86 : 0 : return QList<QNetworkProxy>() << QNetworkProxy( QNetworkProxy::NoProxy );
87 : : }
88 : : }
89 : :
90 : 0 : const auto constExcludeList = nam->excludeList();
91 : 0 : for ( const QString &exclude : constExcludeList )
92 : : {
93 : 0 : if ( !exclude.trimmed().isEmpty() && url.startsWith( exclude ) )
94 : : {
95 : 0 : QgsDebugMsgLevel( QStringLiteral( "using default proxy for %1 [exclude %2]" ).arg( url, exclude ), 4 );
96 : 0 : return QList<QNetworkProxy>() << QNetworkProxy( QNetworkProxy::DefaultProxy );
97 : : }
98 : : }
99 : :
100 : 0 : if ( nam->useSystemProxy() )
101 : : {
102 : 0 : QgsDebugMsgLevel( QStringLiteral( "requesting system proxy for query %1" ).arg( url ), 4 );
103 : 0 : QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery( query );
104 : 0 : if ( !proxies.isEmpty() )
105 : : {
106 : 0 : QgsDebugMsgLevel( QStringLiteral( "using system proxy %1:%2 for query" )
107 : : .arg( proxies.first().hostName() ).arg( proxies.first().port() ), 4 );
108 : 0 : return proxies;
109 : : }
110 : 0 : }
111 : :
112 : 0 : QgsDebugMsgLevel( QStringLiteral( "using fallback proxy for %1" ).arg( url ), 4 );
113 : 0 : return QList<QNetworkProxy>() << nam->fallbackProxy();
114 : 0 : }
115 : : };
116 : : ///@endcond
117 : :
118 : : //
119 : : // Static calls to enforce singleton behavior
120 : : //
121 : 3 : QgsNetworkAccessManager *QgsNetworkAccessManager::instance( Qt::ConnectionType connectionType )
122 : : {
123 : 3 : static QThreadStorage<QgsNetworkAccessManager> sInstances;
124 : 3 : QgsNetworkAccessManager *nam = &sInstances.localData();
125 : :
126 : 3 : if ( nam->thread() == qApp->thread() )
127 : 3 : sMainNAM = nam;
128 : :
129 : 3 : if ( !nam->mInitialized )
130 : : {
131 : 3 : nam->setupDefaultProxyAndCache( connectionType );
132 : 3 : nam->setCacheDisabled( sMainNAM->cacheDisabled() );
133 : 3 : }
134 : :
135 : 3 : return nam;
136 : 0 : }
137 : :
138 : 3 : QgsNetworkAccessManager::QgsNetworkAccessManager( QObject *parent )
139 : 3 : : QNetworkAccessManager( parent )
140 : 6 : {
141 : 3 : setProxyFactory( new QgsNetworkProxyFactory() );
142 : 3 : }
143 : :
144 : 3 : void QgsNetworkAccessManager::setSslErrorHandler( std::unique_ptr<QgsSslErrorHandler> handler )
145 : : {
146 : : Q_ASSERT( sMainNAM == this );
147 : 3 : mSslErrorHandler = std::move( handler );
148 : 3 : }
149 : :
150 : 3 : void QgsNetworkAccessManager::setAuthHandler( std::unique_ptr<QgsNetworkAuthenticationHandler> handler )
151 : : {
152 : : Q_ASSERT( sMainNAM == this );
153 : 3 : mAuthHandler = std::move( handler );
154 : 3 : }
155 : :
156 : 0 : void QgsNetworkAccessManager::insertProxyFactory( QNetworkProxyFactory *factory )
157 : : {
158 : 0 : mProxyFactories.insert( 0, factory );
159 : 0 : }
160 : :
161 : 0 : void QgsNetworkAccessManager::removeProxyFactory( QNetworkProxyFactory *factory )
162 : : {
163 : 0 : mProxyFactories.removeAll( factory );
164 : 0 : }
165 : :
166 : 0 : const QList<QNetworkProxyFactory *> QgsNetworkAccessManager::proxyFactories() const
167 : : {
168 : 0 : return mProxyFactories;
169 : : }
170 : :
171 : 0 : QStringList QgsNetworkAccessManager::excludeList() const
172 : : {
173 : 0 : return mExcludedURLs;
174 : : }
175 : :
176 : 0 : QStringList QgsNetworkAccessManager::noProxyList() const
177 : : {
178 : 0 : return mNoProxyURLs;
179 : : }
180 : :
181 : 0 : const QNetworkProxy &QgsNetworkAccessManager::fallbackProxy() const
182 : : {
183 : 0 : return mFallbackProxy;
184 : : }
185 : :
186 : 3 : void QgsNetworkAccessManager::setFallbackProxyAndExcludes( const QNetworkProxy &proxy, const QStringList &excludes, const QStringList &noProxyURLs )
187 : : {
188 : 3 : 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 : 3 : mFallbackProxy = proxy;
202 : 3 : mExcludedURLs = excludes;
203 : : // remove empty records from excludes list -- these would otherwise match ANY url, so the proxy would always be skipped!
204 : 6 : mExcludedURLs.erase( std::remove_if( mExcludedURLs.begin(), mExcludedURLs.end(), // clazy:exclude=detaching-member
205 : 0 : []( const QString & url )
206 : : {
207 : 0 : return url.trimmed().isEmpty();
208 : 3 : } ), mExcludedURLs.end() ); // clazy:exclude=detaching-member
209 : :
210 : 3 : mNoProxyURLs = noProxyURLs;
211 : 6 : mNoProxyURLs.erase( std::remove_if( mNoProxyURLs.begin(), mNoProxyURLs.end(), // clazy:exclude=detaching-member
212 : 0 : []( const QString & url )
213 : : {
214 : 0 : return url.trimmed().isEmpty();
215 : 3 : } ), mNoProxyURLs.end() ); // clazy:exclude=detaching-member
216 : 3 : }
217 : :
218 : 0 : QNetworkReply *QgsNetworkAccessManager::createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData )
219 : : {
220 : 0 : QgsSettings s;
221 : :
222 : 0 : QNetworkRequest *pReq( const_cast< QNetworkRequest * >( &req ) ); // hack user agent
223 : :
224 : 0 : QString userAgent = s.value( QStringLiteral( "/qgis/networkAndProxy/userAgent" ), "Mozilla/5.0" ).toString();
225 : 0 : if ( !userAgent.isEmpty() )
226 : 0 : userAgent += ' ';
227 : 0 : userAgent += QStringLiteral( "QGIS/%1" ).arg( Qgis::versionInt() );
228 : 0 : pReq->setRawHeader( "User-Agent", userAgent.toLatin1() );
229 : :
230 : : #ifndef QT_NO_SSL
231 : 0 : bool ishttps = pReq->url().scheme().compare( QLatin1String( "https" ), Qt::CaseInsensitive ) == 0;
232 : 0 : if ( ishttps && !QgsApplication::authManager()->isDisabled() )
233 : : {
234 : 0 : QgsDebugMsgLevel( QStringLiteral( "Adding trusted CA certs to request" ), 3 );
235 : 0 : QSslConfiguration sslconfig( pReq->sslConfiguration() );
236 : : // Merge trusted CAs with any additional CAs added by the authentication methods
237 : 0 : sslconfig.setCaCertificates( QgsAuthCertUtils::casMerge( QgsApplication::authManager()->trustedCaCertsCache(), sslconfig.caCertificates( ) ) );
238 : : // check for SSL cert custom config
239 : 0 : QString hostport( QStringLiteral( "%1:%2" )
240 : 0 : .arg( pReq->url().host().trimmed() )
241 : 0 : .arg( pReq->url().port() != -1 ? pReq->url().port() : 443 ) );
242 : 0 : QgsAuthConfigSslServer servconfig = QgsApplication::authManager()->sslCertCustomConfigByHost( hostport.trimmed() );
243 : 0 : if ( !servconfig.isNull() )
244 : : {
245 : 0 : QgsDebugMsg( QStringLiteral( "Adding SSL custom config to request for %1" ).arg( hostport ) );
246 : 0 : sslconfig.setProtocol( servconfig.sslProtocol() );
247 : 0 : sslconfig.setPeerVerifyMode( servconfig.sslPeerVerifyMode() );
248 : 0 : sslconfig.setPeerVerifyDepth( servconfig.sslPeerVerifyDepth() );
249 : 0 : }
250 : :
251 : 0 : pReq->setSslConfiguration( sslconfig );
252 : 0 : }
253 : : #endif
254 : :
255 : 0 : if ( sMainNAM->mCacheDisabled )
256 : : {
257 : : // if caching is disabled then we override whatever the request actually has set!
258 : 0 : pReq->setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
259 : 0 : pReq->setAttribute( QNetworkRequest::CacheSaveControlAttribute, false );
260 : 0 : }
261 : :
262 : : static QAtomicInt sRequestId = 0;
263 : 0 : const int requestId = ++sRequestId;
264 : 0 : QByteArray content;
265 : 0 : if ( QBuffer *buffer = qobject_cast<QBuffer *>( outgoingData ) )
266 : : {
267 : 0 : content = buffer->buffer();
268 : 0 : }
269 : :
270 : 0 : emit requestAboutToBeCreated( QgsNetworkRequestParameters( op, req, requestId, content ) );
271 : : Q_NOWARN_DEPRECATED_PUSH
272 : 0 : emit requestAboutToBeCreated( op, req, outgoingData );
273 : : Q_NOWARN_DEPRECATED_POP
274 : 0 : QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
275 : 0 : reply->setProperty( "requestId", requestId );
276 : :
277 : : Q_NOWARN_DEPRECATED_PUSH
278 : 0 : emit requestCreated( reply );
279 : : Q_NOWARN_DEPRECATED_POP
280 : :
281 : 0 : connect( reply, &QNetworkReply::downloadProgress, this, &QgsNetworkAccessManager::onReplyDownloadProgress );
282 : : #ifndef QT_NO_SSL
283 : 0 : 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 : 0 : if ( timeout() )
290 : : {
291 : 0 : QTimer *timer = new QTimer( reply );
292 : 0 : timer->setObjectName( QStringLiteral( "timeoutTimer" ) );
293 : 0 : connect( timer, &QTimer::timeout, this, &QgsNetworkAccessManager::abortRequest );
294 : 0 : timer->setSingleShot( true );
295 : 0 : timer->start( timeout() );
296 : :
297 : 0 : connect( reply, &QNetworkReply::downloadProgress, timer, [timer] { timer->start(); } );
298 : 0 : connect( reply, &QNetworkReply::uploadProgress, timer, [timer] { timer->start(); } );
299 : 0 : connect( reply, &QNetworkReply::finished, timer, &QTimer::stop );
300 : 0 : }
301 : 0 : QgsDebugMsgLevel( QStringLiteral( "Created [reply:%1]" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ), 3 );
302 : :
303 : 0 : return reply;
304 : 0 : }
305 : :
306 : : #ifndef QT_NO_SSL
307 : 0 : void QgsNetworkAccessManager::unlockAfterSslErrorHandled()
308 : : {
309 : : Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
310 : 0 : mSslErrorWaitCondition.wakeOne();
311 : 0 : }
312 : : #endif
313 : :
314 : 0 : void QgsNetworkAccessManager::abortRequest()
315 : : {
316 : 0 : QTimer *timer = qobject_cast<QTimer *>( sender() );
317 : : Q_ASSERT( timer );
318 : :
319 : 0 : QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
320 : : Q_ASSERT( reply );
321 : :
322 : 0 : reply->abort();
323 : 0 : QgsDebugMsgLevel( QStringLiteral( "Abort [reply:%1] %2" ).arg( reinterpret_cast< qint64 >( reply ), 0, 16 ).arg( reply->url().toString() ), 3 );
324 : 0 : QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
325 : : // Notify the application
326 : 0 : emit requestTimedOut( QgsNetworkRequestParameters( reply->operation(), reply->request(), getRequestId( reply ) ) );
327 : 0 : emit requestTimedOut( reply );
328 : 0 : }
329 : :
330 : 0 : void QgsNetworkAccessManager::onReplyFinished( QNetworkReply *reply )
331 : : {
332 : 0 : emit finished( QgsNetworkReplyContent( reply ) );
333 : 0 : }
334 : :
335 : 0 : void QgsNetworkAccessManager::onReplyDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
336 : : {
337 : 0 : if ( QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() ) )
338 : : {
339 : 0 : emit downloadProgress( getRequestId( reply ), bytesReceived, bytesTotal );
340 : 0 : }
341 : 0 : }
342 : :
343 : : #ifndef QT_NO_SSL
344 : 0 : void QgsNetworkAccessManager::onReplySslErrors( const QList<QSslError> &errors )
345 : : {
346 : 0 : QNetworkReply *reply = qobject_cast< QNetworkReply *>( sender() );
347 : : Q_ASSERT( reply );
348 : : Q_ASSERT( reply->manager() == this );
349 : :
350 : 0 : QgsDebugMsg( QStringLiteral( "Stopping network reply timeout whilst SSL error is handled" ) );
351 : 0 : pauseTimeout( reply );
352 : :
353 : 0 : 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 : 0 : emit sslErrorsOccurred( reply, errors );
358 : 0 : 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 : 0 : mSslErrorHandlerMutex.lock();
363 : 0 : mSslErrorWaitCondition.wait( &mSslErrorHandlerMutex );
364 : 0 : mSslErrorHandlerMutex.unlock();
365 : 0 : afterSslErrorHandled( reply );
366 : 0 : }
367 : 0 : }
368 : :
369 : 0 : void QgsNetworkAccessManager::afterSslErrorHandled( QNetworkReply *reply )
370 : : {
371 : 0 : if ( reply->manager() == this )
372 : : {
373 : 0 : restartTimeout( reply );
374 : 0 : emit sslErrorsHandled( reply );
375 : 0 : }
376 : 0 : else if ( this == sMainNAM )
377 : : {
378 : : // notify other threads to allow them to handle the reply
379 : 0 : qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterSslErrorHandled(); // safe to call directly - the other thread will be stuck waiting for us
380 : 0 : }
381 : 0 : }
382 : :
383 : 0 : void QgsNetworkAccessManager::unlockAfterAuthRequestHandled()
384 : : {
385 : : Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
386 : 0 : mAuthRequestWaitCondition.wakeOne();
387 : 0 : }
388 : :
389 : 0 : void QgsNetworkAccessManager::afterAuthRequestHandled( QNetworkReply *reply )
390 : : {
391 : 0 : if ( reply->manager() == this )
392 : : {
393 : 0 : restartTimeout( reply );
394 : 0 : emit authRequestHandled( reply );
395 : 0 : }
396 : 0 : else if ( this == sMainNAM )
397 : : {
398 : : // notify other threads to allow them to handle the reply
399 : 0 : qobject_cast< QgsNetworkAccessManager *>( reply->manager() )->unlockAfterAuthRequestHandled(); // safe to call directly - the other thread will be stuck waiting for us
400 : 0 : }
401 : 0 : }
402 : :
403 : 0 : void QgsNetworkAccessManager::pauseTimeout( QNetworkReply *reply )
404 : : {
405 : : Q_ASSERT( reply->manager() == this );
406 : :
407 : 0 : QTimer *timer = reply->findChild<QTimer *>( QStringLiteral( "timeoutTimer" ) );
408 : 0 : if ( timer && timer->isActive() )
409 : : {
410 : 0 : timer->stop();
411 : 0 : }
412 : 0 : }
413 : :
414 : 0 : void QgsNetworkAccessManager::restartTimeout( QNetworkReply *reply )
415 : : {
416 : : Q_ASSERT( reply->manager() == this );
417 : : // restart reply timeout
418 : 0 : QTimer *timer = reply->findChild<QTimer *>( QStringLiteral( "timeoutTimer" ) );
419 : 0 : if ( timer )
420 : : {
421 : : Q_ASSERT( !timer->isActive() );
422 : 0 : QgsDebugMsg( QStringLiteral( "Restarting network reply timeout" ) );
423 : 0 : timer->setSingleShot( true );
424 : 0 : timer->start( timeout() );
425 : 0 : }
426 : 0 : }
427 : :
428 : 0 : int QgsNetworkAccessManager::getRequestId( QNetworkReply *reply )
429 : : {
430 : 0 : return reply->property( "requestId" ).toInt();
431 : 0 : }
432 : :
433 : 0 : void QgsNetworkAccessManager::handleSslErrors( QNetworkReply *reply, const QList<QSslError> &errors )
434 : : {
435 : 0 : mSslErrorHandler->handleSslErrors( reply, errors );
436 : 0 : afterSslErrorHandled( reply );
437 : 0 : }
438 : :
439 : : #endif
440 : :
441 : 0 : void QgsNetworkAccessManager::onAuthRequired( QNetworkReply *reply, QAuthenticator *auth )
442 : : {
443 : : Q_ASSERT( reply );
444 : : Q_ASSERT( reply->manager() == this );
445 : :
446 : 0 : QgsDebugMsg( QStringLiteral( "Stopping network reply timeout whilst auth request is handled" ) );
447 : 0 : pauseTimeout( reply );
448 : :
449 : 0 : 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 : 0 : emit authRequestOccurred( reply, auth );
454 : :
455 : 0 : 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 : 0 : mAuthRequestHandlerMutex.lock();
460 : 0 : mAuthRequestWaitCondition.wait( &mAuthRequestHandlerMutex );
461 : 0 : mAuthRequestHandlerMutex.unlock();
462 : 0 : afterAuthRequestHandled( reply );
463 : 0 : }
464 : 0 : }
465 : :
466 : 0 : void QgsNetworkAccessManager::handleAuthRequest( QNetworkReply *reply, QAuthenticator *auth )
467 : : {
468 : 0 : mAuthHandler->handleAuthRequest( reply, auth );
469 : :
470 : 0 : emit requestAuthDetailsAdded( getRequestId( reply ), auth->realm(), auth->user(), auth->password() );
471 : :
472 : 0 : afterAuthRequestHandled( reply );
473 : 0 : }
474 : :
475 : 0 : QString QgsNetworkAccessManager::cacheLoadControlName( QNetworkRequest::CacheLoadControl control )
476 : : {
477 : 0 : switch ( control )
478 : : {
479 : : case QNetworkRequest::AlwaysNetwork:
480 : 0 : return QStringLiteral( "AlwaysNetwork" );
481 : : case QNetworkRequest::PreferNetwork:
482 : 0 : return QStringLiteral( "PreferNetwork" );
483 : : case QNetworkRequest::PreferCache:
484 : 0 : return QStringLiteral( "PreferCache" );
485 : : case QNetworkRequest::AlwaysCache:
486 : 0 : return QStringLiteral( "AlwaysCache" );
487 : : }
488 : 0 : return QStringLiteral( "PreferNetwork" );
489 : 0 : }
490 : :
491 : 0 : QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromName( const QString &name )
492 : : {
493 : 0 : if ( name == QLatin1String( "AlwaysNetwork" ) )
494 : : {
495 : 0 : return QNetworkRequest::AlwaysNetwork;
496 : : }
497 : 0 : else if ( name == QLatin1String( "PreferNetwork" ) )
498 : : {
499 : 0 : return QNetworkRequest::PreferNetwork;
500 : : }
501 : 0 : else if ( name == QLatin1String( "PreferCache" ) )
502 : : {
503 : 0 : return QNetworkRequest::PreferCache;
504 : : }
505 : 0 : else if ( name == QLatin1String( "AlwaysCache" ) )
506 : : {
507 : 0 : return QNetworkRequest::AlwaysCache;
508 : : }
509 : 0 : return QNetworkRequest::PreferNetwork;
510 : 0 : }
511 : :
512 : 3 : void QgsNetworkAccessManager::setupDefaultProxyAndCache( Qt::ConnectionType connectionType )
513 : : {
514 : 3 : mInitialized = true;
515 : 3 : mUseSystemProxy = false;
516 : :
517 : : Q_ASSERT( sMainNAM );
518 : :
519 : 3 : if ( sMainNAM != this )
520 : : {
521 : 0 : connect( this, &QNetworkAccessManager::proxyAuthenticationRequired,
522 : 0 : sMainNAM, &QNetworkAccessManager::proxyAuthenticationRequired,
523 : 0 : connectionType );
524 : :
525 : 0 : connect( this, qOverload< QNetworkReply *>( &QgsNetworkAccessManager::requestTimedOut ),
526 : 0 : sMainNAM, qOverload< QNetworkReply *>( &QgsNetworkAccessManager::requestTimedOut ) );
527 : :
528 : 0 : connect( this, qOverload< QgsNetworkRequestParameters >( &QgsNetworkAccessManager::requestTimedOut ),
529 : 0 : sMainNAM, qOverload< QgsNetworkRequestParameters >( &QgsNetworkAccessManager::requestTimedOut ) );
530 : :
531 : 0 : connect( this, qOverload< QgsNetworkRequestParameters >( &QgsNetworkAccessManager::requestAboutToBeCreated ),
532 : 0 : sMainNAM, qOverload< QgsNetworkRequestParameters >( &QgsNetworkAccessManager::requestAboutToBeCreated ) );
533 : :
534 : 0 : connect( this, qOverload< QgsNetworkReplyContent >( &QgsNetworkAccessManager::finished ),
535 : 0 : sMainNAM, qOverload< QgsNetworkReplyContent >( &QgsNetworkAccessManager::finished ) );
536 : :
537 : 0 : connect( this, &QgsNetworkAccessManager::downloadProgress, sMainNAM, &QgsNetworkAccessManager::downloadProgress );
538 : :
539 : : #ifndef QT_NO_SSL
540 : 0 : connect( this, &QNetworkAccessManager::sslErrors,
541 : 0 : sMainNAM, &QNetworkAccessManager::sslErrors,
542 : 0 : connectionType );
543 : :
544 : 0 : connect( this, &QgsNetworkAccessManager::requestEncounteredSslErrors, sMainNAM, &QgsNetworkAccessManager::requestEncounteredSslErrors );
545 : : #endif
546 : :
547 : 0 : connect( this, &QgsNetworkAccessManager::requestRequiresAuth, sMainNAM, &QgsNetworkAccessManager::requestRequiresAuth );
548 : 0 : }
549 : : else
550 : : {
551 : : #ifndef QT_NO_SSL
552 : 3 : setSslErrorHandler( std::make_unique< QgsSslErrorHandler >() );
553 : : #endif
554 : 3 : setAuthHandler( std::make_unique< QgsNetworkAuthenticationHandler>() );
555 : : }
556 : : #ifndef QT_NO_SSL
557 : 3 : connect( this, &QgsNetworkAccessManager::sslErrorsOccurred, sMainNAM, &QgsNetworkAccessManager::handleSslErrors );
558 : : #endif
559 : 3 : connect( this, &QNetworkAccessManager::authenticationRequired, this, &QgsNetworkAccessManager::onAuthRequired );
560 : 3 : connect( this, &QgsNetworkAccessManager::authRequestOccurred, sMainNAM, &QgsNetworkAccessManager::handleAuthRequest );
561 : :
562 : 3 : connect( this, &QNetworkAccessManager::finished, this, &QgsNetworkAccessManager::onReplyFinished );
563 : :
564 : : // check if proxy is enabled
565 : 3 : QgsSettings settings;
566 : 3 : QNetworkProxy proxy;
567 : 3 : QStringList excludes;
568 : 3 : QStringList noProxyURLs;
569 : :
570 : 6 : bool proxyEnabled = settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool();
571 : 3 : 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 : 0 : excludes = settings.value( QStringLiteral( "proxy/proxyExcludedUrls" ), QStringList() ).toStringList();
576 : :
577 : 0 : noProxyURLs = settings.value( QStringLiteral( "proxy/noProxyUrls" ), QStringList() ).toStringList();
578 : :
579 : : //read type, host, port, user, passw from settings
580 : 0 : QString proxyHost = settings.value( QStringLiteral( "proxy/proxyHost" ), "" ).toString();
581 : 0 : int proxyPort = settings.value( QStringLiteral( "proxy/proxyPort" ), "" ).toString().toInt();
582 : :
583 : 0 : QString proxyUser = settings.value( QStringLiteral( "proxy/proxyUser" ), "" ).toString();
584 : 0 : QString proxyPassword = settings.value( QStringLiteral( "proxy/proxyPassword" ), "" ).toString();
585 : :
586 : 0 : QString proxyTypeString = settings.value( QStringLiteral( "proxy/proxyType" ), "" ).toString();
587 : :
588 : 0 : if ( proxyTypeString == QLatin1String( "DefaultProxy" ) )
589 : : {
590 : 0 : mUseSystemProxy = true;
591 : 0 : QNetworkProxyFactory::setUseSystemConfiguration( true );
592 : 0 : QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
593 : 0 : if ( !proxies.isEmpty() )
594 : : {
595 : 0 : proxy = proxies.first();
596 : 0 : }
597 : 0 : QgsDebugMsgLevel( QStringLiteral( "setting default proxy" ), 4 );
598 : 0 : }
599 : : else
600 : : {
601 : 0 : QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
602 : 0 : if ( proxyTypeString == QLatin1String( "Socks5Proxy" ) )
603 : : {
604 : 0 : proxyType = QNetworkProxy::Socks5Proxy;
605 : 0 : }
606 : 0 : else if ( proxyTypeString == QLatin1String( "HttpProxy" ) )
607 : : {
608 : 0 : proxyType = QNetworkProxy::HttpProxy;
609 : 0 : }
610 : 0 : else if ( proxyTypeString == QLatin1String( "HttpCachingProxy" ) )
611 : : {
612 : 0 : proxyType = QNetworkProxy::HttpCachingProxy;
613 : 0 : }
614 : 0 : else if ( proxyTypeString == QLatin1String( "FtpCachingProxy" ) )
615 : : {
616 : 0 : proxyType = QNetworkProxy::FtpCachingProxy;
617 : 0 : }
618 : 0 : QgsDebugMsg( QStringLiteral( "setting proxy %1 %2:%3 %4/%5" )
619 : : .arg( proxyType )
620 : : .arg( proxyHost ).arg( proxyPort )
621 : : .arg( proxyUser, proxyPassword )
622 : : );
623 : 0 : proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
624 : : }
625 : : // Setup network proxy authentication configuration
626 : 0 : QString authcfg = settings.value( QStringLiteral( "proxy/authcfg" ), "" ).toString();
627 : 0 : if ( !authcfg.isEmpty( ) )
628 : : {
629 : 0 : QgsDebugMsg( QStringLiteral( "setting proxy from stored authentication configuration %1" ).arg( authcfg ) );
630 : : // Never crash! Never.
631 : 0 : if ( QgsApplication::authManager() )
632 : 0 : QgsApplication::authManager()->updateNetworkProxy( proxy, authcfg );
633 : 0 : }
634 : 0 : }
635 : :
636 : 3 : setFallbackProxyAndExcludes( proxy, excludes, noProxyURLs );
637 : :
638 : 3 : QgsNetworkDiskCache *newcache = qobject_cast<QgsNetworkDiskCache *>( cache() );
639 : 3 : if ( !newcache )
640 : 3 : newcache = new QgsNetworkDiskCache( this );
641 : :
642 : 6 : QString cacheDirectory = settings.value( QStringLiteral( "cache/directory" ) ).toString();
643 : 3 : if ( cacheDirectory.isEmpty() )
644 : 3 : cacheDirectory = QStandardPaths::writableLocation( QStandardPaths::CacheLocation );
645 : 6 : qint64 cacheSize = settings.value( QStringLiteral( "cache/size" ), 50 * 1024 * 1024 ).toLongLong();
646 : 3 : newcache->setCacheDirectory( cacheDirectory );
647 : 3 : newcache->setMaximumCacheSize( cacheSize );
648 : 3 : QgsDebugMsgLevel( QStringLiteral( "cacheDirectory: %1" ).arg( newcache->cacheDirectory() ), 4 );
649 : 3 : QgsDebugMsgLevel( QStringLiteral( "maximumCacheSize: %1" ).arg( newcache->maximumCacheSize() ), 4 );
650 : :
651 : 3 : if ( cache() != newcache )
652 : 3 : setCache( newcache );
653 : 3 : }
654 : :
655 : 0 : int QgsNetworkAccessManager::timeout()
656 : : {
657 : 0 : return QgsSettings().value( QStringLiteral( "/qgis/networkAndProxy/networkTimeout" ), 60000 ).toInt();
658 : 0 : }
659 : :
660 : 0 : void QgsNetworkAccessManager::setTimeout( const int time )
661 : : {
662 : 0 : QgsSettings().setValue( QStringLiteral( "/qgis/networkAndProxy/networkTimeout" ), time );
663 : 0 : }
664 : :
665 : 0 : QgsNetworkReplyContent QgsNetworkAccessManager::blockingGet( QNetworkRequest &request, const QString &authCfg, bool forceRefresh, QgsFeedback *feedback )
666 : : {
667 : 0 : QgsBlockingNetworkRequest br;
668 : 0 : br.setAuthCfg( authCfg );
669 : 0 : br.get( request, forceRefresh, feedback );
670 : 0 : return br.reply();
671 : 0 : }
672 : :
673 : 0 : QgsNetworkReplyContent QgsNetworkAccessManager::blockingPost( QNetworkRequest &request, const QByteArray &data, const QString &authCfg, bool forceRefresh, QgsFeedback *feedback )
674 : : {
675 : 0 : QgsBlockingNetworkRequest br;
676 : 0 : br.setAuthCfg( authCfg );
677 : 0 : br.post( request, data, forceRefresh, feedback );
678 : 0 : return br.reply();
679 : 0 : }
680 : 3 :
681 : 3 :
682 : 3 : //
683 : : // QgsNetworkRequestParameters
684 : : //
685 : :
686 : 0 : QgsNetworkRequestParameters::QgsNetworkRequestParameters( QNetworkAccessManager::Operation operation, const QNetworkRequest &request, int requestId, const QByteArray &content )
687 : 0 : : mOperation( operation )
688 : 0 : , mRequest( request )
689 : 0 : , mOriginatingThreadId( QStringLiteral( "0x%2" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char( '0' ) ) )
690 : 0 : , mRequestId( requestId )
691 : 0 : , mContent( content )
692 : 0 : , mInitiatorClass( request.attribute( static_cast< QNetworkRequest::Attribute >( QgsNetworkRequestParameters::AttributeInitiatorClass ) ).toString() )
693 : 0 : , mInitiatorRequestId( request.attribute( static_cast< QNetworkRequest::Attribute >( QgsNetworkRequestParameters::AttributeInitiatorRequestId ) ) )
694 : : {
695 : 0 : }
696 : :
697 : :
698 : : //
699 : : // QgsSslErrorHandler
700 : : //
701 : :
702 : 0 : void QgsSslErrorHandler::handleSslErrors( QNetworkReply *reply, const QList<QSslError> & )
703 : : {
704 : : Q_UNUSED( reply )
705 : 0 : QgsDebugMsg( QStringLiteral( "SSL errors occurred accessing URL:\n%1" ).arg( reply->request().url().toString() ) );
706 : 0 : }
707 : :
708 : : //
709 : : // QgsNetworkAuthenticationHandler
710 : : //
711 : :
712 : 0 : void QgsNetworkAuthenticationHandler::handleAuthRequest( QNetworkReply *reply, QAuthenticator * )
713 : : {
714 : : Q_UNUSED( reply )
715 : 0 : 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 : 0 : }
|