QGIS API Documentation  2.11.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 
36 {
37  public:
40 
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 ) );
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 //
93 {
95  return sInstance;
96 }
97 
99  : QNetworkAccessManager( parent )
100  , mUseSystemProxy( false )
101 {
103 }
104 
106 {
107 }
108 
110 {
111  mProxyFactories.insert( 0, factory );
112 }
113 
115 {
116  mProxyFactories.removeAll( factory );
117 }
118 
120 {
121  return mProxyFactories;
122 }
123 
125 {
126  return mExcludedURLs;
127 }
128 
130 {
131  return mFallbackProxy;
132 }
133 
135 {
136  QgsDebugMsg( QString( "proxy settings: (type:%1 host: %2:%3, user:%4, password:%5" )
137  .arg( proxy.type() == QNetworkProxy::DefaultProxy ? "DefaultProxy" :
138  proxy.type() == QNetworkProxy::Socks5Proxy ? "Socks5Proxy" :
139  proxy.type() == QNetworkProxy::NoProxy ? "NoProxy" :
140  proxy.type() == QNetworkProxy::HttpProxy ? "HttpProxy" :
141  proxy.type() == QNetworkProxy::HttpCachingProxy ? "HttpCachingProxy" :
142  proxy.type() == QNetworkProxy::FtpCachingProxy ? "FtpCachingProxy" :
143  "Undefined" )
144  .arg( proxy.hostName() )
145  .arg( proxy.port() )
146  .arg( proxy.user() )
147  .arg( proxy.password().isEmpty() ? "not set" : "set" ) );
148 
149  mFallbackProxy = proxy;
150  mExcludedURLs = excludes;
151 }
152 
153 QNetworkReply *QgsNetworkAccessManager::createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData )
154 {
155  QSettings s;
156 
157  QNetworkRequest *pReq(( QNetworkRequest * ) &req ); // hack user agent
158 
159  QString userAgent = s.value( "/qgis/networkAndProxy/userAgent", "Mozilla/5.0" ).toString();
160  if ( !userAgent.isEmpty() )
161  userAgent += " ";
162  userAgent += QString( "QGIS/%1" ).arg( QGis::QGIS_VERSION );
163  pReq->setRawHeader( "User-Agent", userAgent.toUtf8() );
164 
165  emit requestAboutToBeCreated( op, req, outgoingData );
166  QNetworkReply *reply = QNetworkAccessManager::createRequest( op, req, outgoingData );
167 
168  emit requestCreated( reply );
169 
170  // abort request, when network timeout happens
171  QTimer *timer = new QTimer( reply );
172  connect( timer, SIGNAL( timeout() ), this, SLOT( abortRequest() ) );
173  timer->setSingleShot( true );
174  timer->start( s.value( "/qgis/networkAndProxy/networkTimeout", "20000" ).toInt() );
175 
176  connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), timer, SLOT( start() ) );
177  connect( reply, SIGNAL( uploadProgress( qint64, qint64 ) ), timer, SLOT( start() ) );
178 
179  return reply;
180 }
181 
182 void QgsNetworkAccessManager::abortRequest()
183 {
184  QTimer *timer = qobject_cast<QTimer *>( sender() );
185  Q_ASSERT( timer );
186 
187  QNetworkReply *reply = qobject_cast<QNetworkReply *>( timer->parent() );
188  Q_ASSERT( reply );
189 
190  QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) );
191 
192  if ( reply->isRunning() )
193  reply->close();
194 
195  emit requestTimedOut( reply );
196 }
197 
198 QString QgsNetworkAccessManager::cacheLoadControlName( QNetworkRequest::CacheLoadControl theControl )
199 {
200  switch ( theControl )
201  {
202  case QNetworkRequest::AlwaysNetwork:
203  return "AlwaysNetwork";
204  break;
205  case QNetworkRequest::PreferNetwork:
206  return "PreferNetwork";
207  break;
208  case QNetworkRequest::PreferCache:
209  return "PreferCache";
210  break;
211  case QNetworkRequest::AlwaysCache:
212  return "AlwaysCache";
213  break;
214  default:
215  break;
216  }
217  return "PreferNetwork";
218 }
219 
220 QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromName( const QString &theName )
221 {
222  if ( theName == "AlwaysNetwork" )
223  {
224  return QNetworkRequest::AlwaysNetwork;
225  }
226  else if ( theName == "PreferNetwork" )
227  {
228  return QNetworkRequest::PreferNetwork;
229  }
230  else if ( theName == "PreferCache" )
231  {
232  return QNetworkRequest::PreferCache;
233  }
234  else if ( theName == "AlwaysCache" )
235  {
236  return QNetworkRequest::AlwaysCache;
237  }
238  return QNetworkRequest::PreferNetwork;
239 }
240 
242 {
244  QStringList excludes;
245 
246  QSettings settings;
247 
248  mUseSystemProxy = false;
249 
250  if ( this != instance() )
251  {
252  Qt::ConnectionType connectionType = thread() == instance()->thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection;
253 
256  connectionType );
257 
258  connect( this, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ),
260  connectionType );
261 
262  connect( this, SIGNAL( requestTimedOut( QNetworkReply* ) ),
263  instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ) );
264 
265 #ifndef QT_NO_OPENSSL
266  connect( this, SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
267  instance(), SIGNAL( sslErrors( QNetworkReply *, const QList<QSslError> & ) ),
268  connectionType );
269 #endif
270  }
271 
272  // check if proxy is enabled
273  bool proxyEnabled = settings.value( "proxy/proxyEnabled", false ).toBool();
274  if ( proxyEnabled )
275  {
276  excludes = settings.value( "proxy/proxyExcludedUrls", "" ).toString().split( "|", QString::SkipEmptyParts );
277 
278  //read type, host, port, user, passw from settings
279  QString proxyHost = settings.value( "proxy/proxyHost", "" ).toString();
280  int proxyPort = settings.value( "proxy/proxyPort", "" ).toString().toInt();
281  QString proxyUser = settings.value( "proxy/proxyUser", "" ).toString();
282  QString proxyPassword = settings.value( "proxy/proxyPassword", "" ).toString();
283 
284  QString proxyTypeString = settings.value( "proxy/proxyType", "" ).toString();
285 
286  if ( proxyTypeString == "DefaultProxy" )
287  {
288  mUseSystemProxy = true;
291  if ( !proxies.isEmpty() )
292  {
293  proxy = proxies.first();
294  }
295  QgsDebugMsg( "setting default proxy" );
296  }
297  else
298  {
299  QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
300  if ( proxyTypeString == "Socks5Proxy" )
301  {
302  proxyType = QNetworkProxy::Socks5Proxy;
303  }
304  else if ( proxyTypeString == "HttpProxy" )
305  {
306  proxyType = QNetworkProxy::HttpProxy;
307  }
308  else if ( proxyTypeString == "HttpCachingProxy" )
309  {
310  proxyType = QNetworkProxy::HttpCachingProxy;
311  }
312  else if ( proxyTypeString == "FtpCachingProxy" )
313  {
314  proxyType = QNetworkProxy::FtpCachingProxy;
315  }
316  QgsDebugMsg( QString( "setting proxy %1 %2:%3 %4/%5" )
317  .arg( proxyType )
318  .arg( proxyHost ).arg( proxyPort )
319  .arg( proxyUser ).arg( proxyPassword )
320  );
321  proxy = QNetworkProxy( proxyType, proxyHost, proxyPort, proxyUser, proxyPassword );
322  }
323  }
324 
325  setFallbackProxyAndExcludes( proxy, excludes );
326 
327  QNetworkDiskCache *newcache = qobject_cast<QNetworkDiskCache*>( cache() );
328  if ( !newcache )
329  newcache = new QNetworkDiskCache( this );
330 
331  QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString();
332  qint64 cacheSize = settings.value( "cache/size", 50 * 1024 * 1024 ).toULongLong();
333  QgsDebugMsg( QString( "setCacheDirectory: %1" ).arg( cacheDirectory ) );
334  QgsDebugMsg( QString( "setMaximumCacheSize: %1" ).arg( cacheSize ) );
335  newcache->setCacheDirectory( cacheDirectory );
336  newcache->setMaximumCacheSize( cacheSize );
337  QgsDebugMsg( QString( "cacheDirectory: %1" ).arg( newcache->cacheDirectory() ) );
338  QgsDebugMsg( QString( "maximumCacheSize: %1" ).arg( newcache->maximumCacheSize() ) );
339 
340  if ( cache() != newcache )
341  setCache( newcache );
342 }
343 
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 *)
virtual QNetworkReply * createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData)
QString password() const
static QString cacheLoadControlName(QNetworkRequest::CacheLoadControl theControl)
Get name for QNetworkRequest::CacheLoadControl.
void sslErrors(QNetworkReply *reply, const QList< QSslError > &errors)
QString user() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
quint16 port() const
QgsNetworkAccessManager(QObject *parent=0)
QObject * sender() const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static QNetworkRequest::CacheLoadControl cacheLoadControlFromName(const QString &theName)
Get QNetworkRequest::CacheLoadControl from name.
bool isRunning() const
const QNetworkProxy & fallbackProxy() const
retrieve fall back proxy (for urls that no factory returned proxies for)
void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
void setupDefaultProxyAndCache()
Setup the NAM according to the user's settings.
QThread * thread() const
virtual QNetworkReply * createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData=0) override
QString toString(QFlags< QUrl::FormattingOption > options) const
qulonglong toULongLong(bool *ok) const
static const QString qgisSettingsDirPath()
Returns the path to the settings directory in user's home dir.
QString tr(const char *sourceText, const char *disambiguation, int n)
const QList< QNetworkProxyFactory * > proxyFactories() const
retrieve proxy factory list
QAbstractNetworkCache * cache() const
int size() const
void setCacheDirectory(const QString &cacheDir)
void setProxyFactory(QNetworkProxyFactory *factory)
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
QNetworkProxy proxy() const
QString hostName() const
virtual QList< QNetworkProxy > queryProxy(const QNetworkProxyQuery &query)=0
int toInt(bool *ok) const
QNetworkProxy::ProxyType type() const
void requestTimedOut(QNetworkReply *)
int toInt(bool *ok, int base) const
bool isEmpty() const
bool isEmpty() const
int removeAll(const T &value)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
void setMaximumCacheSize(qint64 size)
void removeProxyFactory(QNetworkProxyFactory *factory)
remove a factory from the proxy factories list
QCoreApplication * instance()
T & first()
void insertProxyFactory(QNetworkProxyFactory *factory)
insert a factory into the proxy factories list
QString cacheDirectory() const
QVariant value(const QString &key, const QVariant &defaultValue) const
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
void insert(int i, const T &value)
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
QList< QNetworkProxy > systemProxyForQuery(const QNetworkProxyQuery &query)
QUrl url() const
bool toBool() const
void start(int msec)
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
void setUseSystemConfiguration(bool enable)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
virtual void close()
void requestAboutToBeCreated(QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice *)
void setCache(QAbstractNetworkCache *cache)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void setFallbackProxyAndExcludes(const QNetworkProxy &proxy, const QStringList &excludes)
set fallback proxy and URL that shouldn't use it.
virtual QList< QNetworkProxy > queryProxy(const QNetworkProxyQuery &query=QNetworkProxyQuery()) override
qint64 maximumCacheSize() const
void setSingleShot(bool singleShot)
QByteArray toUtf8() const