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