• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KIO

  • sources
  • kde-4.14
  • kdelibs
  • kio
  • misc
  • kpac
proxyscout.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2003 Malte Starostik <malte@kde.org>
3  Copyright (c) 2011 Dawit Alemayehu <adawit@kde.org>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "proxyscout.h"
22 
23 #include "config-kpac.h"
24 
25 #include "discovery.h"
26 #include "script.h"
27 
28 #include <kdebug.h>
29 #include <klocale.h>
30 #include <knotification.h>
31 #include <kprotocolmanager.h>
32 #include <kpluginfactory.h>
33 #include <kpluginloader.h>
34 
35 #ifndef KPAC_NO_SOLID
36 #include <solid/networking.h>
37 #endif
38 
39 #include <QtCore/QFileSystemWatcher>
40 
41 #include <cstdlib>
42 #include <ctime>
43 
44 K_PLUGIN_FACTORY(ProxyScoutFactory,
45  registerPlugin<KPAC::ProxyScout>();
46  )
47 K_EXPORT_PLUGIN(ProxyScoutFactory("KProxyScoutd"))
48 
49 namespace KPAC
50 {
51  enum ProxyType {
52  Unknown = -1,
53  Proxy,
54  Socks,
55  Direct
56  };
57 
58  static ProxyType proxyTypeFor(const QString& mode)
59  {
60  if (mode.compare(QLatin1String("PROXY"), Qt::CaseInsensitive) == 0)
61  return Proxy;
62 
63  if (mode.compare(QLatin1String("DIRECT"), Qt::CaseInsensitive) == 0)
64  return Direct;
65 
66  if (mode.compare(QLatin1String("SOCKS"), Qt::CaseInsensitive) == 0 ||
67  mode.compare(QLatin1String("SOCKS5"), Qt::CaseInsensitive) == 0)
68  return Socks;
69 
70  return Unknown;
71  }
72 
73  ProxyScout::QueuedRequest::QueuedRequest( const QDBusMessage &reply, const KUrl& u, bool sendall )
74  : transaction( reply ), url( u ), sendAll(sendall)
75  {
76  }
77 
78  ProxyScout::ProxyScout(QObject* parent, const QList<QVariant>&)
79  : KDEDModule(parent),
80  m_componentData("proxyscout"),
81  m_downloader( 0 ),
82  m_script( 0 ),
83  m_suspendTime( 0 ),
84  m_debugArea (KDebug::registerArea("proxyscout")),
85  m_watcher( 0 )
86  {
87 #ifndef KPAC_NO_SOLID
88  connect (Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), SLOT(disconnectNetwork()));
89 #endif
90  }
91 
92  ProxyScout::~ProxyScout()
93  {
94  delete m_script;
95  }
96 
97  QStringList ProxyScout::proxiesForUrl( const QString& checkUrl, const QDBusMessage &msg )
98  {
99  KUrl url(checkUrl);
100 
101  if (m_suspendTime) {
102  if ( std::time( 0 ) - m_suspendTime < 300 ) {
103  return QStringList (QLatin1String("DIRECT"));
104  }
105  m_suspendTime = 0;
106  }
107 
108  // Never use a proxy for the script itself
109  if (m_downloader && url.equals(m_downloader->scriptUrl(), KUrl::CompareWithoutTrailingSlash)) {
110  return QStringList (QLatin1String("DIRECT"));
111  }
112 
113  if (m_script) {
114  return handleRequest(url);
115  }
116 
117  if (m_downloader || startDownload()) {
118  msg.setDelayedReply(true);
119  m_requestQueue.append( QueuedRequest( msg, url, true ) );
120  return QStringList(); // return value will be ignored
121  }
122 
123  return QStringList(QLatin1String("DIRECT"));
124  }
125 
126  QString ProxyScout::proxyForUrl( const QString& checkUrl, const QDBusMessage &msg )
127  {
128  KUrl url(checkUrl);
129 
130  if (m_suspendTime) {
131  if ( std::time( 0 ) - m_suspendTime < 300 ) {
132  return QLatin1String("DIRECT");
133  }
134  m_suspendTime = 0;
135  }
136 
137  // Never use a proxy for the script itself
138  if (m_downloader && url.equals(m_downloader->scriptUrl(), KUrl::CompareWithoutTrailingSlash)) {
139  return QLatin1String("DIRECT");
140  }
141 
142  if (m_script) {
143  return handleRequest(url).first();
144  }
145 
146  if (m_downloader || startDownload()) {
147  msg.setDelayedReply(true);
148  m_requestQueue.append( QueuedRequest( msg, url ) );
149  return QString(); // return value will be ignored
150  }
151 
152  return QLatin1String("DIRECT");
153  }
154 
155  void ProxyScout::blackListProxy( const QString& proxy )
156  {
157  m_blackList[ proxy ] = std::time( 0 );
158  }
159 
160  void ProxyScout::reset()
161  {
162  delete m_script;
163  m_script = 0;
164  delete m_downloader;
165  m_downloader = 0;
166  delete m_watcher;
167  m_watcher = 0;
168  m_blackList.clear();
169  m_suspendTime = 0;
170  KProtocolManager::reparseConfiguration();
171  }
172 
173  bool ProxyScout::startDownload()
174  {
175  switch ( KProtocolManager::proxyType() )
176  {
177  case KProtocolManager::WPADProxy:
178  if (m_downloader && !qobject_cast<Discovery*>(m_downloader)) {
179  delete m_downloader;
180  m_downloader = 0;
181  }
182  if (!m_downloader) {
183  m_downloader = new Discovery(this);
184  connect(m_downloader, SIGNAL(result(bool)), this, SLOT(downloadResult(bool)));
185  }
186  break;
187  case KProtocolManager::PACProxy: {
188  if (m_downloader && !qobject_cast<Downloader*>(m_downloader)) {
189  delete m_downloader;
190  m_downloader = 0;
191  }
192  if (!m_downloader) {
193  m_downloader = new Downloader(this);
194  connect(m_downloader, SIGNAL(result(bool)), this, SLOT(downloadResult(bool)));
195  }
196 
197  const KUrl url (KProtocolManager::proxyConfigScript());
198  if (url.isLocalFile()) {
199  if (!m_watcher) {
200  m_watcher = new QFileSystemWatcher(this);
201  connect (m_watcher, SIGNAL(fileChanged(QString)), SLOT(proxyScriptFileChanged(QString)));
202  }
203  proxyScriptFileChanged(url.path());
204  } else {
205  delete m_watcher;
206  m_watcher = 0;
207  m_downloader->download( url );
208  }
209  break;
210  }
211  default:
212  return false;
213  }
214 
215  return true;
216  }
217 
218  void ProxyScout::disconnectNetwork()
219  {
220  // NOTE: We only connect to Solid's network notifier's shouldDisconnect
221  // signal because we only want to redo WPAD when a network interface is
222  // brought out of hibernation or restarted for whatever reason.
223  reset();
224  }
225 
226  void ProxyScout::downloadResult( bool success )
227  {
228  if ( success ) {
229  try
230  {
231  if (!m_script) {
232  m_script = new Script(m_downloader->script());
233  }
234  }
235  catch ( const Script::Error& e )
236  {
237  kWarning() << "Error:" << e.message();
238  KNotification *notify= new KNotification ( "script-error" );
239  notify->setText( i18n("The proxy configuration script is invalid:\n%1" , e.message() ) );
240  notify->setComponentData(m_componentData);
241  notify->sendEvent();
242  success = false;
243  }
244  } else {
245  KNotification *notify = new KNotification ("download-error");
246  notify->setText( m_downloader->error() );
247  notify->setComponentData(m_componentData);
248  notify->sendEvent();
249  }
250 
251  if (success) {
252  for (RequestQueue::Iterator it = m_requestQueue.begin(), itEnd = m_requestQueue.end(); it != itEnd; ++it) {
253  if ((*it).sendAll) {
254  const QVariant result (handleRequest((*it).url));
255  QDBusConnection::sessionBus().send((*it).transaction.createReply(result));
256  } else {
257  const QVariant result (handleRequest((*it).url).first());
258  QDBusConnection::sessionBus().send((*it).transaction.createReply(result));
259  }
260  }
261  } else {
262  for (RequestQueue::Iterator it = m_requestQueue.begin(), itEnd = m_requestQueue.end(); it != itEnd; ++it) {
263  QDBusConnection::sessionBus().send((*it).transaction.createReply(QString::fromLatin1("DIRECT")));
264  }
265  }
266 
267  m_requestQueue.clear();
268 
269  // Suppress further attempts for 5 minutes
270  if ( !success ) {
271  m_suspendTime = std::time( 0 );
272  }
273  }
274 
275  void ProxyScout::proxyScriptFileChanged(const QString& path)
276  {
277  // Should never get called if we do not have a watcher...
278  Q_ASSERT(m_watcher);
279 
280  // Remove the current file being watched...
281  if (!m_watcher->files().isEmpty()) {
282  m_watcher->removePaths(m_watcher->files());
283  }
284 
285  // NOTE: QFileSystemWatcher only adds a path if it either exists or
286  // is not already being monitored.
287  m_watcher->addPath(path);
288 
289  // Reload...
290  m_downloader->download(KUrl::fromPath(path));
291  }
292 
293  QStringList ProxyScout::handleRequest( const KUrl& url )
294  {
295  try
296  {
297  QStringList proxyList;
298  const QString result = m_script->evaluate(url).trimmed();
299  const QStringList proxies = result.split(QLatin1Char(';'), QString::SkipEmptyParts);
300  const int size = proxies.count();
301 
302  for (int i = 0; i < size; ++i) {
303  QString mode, address;
304  const QString proxy = proxies.at(i).trimmed();
305  const int index = proxy.indexOf(QLatin1Char(' '));
306  if (index == -1) { // Only "DIRECT" should match this!
307  mode = proxy;
308  address = proxy;
309  } else {
310  mode = proxy.left(index);
311  address = proxy.mid(index + 1).trimmed();
312  }
313 
314  const ProxyType type = proxyTypeFor(mode);
315  if (type == Unknown) {
316  continue;
317  }
318 
319  if (type == Proxy || type == Socks) {
320  const int index = address.indexOf(QLatin1Char(':'));
321  if (index == -1 || !KProtocolInfo::isKnownProtocol(address.left(index))) {
322  const QString protocol ((type == Proxy ? QLatin1String("http://") : QLatin1String("socks://")));
323  const KUrl url (protocol + address);
324  if (url.isValid()) {
325  address = url.url();
326  } else {
327  continue;
328  }
329  }
330  }
331 
332  if (type == Direct || !m_blackList.contains(address)) {
333  proxyList << address;
334  } else if (std::time(0) - m_blackList[address] > 1800) { // 30 minutes
335  // black listing expired
336  m_blackList.remove( address );
337  proxyList << address;
338  }
339  }
340 
341  if (!proxyList.isEmpty()) {
342  kDebug(m_debugArea) << proxyList;
343  return proxyList;
344  }
345  // FIXME: blacklist
346  }
347  catch ( const Script::Error& e )
348  {
349  kError() << e.message();
350  KNotification *n=new KNotification( "evaluation-error" );
351  n->setText( i18n( "The proxy configuration script returned an error:\n%1" , e.message() ) );
352  n->setComponentData(m_componentData);
353  n->sendEvent();
354  }
355 
356  return QStringList (QLatin1String("DIRECT"));
357  }
358 }
359 
360 #include "proxyscout.moc"
361 
362 // vim: ts=4 sw=4 et
i18n
QString i18n(const char *text)
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
KProtocolManager::reparseConfiguration
static void reparseConfiguration()
Force a reload of the general config file of io-slaves ( kioslaverc).
Definition: kprotocolmanager.cpp:232
kdebug.h
QDBusMessage::setDelayedReply
void setDelayedReply(bool enable) const
KProtocolInfo::isKnownProtocol
static bool isKnownProtocol(const KUrl &url)
KDEDModule
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
K_PLUGIN_FACTORY
K_PLUGIN_FACTORY(ProxyScoutFactory, registerPlugin< KPAC::ProxyScout >();) namespace KPAC
Definition: proxyscout.cpp:44
QList::at
const T & at(int i) const
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KUrl::fromPath
static KUrl fromPath(const QString &text)
QDBusConnection::sessionBus
QDBusConnection sessionBus()
KUrl::CompareWithoutTrailingSlash
QString::remove
QString & remove(int position, int n)
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
script.h
discovery.h
KUrl
kprotocolmanager.h
knotification.h
QList::count
int count(const T &value) const
QObject
kpluginloader.h
QList::isEmpty
bool isEmpty() const
KProtocolManager::PACProxy
Definition: kprotocolmanager.h:199
KNotification::setText
void setText(const QString &text)
QDBusConnection::send
bool send(const QDBusMessage &message) const
QString::trimmed
QString trimmed() const
KDebug::registerArea
static int registerArea(const QByteArray &areaName, bool enabled=true)
Unknown
proxyscout.h
KProtocolManager::WPADProxy
Definition: kprotocolmanager.h:200
QString
QList< QVariant >
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KNotification::setComponentData
void setComponentData(const KComponentData &componentData)
QStringList
QLatin1Char
KNotification
KProtocolManager::proxyConfigScript
static QString proxyConfigScript()
Returns the URL of the script for automatic proxy configuration.
Definition: kprotocolmanager.cpp:983
KNotification::sendEvent
void sendEvent()
QFileSystemWatcher
QUrl::isValid
bool isValid() const
QString::mid
QString mid(int position, int n) const
KProtocolManager::proxyType
static ProxyType proxyType()
Returns the type of proxy configuration that is used.
Definition: kprotocolmanager.cpp:312
QDBusMessage
QLatin1String
kpluginfactory.h
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
QString::left
QString left(int n) const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
reset
KGuiItem reset()
KUrl::isLocalFile
bool isLocalFile() const
QString::compare
int compare(const QString &other) const
KUrl::equals
bool equals(const KUrl &u, const EqualsOptions &options=0) const
K_EXPORT_PLUGIN
#define K_EXPORT_PLUGIN(factory)
QVariant
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:53 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal