00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <string.h>
00022 #include <sys/utsname.h>
00023
00024 #include <dcopref.h>
00025 #include <kdebug.h>
00026 #include <kglobal.h>
00027 #include <klocale.h>
00028 #include <kconfig.h>
00029 #include <kstandarddirs.h>
00030 #include <klibloader.h>
00031 #include <kstringhandler.h>
00032 #include <kstaticdeleter.h>
00033 #include <kio/slaveconfig.h>
00034 #include <kio/ioslave_defaults.h>
00035 #include <kio/http_slave_defaults.h>
00036
00037 #include "kprotocolmanager.h"
00038
00039 class
00040 KProtocolManagerPrivate
00041 {
00042 public:
00043 KProtocolManagerPrivate();
00044
00045 ~KProtocolManagerPrivate();
00046
00047 KConfig *config;
00048 KConfig *http_config;
00049 bool init_busy;
00050 KURL url;
00051 QString protocol;
00052 QString proxy;
00053 QString modifiers;
00054 QString useragent;
00055 };
00056
00057 static KProtocolManagerPrivate* d = 0;
00058 static KStaticDeleter<KProtocolManagerPrivate> kpmpksd;
00059
00060 KProtocolManagerPrivate::KProtocolManagerPrivate()
00061 :config(0), http_config(0), init_busy(false)
00062 {
00063 kpmpksd.setObject(d, this);
00064 }
00065
00066 KProtocolManagerPrivate::~KProtocolManagerPrivate()
00067 {
00068 delete config;
00069 delete http_config;
00070 }
00071
00072
00073
00074 #define CFG_DEFAULT_UAGENT(X) \
00075 QString("Mozilla/5.0 (compatible; Konqueror/%1.%2%3) KHTML/%4.%5.%6 (like Gecko)") \
00076 .arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(X).arg(KDE_VERSION_MAJOR).arg(KDE_VERSION_MINOR).arg(KDE_VERSION_RELEASE)
00077
00078 void KProtocolManager::reparseConfiguration()
00079 {
00080 kpmpksd.destructObject();
00081
00082
00083 KIO::SlaveConfig::self()->reset ();
00084 }
00085
00086 KConfig *KProtocolManager::config()
00087 {
00088 if (!d)
00089 d = new KProtocolManagerPrivate;
00090
00091 if (!d->config)
00092 {
00093 d->config = new KConfig("kioslaverc", true, false);
00094 }
00095 return d->config;
00096 }
00097
00098 KConfig *KProtocolManager::http_config()
00099 {
00100 if (!d)
00101 d = new KProtocolManagerPrivate;
00102
00103 if (!d->http_config)
00104 {
00105 d->http_config = new KConfig("kio_httprc", false, false);
00106 }
00107 return d->http_config;
00108 }
00109
00110
00111
00112 int KProtocolManager::readTimeout()
00113 {
00114 KConfig *cfg = config();
00115 cfg->setGroup( QString::null );
00116 int val = cfg->readNumEntry( "ReadTimeout", DEFAULT_READ_TIMEOUT );
00117 return QMAX(MIN_TIMEOUT_VALUE, val);
00118 }
00119
00120 int KProtocolManager::connectTimeout()
00121 {
00122 KConfig *cfg = config();
00123 cfg->setGroup( QString::null );
00124 int val = cfg->readNumEntry( "ConnectTimeout", DEFAULT_CONNECT_TIMEOUT );
00125 return QMAX(MIN_TIMEOUT_VALUE, val);
00126 }
00127
00128 int KProtocolManager::proxyConnectTimeout()
00129 {
00130 KConfig *cfg = config();
00131 cfg->setGroup( QString::null );
00132 int val = cfg->readNumEntry( "ProxyConnectTimeout", DEFAULT_PROXY_CONNECT_TIMEOUT );
00133 return QMAX(MIN_TIMEOUT_VALUE, val);
00134 }
00135
00136 int KProtocolManager::responseTimeout()
00137 {
00138 KConfig *cfg = config();
00139 cfg->setGroup( QString::null );
00140 int val = cfg->readNumEntry( "ResponseTimeout", DEFAULT_RESPONSE_TIMEOUT );
00141 return QMAX(MIN_TIMEOUT_VALUE, val);
00142 }
00143
00144
00145
00146 bool KProtocolManager::useProxy()
00147 {
00148 return proxyType() != NoProxy;
00149 }
00150
00151 bool KProtocolManager::useReverseProxy()
00152 {
00153 KConfig *cfg = config();
00154 cfg->setGroup( "Proxy Settings" );
00155 return cfg->readBoolEntry("ReversedException", false);
00156 }
00157
00158 KProtocolManager::ProxyType KProtocolManager::proxyType()
00159 {
00160 KConfig *cfg = config();
00161 cfg->setGroup( "Proxy Settings" );
00162 return static_cast<ProxyType>(cfg->readNumEntry( "ProxyType" ));
00163 }
00164
00165 KProtocolManager::ProxyAuthMode KProtocolManager::proxyAuthMode()
00166 {
00167 KConfig *cfg = config();
00168 cfg->setGroup( "Proxy Settings" );
00169 return static_cast<ProxyAuthMode>(cfg->readNumEntry( "AuthMode" ));
00170 }
00171
00172
00173
00174 bool KProtocolManager::useCache()
00175 {
00176 KConfig *cfg = http_config();
00177 return cfg->readBoolEntry( "UseCache", true );
00178 }
00179
00180 KIO::CacheControl KProtocolManager::cacheControl()
00181 {
00182 KConfig *cfg = http_config();
00183 QString tmp = cfg->readEntry("cache");
00184 if (tmp.isEmpty())
00185 return DEFAULT_CACHE_CONTROL;
00186 return KIO::parseCacheControl(tmp);
00187 }
00188
00189 QString KProtocolManager::cacheDir()
00190 {
00191 KConfig *cfg = http_config();
00192 return cfg->readPathEntry("CacheDir", KGlobal::dirs()->saveLocation("cache","http"));
00193 }
00194
00195 int KProtocolManager::maxCacheAge()
00196 {
00197 KConfig *cfg = http_config();
00198 return cfg->readNumEntry( "MaxCacheAge", DEFAULT_MAX_CACHE_AGE );
00199 }
00200
00201 int KProtocolManager::maxCacheSize()
00202 {
00203 KConfig *cfg = http_config();
00204 return cfg->readNumEntry( "MaxCacheSize", DEFAULT_MAX_CACHE_SIZE );
00205 }
00206
00207 QString KProtocolManager::noProxyFor()
00208 {
00209 KProtocolManager::ProxyType type = proxyType();
00210
00211 KConfig *cfg = config();
00212 cfg->setGroup( "Proxy Settings" );
00213
00214 QString noProxy = cfg->readEntry( "NoProxyFor" );
00215 if (type == EnvVarProxy)
00216 noProxy = QString::fromLocal8Bit(getenv(noProxy.local8Bit()));
00217
00218 return noProxy;
00219 }
00220
00221 QString KProtocolManager::proxyFor( const QString& protocol )
00222 {
00223 QString scheme = protocol.lower();
00224
00225 if (scheme == "webdav")
00226 scheme = "http";
00227 else if (scheme == "webdavs")
00228 scheme = "https";
00229
00230 KConfig *cfg = config();
00231 cfg->setGroup( "Proxy Settings" );
00232 return cfg->readEntry( scheme + "Proxy" );
00233 }
00234
00235 QString KProtocolManager::proxyForURL( const KURL &url )
00236 {
00237 QString proxy;
00238 ProxyType pt = proxyType();
00239
00240 switch (pt)
00241 {
00242 case PACProxy:
00243 case WPADProxy:
00244 if (!url.host().isEmpty())
00245 {
00246 KURL u (url);
00247 QString p = u.protocol().lower();
00248
00249
00250
00251 if ( p == "webdav" )
00252 {
00253 p = "http";
00254 u.setProtocol( p );
00255 }
00256 else if ( p == "webdavs" )
00257 {
00258 p = "https";
00259 u.setProtocol( p );
00260 }
00261
00262 if ( p.startsWith("http") || p == "ftp" || p == "gopher" )
00263 DCOPRef( "kded", "proxyscout" ).call( "proxyForURL", u ).get( proxy );
00264 }
00265 break;
00266 case EnvVarProxy:
00267 proxy = QString::fromLocal8Bit(getenv(proxyFor(url.protocol()).local8Bit())).stripWhiteSpace();
00268 break;
00269 case ManualProxy:
00270 proxy = proxyFor( url.protocol() );
00271 break;
00272 case NoProxy:
00273 default:
00274 break;
00275 }
00276
00277 return (proxy.isEmpty() ? QString::fromLatin1("DIRECT") : proxy);
00278 }
00279
00280 void KProtocolManager::badProxy( const QString &proxy )
00281 {
00282 DCOPRef( "kded", "proxyscout" ).send( "blackListProxy", proxy );
00283 }
00284
00285
00286
00287
00288
00289
00290 static bool revmatch(const char *host, const char *nplist)
00291 {
00292 if (host == 0)
00293 return false;
00294
00295 const char *hptr = host + strlen( host ) - 1;
00296 const char *nptr = nplist + strlen( nplist ) - 1;
00297 const char *shptr = hptr;
00298
00299 while ( nptr >= nplist )
00300 {
00301 if ( *hptr != *nptr )
00302 {
00303 hptr = shptr;
00304
00305
00306 while(--nptr>=nplist && *nptr!=',' && *nptr!=' ') ;
00307
00308
00309 while(--nptr>=nplist && (*nptr==',' || *nptr==' ')) ;
00310 }
00311 else
00312 {
00313 if ( nptr==nplist || nptr[-1]==',' || nptr[-1]==' ')
00314 return true;
00315 if ( hptr == host )
00316 return false;
00317
00318 hptr--;
00319 nptr--;
00320 }
00321 }
00322
00323 return false;
00324 }
00325
00326 QString KProtocolManager::slaveProtocol(const KURL &url, QString &proxy)
00327 {
00328 if (url.hasSubURL())
00329 {
00330 KURL::List list = KURL::split(url);
00331 KURL::List::Iterator it = list.fromLast();
00332 return slaveProtocol(*it, proxy);
00333 }
00334
00335 if (!d)
00336 d = new KProtocolManagerPrivate;
00337
00338 if (d->url == url)
00339 {
00340 proxy = d->proxy;
00341 return d->protocol;
00342 }
00343
00344 if (useProxy())
00345 {
00346 proxy = proxyForURL(url);
00347 if ((proxy != "DIRECT") && (!proxy.isEmpty()))
00348 {
00349 bool isRevMatch = false;
00350 KProtocolManager::ProxyType type = proxyType();
00351 bool useRevProxy = ((type == ManualProxy) && useReverseProxy());
00352
00353 QString noProxy;
00354
00355
00356 if ( (type == ManualProxy) || (type == EnvVarProxy) )
00357 noProxy = noProxyFor();
00358
00359 if (!noProxy.isEmpty())
00360 {
00361 QString qhost = url.host().lower();
00362 const char *host = qhost.latin1();
00363 QString qno_proxy = noProxy.stripWhiteSpace().lower();
00364 const char *no_proxy = qno_proxy.latin1();
00365 isRevMatch = revmatch(host, no_proxy);
00366
00367
00368
00369
00370 if (!isRevMatch && url.port() > 0)
00371 {
00372 qhost += ':' + QString::number (url.port());
00373 host = qhost.latin1();
00374 isRevMatch = revmatch (host, no_proxy);
00375 }
00376
00377
00378
00379 if (!isRevMatch && host && (strchr(host, '.') == NULL))
00380 isRevMatch = revmatch("<local>", no_proxy);
00381 }
00382
00383 if ( (!useRevProxy && !isRevMatch) || (useRevProxy && isRevMatch) )
00384 {
00385 d->url = proxy;
00386 if ( d->url.isValid() )
00387 {
00388
00389
00390 QString protocol = url.protocol().lower();
00391 if (protocol.startsWith("http") || protocol.startsWith("webdav"))
00392 d->protocol = protocol;
00393 else
00394 {
00395 d->protocol = d->url.protocol();
00396 kdDebug () << "slaveProtocol: " << d->protocol << endl;
00397 }
00398
00399 d->url = url;
00400 d->proxy = proxy;
00401 return d->protocol;
00402 }
00403 }
00404 }
00405 }
00406
00407 d->url = url;
00408 d->proxy = proxy = QString::null;
00409 d->protocol = url.protocol();
00410 return d->protocol;
00411 }
00412
00413
00414
00415 QString KProtocolManager::userAgentForHost( const QString& hostname )
00416 {
00417 QString sendUserAgent = KIO::SlaveConfig::self()->configData("http", hostname.lower(), "SendUserAgent").lower();
00418 if (sendUserAgent == "false")
00419 return QString::null;
00420
00421 QString useragent = KIO::SlaveConfig::self()->configData("http", hostname.lower(), "UserAgent");
00422
00423
00424
00425 if (useragent.isEmpty())
00426 return defaultUserAgent();
00427
00428 return useragent;
00429 }
00430
00431 QString KProtocolManager::defaultUserAgent( )
00432 {
00433 QString modifiers = KIO::SlaveConfig::self()->configData("http", QString::null, "UserAgentKeys");
00434 return defaultUserAgent(modifiers);
00435 }
00436
00437 QString KProtocolManager::defaultUserAgent( const QString &_modifiers )
00438 {
00439 if (!d)
00440 d = new KProtocolManagerPrivate;
00441
00442 QString modifiers = _modifiers.lower();
00443 if (modifiers.isEmpty())
00444 modifiers = DEFAULT_USER_AGENT_KEYS;
00445
00446 if (d->modifiers == modifiers)
00447 return d->useragent;
00448
00449 QString supp;
00450 struct utsname nam;
00451 if( uname(&nam) >= 0 )
00452 {
00453 if( modifiers.contains('o') )
00454 {
00455 supp += QString("; %1").arg(nam.sysname);
00456 if ( modifiers.contains('v') )
00457 supp += QString(" %1").arg(nam.release);
00458 }
00459 if( modifiers.contains('p') )
00460 {
00461 supp += QString::fromLatin1("; X11");
00462 }
00463 if( modifiers.contains('m') )
00464 {
00465 supp += QString("; %1").arg(nam.machine);
00466 }
00467 if( modifiers.contains('l') )
00468 {
00469 QStringList languageList = KGlobal::locale()->languageList();
00470 QStringList::Iterator it = languageList.find( QString::fromLatin1("C") );
00471 if( it != languageList.end() )
00472 {
00473 if( languageList.contains( QString::fromLatin1("en") ) > 0 )
00474 languageList.remove( it );
00475 else
00476 (*it) = QString::fromLatin1("en");
00477 }
00478 if( languageList.count() )
00479 supp += QString("; %1").arg(languageList.join(", "));
00480 }
00481 }
00482 d->modifiers = modifiers;
00483 d->useragent = CFG_DEFAULT_UAGENT(supp);
00484
00485 #define STRINGIFY(macro_or_string) STRINGIFY_ARG(macro_or_string)
00486 #define STRINGIFY_ARG(contents) #contents
00487 d->useragent.append(" (Kubuntu package " STRINGIFY(DEBIAN_VERSION) ")");
00488
00489 return d->useragent;
00490 }
00491
00492
00493
00494 bool KProtocolManager::markPartial()
00495 {
00496 KConfig *cfg = config();
00497 cfg->setGroup( QString::null );
00498 return cfg->readBoolEntry( "MarkPartial", true );
00499 }
00500
00501 int KProtocolManager::minimumKeepSize()
00502 {
00503 KConfig *cfg = config();
00504 cfg->setGroup( QString::null );
00505 return cfg->readNumEntry( "MinimumKeepSize",
00506 DEFAULT_MINIMUM_KEEP_SIZE );
00507 }
00508
00509 bool KProtocolManager::autoResume()
00510 {
00511 KConfig *cfg = config();
00512 cfg->setGroup( QString::null );
00513 return cfg->readBoolEntry( "AutoResume", false );
00514 }
00515
00516 bool KProtocolManager::persistentConnections()
00517 {
00518 KConfig *cfg = config();
00519 cfg->setGroup( QString::null );
00520 return cfg->readBoolEntry( "PersistentConnections", true );
00521 }
00522
00523 bool KProtocolManager::persistentProxyConnection()
00524 {
00525 KConfig *cfg = config();
00526 cfg->setGroup( QString::null );
00527 return cfg->readBoolEntry( "PersistentProxyConnection", false );
00528 }
00529
00530 QString KProtocolManager::proxyConfigScript()
00531 {
00532 KConfig *cfg = config();
00533 cfg->setGroup( "Proxy Settings" );
00534 return cfg->readEntry( "Proxy Config Script" );
00535 }