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

KIO

proxyscout.cpp
Go to the documentation of this file.
00001 /*
00002    Copyright (c) 2003 Malte Starostik <malte@kde.org>
00003    Copyright (c) 2011 Dawit Alemayehu <adawit@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "proxyscout.h"
00022 
00023 #include "config-kpac.h"
00024 
00025 #include "discovery.h"
00026 #include "script.h"
00027 
00028 #include <kdebug.h>
00029 #include <klocale.h>
00030 #include <knotification.h>
00031 #include <kprotocolmanager.h>
00032 #include <kpluginfactory.h>
00033 #include <kpluginloader.h>
00034 
00035 #ifndef KPAC_NO_SOLID
00036 #include <solid/networking.h>
00037 #endif
00038 
00039 #include <QtCore/QFileSystemWatcher>
00040 
00041 #include <cstdlib>
00042 #include <ctime>
00043 
00044 K_PLUGIN_FACTORY(ProxyScoutFactory,
00045                  registerPlugin<KPAC::ProxyScout>();
00046     )
00047 K_EXPORT_PLUGIN(ProxyScoutFactory("KProxyScoutd"))
00048 
00049 namespace KPAC
00050 {
00051     enum ProxyType {
00052         Unknown = -1,
00053         Proxy,
00054         Socks,
00055         Direct
00056     };
00057 
00058     static ProxyType proxyTypeFor(const QString& mode)
00059     {
00060         if (mode.compare(QLatin1String("PROXY"), Qt::CaseInsensitive) == 0)
00061             return Proxy;
00062 
00063         if (mode.compare(QLatin1String("DIRECT"), Qt::CaseInsensitive) == 0)
00064             return Direct;
00065 
00066         if (mode.compare(QLatin1String("SOCKS"), Qt::CaseInsensitive) == 0 ||
00067             mode.compare(QLatin1String("SOCKS5"), Qt::CaseInsensitive) == 0)
00068             return Socks;
00069 
00070         return Unknown;
00071     }
00072 
00073     ProxyScout::QueuedRequest::QueuedRequest( const QDBusMessage &reply, const KUrl& u, bool sendall )
00074         : transaction( reply ), url( u ), sendAll(sendall)
00075     {
00076     }
00077 
00078     ProxyScout::ProxyScout(QObject* parent, const QList<QVariant>&)
00079         : KDEDModule(parent),
00080           m_componentData("proxyscout"),
00081           m_downloader( 0 ),
00082           m_script( 0 ),
00083           m_suspendTime( 0 ),
00084           m_debugArea (KDebug::registerArea("proxyscout")),
00085           m_watcher( 0 )
00086     {
00087 #ifndef KPAC_NO_SOLID
00088         connect (Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), SLOT(disconnectNetwork()));
00089 #endif
00090     }
00091 
00092     ProxyScout::~ProxyScout()
00093     {
00094         delete m_script;
00095     }
00096 
00097     QStringList ProxyScout::proxiesForUrl( const QString& checkUrl, const QDBusMessage &msg )
00098     {
00099         KUrl url(checkUrl);
00100 
00101         if (m_suspendTime) {
00102             if ( std::time( 0 ) - m_suspendTime < 300 ) {
00103                 return QStringList (QLatin1String("DIRECT"));
00104             }
00105             m_suspendTime = 0;
00106         }
00107 
00108         // Never use a proxy for the script itself
00109         if (m_downloader && url.equals(m_downloader->scriptUrl(), KUrl::CompareWithoutTrailingSlash)) {
00110             return QStringList (QLatin1String("DIRECT"));
00111         }
00112 
00113         if (m_script) {
00114             return handleRequest(url);
00115         }
00116 
00117         if (m_downloader || startDownload()) {
00118             msg.setDelayedReply(true);
00119             m_requestQueue.append( QueuedRequest( msg, url, true ) );
00120             return QStringList();   // return value will be ignored
00121         }
00122 
00123         return QStringList(QLatin1String("DIRECT"));
00124     }
00125 
00126     QString ProxyScout::proxyForUrl( const QString& checkUrl, const QDBusMessage &msg )
00127     {
00128         KUrl url(checkUrl);
00129 
00130         if (m_suspendTime) {
00131             if ( std::time( 0 ) - m_suspendTime < 300 ) {
00132                 return QLatin1String("DIRECT");
00133             }
00134             m_suspendTime = 0;
00135         }
00136 
00137         // Never use a proxy for the script itself
00138         if (m_downloader && url.equals(m_downloader->scriptUrl(), KUrl::CompareWithoutTrailingSlash)) {
00139             return QLatin1String("DIRECT");
00140         }
00141 
00142         if (m_script) {
00143             return handleRequest(url).first();
00144         }
00145 
00146         if (m_downloader || startDownload()) {
00147             msg.setDelayedReply(true);
00148             m_requestQueue.append( QueuedRequest( msg, url ) );
00149             return QString();   // return value will be ignored
00150         }
00151 
00152         return QLatin1String("DIRECT");
00153     }
00154 
00155     void ProxyScout::blackListProxy( const QString& proxy )
00156     {
00157         m_blackList[ proxy ] = std::time( 0 );
00158     }
00159 
00160     void ProxyScout::reset()
00161     {
00162         delete m_script;
00163         m_script = 0;
00164         delete m_downloader;
00165         m_downloader = 0;
00166         delete m_watcher;
00167         m_watcher = 0;
00168         m_blackList.clear();
00169         m_suspendTime = 0;
00170         KProtocolManager::reparseConfiguration();
00171     }
00172 
00173     bool ProxyScout::startDownload()
00174     {
00175         switch ( KProtocolManager::proxyType() )
00176         {
00177             case KProtocolManager::WPADProxy:
00178                 if (m_downloader && !qobject_cast<Discovery*>(m_downloader)) {
00179                     delete m_downloader;
00180                     m_downloader = 0;
00181                 }
00182                 if (!m_downloader) {
00183                     m_downloader = new Discovery(this);
00184                     connect(m_downloader, SIGNAL(result(bool)), this, SLOT(downloadResult(bool)));
00185                 }
00186                 break;
00187             case KProtocolManager::PACProxy: {
00188                 if (m_downloader && !qobject_cast<Downloader*>(m_downloader)) {
00189                     delete m_downloader;
00190                     m_downloader = 0;
00191                 }
00192                 if (!m_downloader) {
00193                     m_downloader = new Downloader(this);
00194                     connect(m_downloader, SIGNAL(result(bool)), this, SLOT(downloadResult(bool)));
00195                 }
00196 
00197                 const KUrl url (KProtocolManager::proxyConfigScript());
00198                 if (url.isLocalFile()) {
00199                     if (!m_watcher) {
00200                         m_watcher = new QFileSystemWatcher(this);
00201                         connect (m_watcher, SIGNAL(fileChanged(QString)), SLOT(proxyScriptFileChanged(QString)));
00202                     }
00203                     proxyScriptFileChanged(url.path());
00204                 } else {
00205                     delete m_watcher;
00206                     m_watcher = 0;
00207                     m_downloader->download( url );
00208                 }
00209                 break;
00210             }
00211             default:
00212                 return false;
00213         }
00214 
00215         return true;
00216     }
00217 
00218     void ProxyScout::disconnectNetwork()
00219     {
00220         // NOTE: We only connect to Solid's network notifier's shouldDisconnect
00221         // signal because we only want to redo WPAD when a network interface is 
00222         // brought out of hibernation or restarted for whatever reason.
00223         reset();
00224     }
00225 
00226     void ProxyScout::downloadResult( bool success )
00227     {
00228         if ( success ) {
00229             try
00230             {
00231                 if (!m_script) {
00232                     m_script = new Script(m_downloader->script());
00233                 }
00234             }
00235             catch ( const Script::Error& e )
00236             {
00237                 kWarning() << "Error:" << e.message();
00238                 KNotification *notify= new KNotification ( "script-error" );
00239                 notify->setText( i18n("The proxy configuration script is invalid:\n%1" , e.message() ) );
00240                 notify->setComponentData(m_componentData);
00241                 notify->sendEvent();
00242                 success = false;
00243             }
00244         } else {
00245             KNotification *notify = new KNotification ("download-error");
00246             notify->setText( m_downloader->error() );
00247             notify->setComponentData(m_componentData);
00248             notify->sendEvent();
00249         }
00250 
00251         if (success) {
00252             for (RequestQueue::Iterator it = m_requestQueue.begin(), itEnd = m_requestQueue.end(); it != itEnd; ++it) {
00253                 if ((*it).sendAll) {
00254                     const QVariant result (handleRequest((*it).url));
00255                     QDBusConnection::sessionBus().send((*it).transaction.createReply(result));
00256                 } else {
00257                     const QVariant result (handleRequest((*it).url).first());
00258                     QDBusConnection::sessionBus().send((*it).transaction.createReply(result));
00259                 }
00260             }
00261         } else {
00262             for (RequestQueue::Iterator it = m_requestQueue.begin(), itEnd = m_requestQueue.end(); it != itEnd; ++it) {
00263                 QDBusConnection::sessionBus().send((*it).transaction.createReply(QString::fromLatin1("DIRECT")));
00264             }
00265         }
00266 
00267         m_requestQueue.clear();
00268 
00269         // Suppress further attempts for 5 minutes
00270         if ( !success ) {
00271             m_suspendTime = std::time( 0 );
00272         }
00273     }
00274 
00275     void ProxyScout::proxyScriptFileChanged(const QString& path)
00276     {
00277         // Should never get called if we do not have a watcher...
00278         Q_ASSERT(m_watcher);
00279 
00280         // Remove the current file being watched...
00281         if (!m_watcher->files().isEmpty()) {
00282            m_watcher->removePaths(m_watcher->files());
00283         }
00284 
00285         // NOTE: QFileSystemWatcher only adds a path if it either exists or
00286         // is not already being monitored.
00287         m_watcher->addPath(path);
00288 
00289         // Reload...
00290         m_downloader->download( KUrl( path ) );
00291     }
00292 
00293     QStringList ProxyScout::handleRequest( const KUrl& url )
00294     {
00295         try
00296         {
00297             QStringList proxyList;
00298             const QString result = m_script->evaluate(url).trimmed();
00299             const QStringList proxies = result.split(QLatin1Char(';'), QString::SkipEmptyParts);
00300             const int size = proxies.count();
00301 
00302             for (int i = 0; i < size; ++i) {
00303                 QString mode, address;
00304                 const QString proxy = proxies.at(i).trimmed();
00305                 const int index = proxy.indexOf(QLatin1Char(' '));
00306                 if (index == -1) { // Only "DIRECT" should match this!
00307                     mode = proxy;
00308                     address = proxy;
00309                 } else {
00310                     mode = proxy.left(index);
00311                     address = proxy.mid(index + 1).trimmed();
00312                 }
00313 
00314                 const ProxyType type = proxyTypeFor(mode);
00315                 if (type == Unknown) {
00316                     continue;
00317                 }
00318 
00319                 if (type == Proxy || type == Socks) {
00320                     const int index = address.indexOf(QLatin1Char(':'));
00321                     if (index == -1 || !KProtocolInfo::isKnownProtocol(address.left(index))) {
00322                         const QString protocol ((type == Proxy ? QLatin1String("http://") : QLatin1String("socks://")));
00323                         const KUrl url (protocol + address);
00324                         if (url.isValid()) {
00325                             address = url.url();
00326                         } else {
00327                             continue;
00328                         }
00329                     }
00330                 }
00331 
00332                 if (type == Direct || !m_blackList.contains(address)) {
00333                     proxyList << address;
00334                 } else if (std::time(0) - m_blackList[address] > 1800) { // 30 minutes
00335                     // black listing expired
00336                     m_blackList.remove( address );
00337                     proxyList << address;
00338                 }
00339             }
00340 
00341             if (!proxyList.isEmpty()) {
00342                 kDebug(m_debugArea) << proxyList;
00343                 return proxyList;
00344             }
00345             // FIXME: blacklist
00346         }
00347         catch ( const Script::Error& e )
00348         {
00349             kError() << e.message();
00350             KNotification *n=new KNotification( "evaluation-error" );
00351             n->setText( i18n( "The proxy configuration script returned an error:\n%1" , e.message() ) );
00352             n->setComponentData(m_componentData);
00353             n->sendEvent();
00354         }
00355 
00356         return QStringList (QLatin1String("DIRECT"));
00357     }
00358 }
00359 
00360 #include "proxyscout.moc"
00361 
00362 // vim: ts=4 sw=4 et
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:55:23 by doxygen 1.8.0 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-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 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
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