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 
90  : QNetworkAccessManager( parent )
91  , mUseSystemProxy( false )
92 {
93  setProxyFactory( new QgsNetworkProxyFactory() );
94 }
95 
97 {
98 }
99 
100 void QgsNetworkAccessManager::insertProxyFactory( QNetworkProxyFactory *factory )
101 {
102  mProxyFactories.insert( 0, factory );
103 }
104 
105 void QgsNetworkAccessManager::removeProxyFactory( QNetworkProxyFactory *factory )
106 {
107  mProxyFactories.removeAll( factory );
108 }
109 
110 const QList<QNetworkProxyFactory *> QgsNetworkAccessManager::proxyFactories() const
111 {
112  return mProxyFactories;
113 }
114 
115 const QStringList &QgsNetworkAccessManager::excludeList() const
116 {
117  return mExcludedURLs;
118 }
119 
120 const QNetworkProxy &QgsNetworkAccessManager::fallbackProxy() const
121 {
122  return mFallbackProxy;
123 }
124 
125 void QgsNetworkAccessManager::setFallbackProxyAndExcludes( const QNetworkProxy &proxy, const QStringList &excludes )
126 {
127  QgsDebugMsg( QString( "proxy settings: (type:%1 host: %2:%3, user:%4, password:%5" )
128  .arg( proxy.type() == QNetworkProxy::DefaultProxy ? "DefaultProxy" :
129  proxy.type() == QNetworkProxy::Socks5Proxy ? "Socks5Proxy" :
130  proxy.type() == QNetworkProxy::NoProxy ? "NoProxy" :
131  proxy.type() == QNetworkProxy::HttpProxy ? "HttpProxy" :
132  proxy.type() == QNetworkProxy::HttpCachingProxy ? "HttpCachingProxy" :
133  proxy.type() == QNetworkProxy::FtpCachingProxy ? "FtpCachingProxy" :
134  "Undefined" )
135  .arg( proxy.hostName() )
136  .arg( proxy.port() )
137  .arg( proxy.user() )
138  .arg( proxy.password().isEmpty() ? "not set" : "set" ) );
139 
140  mFallbackProxy = proxy;
141  mExcludedURLs = excludes;
142 }
143 
144 QNetworkReply *QgsNetworkAccessManager::createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData )
145 {
146  QSettings s;
147 
148  QNetworkRequest *pReq(( QNetworkRequest * ) &req ); // hack user agent
149 
150  QString userAgent = s.value( "/qgis/networkAndProxy/userAgent", "Mozilla/5.0" ).toString();
151  if ( !userAgent.isEmpty() )
152  userAgent += " ";
153  userAgent += QString( "QGIS/%1" ).arg( QGis::QGIS_VERSION );
154  pReq->setRawHeader( "User-Agent", userAgent.toUtf8() );
155 
156  emit requestAboutToBeCreated( op, req, outgoingData );
157  QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
158 
159  emit requestCreated( reply );
160 
161  // abort request, when network timeout happens
162  QTimer *timer = new QTimer( reply );
163  connect( timer, SIGNAL( timeout() ), this, SLOT( abortRequest() ) );
164  timer->setSingleShot( true );
165  timer->start( s.value( "/qgis/networkAndProxy/networkTimeout", "20000" ).toInt() );
166 
167  connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), timer, SLOT( start() ) );
168  connect( reply, SIGNAL( uploadProgress( qint64, qint64 ) ), timer, SLOT( start() ) );
169 
170  return reply;
171 }
172 
173 void QgsNetworkAccessManager::abortRequest()
174 {
175  QTimer *timer = qobject_cast<QTimer *>( sender() );
176  Q_ASSERT( timer );
177 
178  QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
179  Q_ASSERT( reply );
180 
181  QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
182 
183  if ( reply->isRunning() )
184  reply->close();
185 
186  emit requestTimedOut( reply );
187 }
188 
189 QString QgsNetworkAccessManager::cacheLoadControlName( QNetworkRequest::CacheLoadControl theControl )
190 {
191  switch ( theControl )
192  {
193  case QNetworkRequest::AlwaysNetwork:
194  return "AlwaysNetwork";
195  break;
196  case QNetworkRequest::PreferNetwork:
197  return "PreferNetwork";
198  break;
199  case QNetworkRequest::PreferCache:
200  return "PreferCache";
201  break;
202  case QNetworkRequest::AlwaysCache:
203  return "AlwaysCache";
204  break;
205  default:
206  break;
207  }
208  return "PreferNetwork";
209 }
210 
211 QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromName( const QString &theName )
212 {
213  if ( theName == "AlwaysNetwork" )
214  {
215  return QNetworkRequest::AlwaysNetwork;
216  }
217  else if ( theName == "PreferNetwork" )
218  {
219  return QNetworkRequest::PreferNetwork;
220  }
221  else if ( theName == "PreferCache" )
222  {
223  return QNetworkRequest::PreferCache;
224  }
225  else if ( theName == "AlwaysCache" )
226  {
227  return QNetworkRequest::AlwaysCache;
228  }
229  return QNetworkRequest::PreferNetwork;
230 }
231 
233 {
234  QNetworkProxy proxy;
235  QStringList excludes;
236 
237  QSettings settings;
238 
239  mUseSystemProxy = false;
240 
241  if ( this != instance() )
242  {
243  Qt::ConnectionType connectionType = thread() == instance()->thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection;
244 
245  connect( this, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
246  instance(), SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ),
247  connectionType );
248 
249  connect( this, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
250  instance(), SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
251  connectionType );
252 
253  connect( this, SIGNAL( requestTimedOut( QNetworkReply* ) ),
254  instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ) );
255 
256 #ifndef QT_NO_OPENSSL
257  connect( this, SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
258  instance(), SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
259  connectionType );
260 #endif
261  }
262 
263  // check if proxy is enabled
264  bool proxyEnabled = settings.value( "proxy/proxyEnabled", false ).toBool();
265  if ( proxyEnabled )
266  {
267  excludes = settings.value( "proxy/proxyExcludedUrls", "" ).toString().split( "|", QString::SkipEmptyParts );
268 
269  //read type, host, port, user, passw from settings
270  QString proxyHost = settings.value( "proxy/proxyHost", "" ).toString();
271  int proxyPort = settings.value( "proxy/proxyPort", "" ).toString().toInt();
272  QString proxyUser = settings.value( "proxy/proxyUser", "" ).toString();
273  QString proxyPassword = settings.value( "proxy/proxyPassword", "" ).toString();
274 
275  QString proxyTypeString = settings.value( "proxy/proxyType", "" ).toString();
276 
277  if ( proxyTypeString == "DefaultProxy" )
278  {
279  mUseSystemProxy = true;
280  QNetworkProxyFactory::setUseSystemConfiguration( true );
281  QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
282  if ( !proxies.isEmpty() )
283  {
284  proxy = proxies.first();
285  }
286  QgsDebugMsg( "setting default proxy" );
287  }
288  else
289  {
290  QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
291  if ( proxyTypeString == "Socks5Proxy" )
292  {
293  proxyType = QNetworkProxy::Socks5Proxy;
294  }
295  else if ( proxyTypeString == "HttpProxy" )
296  {
297  proxyType = QNetworkProxy::HttpProxy;
298  }
299  else if ( proxyTypeString == "HttpCachingProxy" )
300  {
301  proxyType = QNetworkProxy::HttpCachingProxy;
302  }
303  else if ( proxyTypeString == "FtpCachingProxy" )
304  {
305  proxyType = QNetworkProxy::FtpCachingProxy;
306  }
307  QgsDebugMsg( QString( "setting proxy %1 %2:%3 %4/%5" )
308  .arg( proxyType )
309  .arg( proxyHost ).arg( proxyPort )
310  .arg( proxyUser ).arg( proxyPassword )
311  );
312  proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
313  }
314  }
315 
316 #if QT_VERSION >= 0x40500
317  setFallbackProxyAndExcludes( proxy, excludes );
318 
319  QNetworkDiskCache *newcache = qobject_cast<QNetworkDiskCache*>( cache() );
320  if ( !newcache )
321  newcache = new QNetworkDiskCache( this );
322 
323  QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString();
324  qint64 cacheSize = settings.value( "cache/size", 50 * 1024 * 1024 ).toULongLong();
325  QgsDebugMsg( QString( "setCacheDirectory: %1" ).arg( cacheDirectory ) );
326  QgsDebugMsg( QString( "setMaximumCacheSize: %1" ).arg( cacheSize ) );
327  newcache->setCacheDirectory( cacheDirectory );
328  newcache->setMaximumCacheSize( cacheSize );
329  QgsDebugMsg( QString( "cacheDirectory: %1" ).arg( newcache->cacheDirectory() ) );
330  QgsDebugMsg( QString( "maximumCacheSize: %1" ).arg( newcache->maximumCacheSize() ) );
331 
332  if ( cache() != newcache )
333  setCache( newcache );
334 #else
335  setProxy( proxy );
336 #endif
337 }
338 
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.
static QgsNetworkAccessManager * instance()
Definition: qgssingleton.h:23
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
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)