• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • 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                 m_downloader = new Discovery( this );
00179                 break;
00180             case KProtocolManager::PACProxy:
00181             {
00182                 m_downloader = new Downloader( this );
00183                 KUrl url( KProtocolManager::proxyConfigScript() );
00184                 if (url.isLocalFile()) {
00185                     if (!m_watcher) {
00186                         m_watcher = new QFileSystemWatcher( this );
00187                         connect (m_watcher, SIGNAL(fileChanged(QString)), SLOT(proxyScriptFileChanged(QString)));
00188                     }
00189                     proxyScriptFileChanged(url.path());
00190                 } else {
00191                     delete m_watcher;
00192                     m_watcher = 0;
00193                     m_downloader->download( url );
00194                 }
00195                 break;
00196             }
00197             default:
00198                 return false;
00199         }
00200 
00201         connect(m_downloader, SIGNAL(result(bool)), SLOT(downloadResult(bool)));
00202         return true;
00203     }
00204 
00205     void ProxyScout::disconnectNetwork()
00206     {
00207         // NOTE: We only connect to Solid's network notifier's shouldDisconnect
00208         // signal because we only want to redo WPAD when a network interface is 
00209         // brought out of hibernation or restarted for whatever reason.
00210         reset();
00211     }
00212 
00213     void ProxyScout::downloadResult( bool success )
00214     {
00215         if ( success ) {
00216             try
00217             {
00218                 m_script = new Script( m_downloader->script() );
00219             }
00220             catch ( const Script::Error& e )
00221             {
00222                 kWarning() << "Error:" << e.message();
00223                 KNotification *notify= new KNotification ( "script-error" );
00224                 notify->setText( i18n("The proxy configuration script is invalid:\n%1" , e.message() ) );
00225                 notify->setComponentData(m_componentData);
00226                 notify->sendEvent();
00227                 success = false;
00228             }
00229         } else {
00230             KNotification *notify = new KNotification ("download-error");
00231             notify->setText( m_downloader->error() );
00232             notify->setComponentData(m_componentData);
00233             notify->sendEvent();
00234         }
00235 
00236         if (success) {
00237             for (RequestQueue::Iterator it = m_requestQueue.begin(), itEnd = m_requestQueue.end(); it != itEnd; ++it) {
00238                 if ((*it).sendAll) {
00239                     const QVariant result (handleRequest((*it).url));
00240                     QDBusConnection::sessionBus().send((*it).transaction.createReply(result));
00241                 } else {
00242                     const QVariant result (handleRequest((*it).url).first());
00243                     QDBusConnection::sessionBus().send((*it).transaction.createReply(result));
00244                 }
00245             }
00246         } else {
00247             for (RequestQueue::Iterator it = m_requestQueue.begin(), itEnd = m_requestQueue.end(); it != itEnd; ++it) {
00248                 QDBusConnection::sessionBus().send((*it).transaction.createReply(QString::fromLatin1("DIRECT")));
00249             }
00250         }
00251 
00252         m_requestQueue.clear();
00253         m_downloader->deleteLater();
00254         m_downloader = 0;
00255         // Suppress further attempts for 5 minutes
00256         if ( !success ) {
00257             m_suspendTime = std::time( 0 );
00258         }
00259     }
00260 
00261     void ProxyScout::proxyScriptFileChanged(const QString& path)
00262     {
00263         // Should never get called if we do not have a watcher...
00264         Q_ASSERT(m_watcher);
00265 
00266         // if it does not exist, bogus file was given or it was deleted...
00267         if (QFile::exists(path)) {
00268             // if not contained, first attempt or file was renamed...
00269             if (!m_watcher->files().contains(path)) {
00270                 m_watcher->removePaths(m_watcher->files());
00271                 m_watcher->addPath(path);
00272             }
00273         }
00274 
00275         // Reload...
00276         m_downloader->download( KUrl( path ) );
00277     }
00278 
00279     QStringList ProxyScout::handleRequest( const KUrl& url )
00280     {
00281         try
00282         {
00283             QStringList proxyList;
00284             const QString result = m_script->evaluate(url).trimmed();
00285             const QStringList proxies = result.split(QLatin1Char(';'), QString::SkipEmptyParts);
00286             const int size = proxies.count();
00287 
00288             for (int i = 0; i < size; ++i) {
00289                 QString mode, address;
00290                 const QString proxy = proxies.at(i).trimmed();
00291                 const int index = proxy.indexOf(QLatin1Char(' '));
00292                 if (index == -1) { // Only "DIRECT" should match this!
00293                     mode = proxy;
00294                     address = proxy;
00295                 } else {
00296                     mode = proxy.left(index);
00297                     address = proxy.mid(index + 1).trimmed();
00298                 }
00299 
00300                 const ProxyType type = proxyTypeFor(mode);
00301                 if (type == Unknown) {
00302                     continue;
00303                 }
00304 
00305                 if (type == Proxy || type == Socks) {
00306                     const int index = address.indexOf(QLatin1Char(':'));
00307                     if (index == -1 || !KProtocolInfo::isKnownProtocol(address.left(index))) {
00308                         const QString protocol ((type == Proxy ? QLatin1String("https://") : QLatin1String("socks://")));
00309                         const KUrl url (protocol + address);
00310                         if (url.isValid()) {
00311                             address = url.url();
00312                         } else {
00313                             continue;
00314                         }
00315                     }
00316                 }
00317 
00318                 if (type == Direct || !m_blackList.contains(address)) {
00319                     proxyList << address;
00320                 } else if (std::time(0) - m_blackList[address] > 1800) { // 30 minutes
00321                     // black listing expired
00322                     m_blackList.remove( address );
00323                     proxyList << address;
00324                 }
00325             }
00326 
00327             if (!proxyList.isEmpty()) {
00328                 kDebug(m_debugArea) << proxyList;
00329                 return proxyList;
00330             }
00331             // FIXME: blacklist
00332         }
00333         catch ( const Script::Error& e )
00334         {
00335             kError() << e.message();
00336             KNotification *n=new KNotification( "evaluation-error" );
00337             n->setText( i18n( "The proxy configuration script returned an error:\n%1" , e.message() ) );
00338             n->setComponentData(m_componentData);
00339             n->sendEvent();
00340         }
00341 
00342         return QStringList (QLatin1String("DIRECT"));
00343     }
00344 }
00345 
00346 #include "proxyscout.moc"
00347 
00348 // vim: ts=4 sw=4 et

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal