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