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

KIO

  • 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
44K_PLUGIN_FACTORY(ProxyScoutFactory,
45 registerPlugin<KPAC::ProxyScout>();
46 )
47K_EXPORT_PLUGIN(ProxyScoutFactory("KProxyScoutd"))
48
49namespace 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
KDEDModule
KNotification
KNotification::sendEvent
void sendEvent()
KNotification::setComponentData
void setComponentData(const KComponentData &componentData)
KNotification::setText
void setText(const QString &text)
K_EXPORT_PLUGIN
#define K_EXPORT_PLUGIN(factory)
KProtocolManager::proxyConfigScript
static QString proxyConfigScript()
Returns the URL of the script for automatic proxy configuration.
Definition: kprotocolmanager.cpp:984
KProtocolManager::PACProxy
@ PACProxy
Definition: kprotocolmanager.h:199
KProtocolManager::WPADProxy
@ WPADProxy
Definition: kprotocolmanager.h:200
KProtocolManager::reparseConfiguration
static void reparseConfiguration()
Force a reload of the general config file of io-slaves ( kioslaverc).
Definition: kprotocolmanager.cpp:232
KProtocolManager::proxyType
static ProxyType proxyType()
Returns the type of proxy configuration that is used.
Definition: kprotocolmanager.cpp:312
KUrl
KUrl::fromPath
static KUrl fromPath(const QString &text)
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::equals
bool equals(const KUrl &u, const EqualsOptions &options=0) const
KUrl::isLocalFile
bool isLocalFile() const
KUrl::CompareWithoutTrailingSlash
CompareWithoutTrailingSlash
QList
QObject
discovery.h
kDebug
#define kDebug
kWarning
#define kWarning
kdebug.h
klocale.h
i18n
QString i18n(const char *text)
knotification.h
kpluginfactory.h
kpluginloader.h
kprotocolmanager.h
Unknown
Unknown
KPAC
Definition: discovery.cpp:58
reset
KGuiItem reset()
K_PLUGIN_FACTORY
K_PLUGIN_FACTORY(ProxyScoutFactory, registerPlugin< KPAC::ProxyScout >();) namespace KPAC
Definition: proxyscout.cpp:44
proxyscout.h
script.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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.14.38 API Reference

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