QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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 
29 #include <QUrl>
30 #include <QSettings>
31 #include <QTimer>
32 #include <QNetworkReply>
33 #include <QNetworkDiskCache>
34 
35 class QgsNetworkProxyFactory : public QNetworkProxyFactory
36 {
37  public:
40 
41  virtual QList<QNetworkProxy> queryProxy( const QNetworkProxyQuery & query = QNetworkProxyQuery() )
42  {
44 
45  // iterate proxies factories and take first non empty list
46  foreach ( QNetworkProxyFactory *f, nam->proxyFactories() )
47  {
48  QList<QNetworkProxy> systemproxies = f->systemProxyForQuery( query );
49  if ( systemproxies.size() > 0 )
50  return systemproxies;
51 
52  QList<QNetworkProxy> proxies = f->queryProxy( query );
53  if ( proxies.size() > 0 )
54  return proxies;
55  }
56 
57  // no proxies from the proxy factor list check for excludes
58  if ( query.queryType() != QNetworkProxyQuery::UrlRequest )
59  return QList<QNetworkProxy>() << nam->fallbackProxy();
60 
61  QString url = query.url().toString();
62 
63  foreach ( QString exclude, nam->excludeList() )
64  {
65  if ( url.startsWith( exclude ) )
66  {
67  QgsDebugMsg( QString( "using default proxy for %1 [exclude %2]" ).arg( url ).arg( exclude ) );
68  return QList<QNetworkProxy>() << QNetworkProxy();
69  }
70  }
71 
72  if ( nam->useSystemProxy() )
73  {
74  QgsDebugMsg( QString( "requesting system proxy for query %1" ).arg( url ) );
75  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery( query );
76  if ( !proxies.isEmpty() )
77  {
78  QgsDebugMsg( QString( "using system proxy %1:%2 for query" )
79  .arg( proxies.first().hostName() ).arg( proxies.first().port() ) );
80  return proxies;
81  }
82  }
83 
84  QgsDebugMsg( QString( "using fallback proxy for %1" ).arg( url ) );
85  return QList<QNetworkProxy>() << nam->fallbackProxy();
86  }
87 };
88 
89 //
90 // Static calls to enforce singleton behaviour
91 //
92 QgsNetworkAccessManager* QgsNetworkAccessManager::sInstance = 0;
94 {
95  if ( sInstance == 0 )
96  {
97  sInstance = new QgsNetworkAccessManager();
98  }
99  return sInstance;
100 }
101 
103  : QNetworkAccessManager( parent )
104  , mUseSystemProxy( false )
105 {
106  setProxyFactory( new QgsNetworkProxyFactory() );
107 }
108 
110 {
111 }
112 
113 void QgsNetworkAccessManager::insertProxyFactory( QNetworkProxyFactory *factory )
114 {
115  mProxyFactories.insert( 0, factory );
116 }
117 
118 void QgsNetworkAccessManager::removeProxyFactory( QNetworkProxyFactory *factory )
119 {
120  mProxyFactories.removeAll( factory );
121 }
122 
123 const QList<QNetworkProxyFactory *> QgsNetworkAccessManager::proxyFactories() const
124 {
125  return mProxyFactories;
126 }
127 
128 const QStringList &QgsNetworkAccessManager::excludeList() const
129 {
130  return mExcludedURLs;
131 }
132 
133 const QNetworkProxy &QgsNetworkAccessManager::fallbackProxy() const
134 {
135  return mFallbackProxy;
136 }
137 
138 void QgsNetworkAccessManager::setFallbackProxyAndExcludes( const QNetworkProxy &proxy, const QStringList &excludes )
139 {
140  QgsDebugMsg( QString( "proxy settings: (type:%1 host: %2:%3, user:%4, password:%5" )
141  .arg( proxy.type() == QNetworkProxy::DefaultProxy ? "DefaultProxy" :
142  proxy.type() == QNetworkProxy::Socks5Proxy ? "Socks5Proxy" :
143  proxy.type() == QNetworkProxy::NoProxy ? "NoProxy" :
144  proxy.type() == QNetworkProxy::HttpProxy ? "HttpProxy" :
145  proxy.type() == QNetworkProxy::HttpCachingProxy ? "HttpCachingProxy" :
146  proxy.type() == QNetworkProxy::FtpCachingProxy ? "FtpCachingProxy" :
147  "Undefined" )
148  .arg( proxy.hostName() )
149  .arg( proxy.port() )
150  .arg( proxy.user() )
151  .arg( proxy.password().isEmpty() ? "not set" : "set" ) );
152 
153  mFallbackProxy = proxy;
154  mExcludedURLs = excludes;
155 }
156 
157 QNetworkReply *QgsNetworkAccessManager::createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData )
158 {
159  QSettings s;
160 
161  QNetworkRequest *pReq(( QNetworkRequest * ) &req ); // hack user agent
162 
163  QString userAgent = s.value( "/qgis/networkAndProxy/userAgent", "Mozilla/5.0" ).toString();
164  if ( !userAgent.isEmpty() )
165  userAgent += " ";
166  userAgent += QString( "QGIS/%1" ).arg( QGis::QGIS_VERSION );
167  pReq->setRawHeader( "User-Agent", userAgent.toUtf8() );
168 
169  emit requestAboutToBeCreated( op, req, outgoingData );
170  QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
171 
172  emit requestCreated( reply );
173 
174  // abort request, when network timeout happens
175  QTimer *timer = new QTimer( reply );
176  connect( timer, SIGNAL( timeout() ), this, SLOT( abortRequest() ) );
177  timer->setSingleShot( true );
178  timer->start( s.value( "/qgis/networkAndProxy/networkTimeout", "20000" ).toInt() );
179 
180  connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), timer, SLOT( start() ) );
181  connect( reply, SIGNAL( uploadProgress( qint64, qint64 ) ), timer, SLOT( start() ) );
182 
183  return reply;
184 }
185 
186 void QgsNetworkAccessManager::abortRequest()
187 {
188  QTimer *timer = qobject_cast<QTimer *>( sender() );
189  Q_ASSERT( timer );
190 
191  QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
192  Q_ASSERT( reply );
193 
194  QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
195 
196  if ( reply->isRunning() )
197  reply->close();
198 
199  emit requestTimedOut( reply );
200 }
201 
202 QString QgsNetworkAccessManager::cacheLoadControlName( QNetworkRequest::CacheLoadControl theControl )
203 {
204  switch ( theControl )
205  {
206  case QNetworkRequest::AlwaysNetwork:
207  return "AlwaysNetwork";
208  break;
209  case QNetworkRequest::PreferNetwork:
210  return "PreferNetwork";
211  break;
212  case QNetworkRequest::PreferCache:
213  return "PreferCache";
214  break;
215  case QNetworkRequest::AlwaysCache:
216  return "AlwaysCache";
217  break;
218  default:
219  break;
220  }
221  return "PreferNetwork";
222 }
223 
224 QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromName( const QString &theName )
225 {
226  if ( theName == "AlwaysNetwork" )
227  {
228  return QNetworkRequest::AlwaysNetwork;
229  }
230  else if ( theName == "PreferNetwork" )
231  {
232  return QNetworkRequest::PreferNetwork;
233  }
234  else if ( theName == "PreferCache" )
235  {
236  return QNetworkRequest::PreferCache;
237  }
238  else if ( theName == "AlwaysCache" )
239  {
240  return QNetworkRequest::AlwaysCache;
241  }
242  return QNetworkRequest::PreferNetwork;
243 }
244 
246 {
247  QNetworkProxy proxy;
248  QStringList excludes;
249 
250  QSettings settings;
251 
252  mUseSystemProxy = false;
253 
254  if ( this != instance() )
255  {
256  Qt::ConnectionType connectionType = thread() == instance()->thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection;
257 
258  connect( this, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
259  instance(), SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
260  connectionType );
261 
262  connect( this, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
263  instance(), SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
264  connectionType );
265 
266  connect( this, SIGNAL( requestTimedOut( QNetworkReply* ) ),
267  instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ) );
268 
269 #ifndef QT_NO_OPENSSL
270  connect( this, SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
271  instance(), SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
272  connectionType );
273 #endif
274  }
275 
276  // check if proxy is enabled
277  bool proxyEnabled = settings.value( "proxy/proxyEnabled", false ).toBool();
278  if ( proxyEnabled )
279  {
280  excludes = settings.value( "proxy/proxyExcludedUrls", "" ).toString().split( "|", QString::SkipEmptyParts );
281 
282  //read type, host, port, user, passw from settings
283  QString proxyHost = settings.value( "proxy/proxyHost", "" ).toString();
284  int proxyPort = settings.value( "proxy/proxyPort", "" ).toString().toInt();
285  QString proxyUser = settings.value( "proxy/proxyUser", "" ).toString();
286  QString proxyPassword = settings.value( "proxy/proxyPassword", "" ).toString();
287 
288  QString proxyTypeString = settings.value( "proxy/proxyType", "" ).toString();
289 
290  if ( proxyTypeString == "DefaultProxy" )
291  {
292  mUseSystemProxy = true;
293  QNetworkProxyFactory::setUseSystemConfiguration( true );
294  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
295  if ( !proxies.isEmpty() )
296  {
297  proxy = proxies.first();
298  }
299  QgsDebugMsg( "setting default proxy" );
300  }
301  else
302  {
303  QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
304  if ( proxyTypeString == "Socks5Proxy" )
305  {
306  proxyType = QNetworkProxy::Socks5Proxy;
307  }
308  else if ( proxyTypeString == "HttpProxy" )
309  {
310  proxyType = QNetworkProxy::HttpProxy;
311  }
312  else if ( proxyTypeString == "HttpCachingProxy" )
313  {
314  proxyType = QNetworkProxy::HttpCachingProxy;
315  }
316  else if ( proxyTypeString == "FtpCachingProxy" )
317  {
318  proxyType = QNetworkProxy::FtpCachingProxy;
319  }
320  QgsDebugMsg( QString( "setting proxy %1 %2:%3 %4/%5" )
321  .arg( proxyType )
322  .arg( proxyHost ).arg( proxyPort )
323  .arg( proxyUser ).arg( proxyPassword )
324  );
325  proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
326  }
327  }
328 
329 #if QT_VERSION >= 0x40500
330  setFallbackProxyAndExcludes( proxy, excludes );
331 
332  QNetworkDiskCache *newcache = qobject_cast<QNetworkDiskCache*>( cache() );
333  if ( !newcache )
334  newcache = new QNetworkDiskCache( this );
335 
336  QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString();
337  qint64 cacheSize = settings.value( "cache/size", 50 * 1024 * 1024 ).toULongLong();
338  QgsDebugMsg( QString( "setCacheDirectory: %1" ).arg( cacheDirectory ) );
339  QgsDebugMsg( QString( "setMaximumCacheSize: %1" ).arg( cacheSize ) );
340  newcache->setCacheDirectory( cacheDirectory );
341  newcache->setMaximumCacheSize( cacheSize );
342  QgsDebugMsg( QString( "cacheDirectory: %1" ).arg( newcache->cacheDirectory() ) );
343  QgsDebugMsg( QString( "maximumCacheSize: %1" ).arg( newcache->maximumCacheSize() ) );
344 
345  if ( cache() != newcache )
346  setCache( newcache );
347 #else
348  setProxy( proxy );
349 #endif
350 }
351 
static const char * QGIS_VERSION
Definition: qgis.h:40
const QStringList & excludeList() const
retrieve exclude list (urls shouldn't use the fallback proxy)
void requestCreated(QNetworkReply *)
static QString cacheLoadControlName(QNetworkRequest::CacheLoadControl theControl)
Get name for QNetworkRequest::CacheLoadControl.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsNetworkAccessManager(QObject *parent=0)
static QNetworkRequest::CacheLoadControl cacheLoadControlFromName(const QString &theName)
Get QNetworkRequest::CacheLoadControl from name.
const QNetworkProxy & fallbackProxy() const
retrieve fall back proxy (for urls that no factory returned proxies for)
void setupDefaultProxyAndCache()
Setup the NAM according to the user's settings.
static const QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
const QList< QNetworkProxyFactory * > proxyFactories() const
retrieve proxy factory list
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void requestTimedOut(QNetworkReply *)
virtual QNetworkReply * createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData=0)
void removeProxyFactory(QNetworkProxyFactory *factory)
remove a factory from the proxy factories list
void insertProxyFactory(QNetworkProxyFactory *factory)
insert a factory into the proxy factories list
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
virtual QList< QNetworkProxy > queryProxy(const QNetworkProxyQuery &query=QNetworkProxyQuery())
void requestAboutToBeCreated(QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice *)
void setFallbackProxyAndExcludes(const QNetworkProxy &proxy, const QStringList &excludes)
set fallback proxy and URL that shouldn't use it.
#define tr(sourceText)