kprotocolmanager.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999 Torben Weis <weis@kde.org> 00003 Copyright (C) 2000- Waldo Bastain <bastain@kde.org> 00004 Copyright (C) 2000- Dawit Alemayehu <adawit@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 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 <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 // DEFAULT USERAGENT STRING 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 // Force the slave config to re-read its config... 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 /*=============================== TIMEOUT SETTINGS ==========================*/ 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 /*========================== PROXY SETTINGS =================================*/ 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 /*========================== CACHING =====================================*/ 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 ); // 14 days 00199 } 00200 00201 int KProtocolManager::maxCacheSize() 00202 { 00203 KConfig *cfg = http_config(); 00204 return cfg->readNumEntry( "MaxCacheSize", DEFAULT_MAX_CACHE_SIZE ); // 5 MB 00205 } 00206 00207 QString KProtocolManager::noProxyForRaw() 00208 { 00209 KConfig *cfg = config(); 00210 cfg->setGroup( "Proxy Settings" ); 00211 00212 return cfg->readEntry( "NoProxyFor" ); 00213 } 00214 00215 QString KProtocolManager::noProxyFor() 00216 { 00217 QString noProxy = noProxyForRaw(); 00218 if (proxyType() == EnvVarProxy) 00219 noProxy = QString::fromLocal8Bit(getenv(noProxy.local8Bit())); 00220 00221 return noProxy; 00222 } 00223 00224 QString KProtocolManager::proxyFor( const QString& protocol ) 00225 { 00226 QString scheme = protocol.lower(); 00227 00228 if (scheme == "webdav") 00229 scheme = "http"; 00230 else if (scheme == "webdavs") 00231 scheme = "https"; 00232 00233 KConfig *cfg = config(); 00234 cfg->setGroup( "Proxy Settings" ); 00235 return cfg->readEntry( scheme + "Proxy" ); 00236 } 00237 00238 QString KProtocolManager::proxyForURL( const KURL &url ) 00239 { 00240 QString proxy; 00241 ProxyType pt = proxyType(); 00242 00243 switch (pt) 00244 { 00245 case PACProxy: 00246 case WPADProxy: 00247 if (!url.host().isEmpty()) 00248 { 00249 KURL u (url); 00250 QString p = u.protocol().lower(); 00251 00252 // webdav is a KDE specific protocol. Look up proxy 00253 // information using HTTP instead... 00254 if ( p == "webdav" ) 00255 { 00256 p = "http"; 00257 u.setProtocol( p ); 00258 } 00259 else if ( p == "webdavs" ) 00260 { 00261 p = "https"; 00262 u.setProtocol( p ); 00263 } 00264 00265 if ( p.startsWith("http") || p == "ftp" || p == "gopher" ) 00266 DCOPRef( "kded", "proxyscout" ).call( "proxyForURL", u ).get( proxy ); 00267 } 00268 break; 00269 case EnvVarProxy: 00270 proxy = QString::fromLocal8Bit(getenv(proxyFor(url.protocol()).local8Bit())).stripWhiteSpace(); 00271 break; 00272 case ManualProxy: 00273 proxy = proxyFor( url.protocol() ); 00274 break; 00275 case NoProxy: 00276 default: 00277 break; 00278 } 00279 00280 return (proxy.isEmpty() ? QString::fromLatin1("DIRECT") : proxy); 00281 } 00282 00283 void KProtocolManager::badProxy( const QString &proxy ) 00284 { 00285 DCOPRef( "kded", "proxyscout" ).send( "blackListProxy", proxy ); 00286 } 00287 00288 /* 00289 Domain suffix match. E.g. return true if host is "cuzco.inka.de" and 00290 nplist is "inka.de,hadiko.de" or if host is "localhost" and nplist is 00291 "localhost". 00292 */ 00293 static bool revmatch(const char *host, const char *nplist) 00294 { 00295 if (host == 0) 00296 return false; 00297 00298 const char *hptr = host + strlen( host ) - 1; 00299 const char *nptr = nplist + strlen( nplist ) - 1; 00300 const char *shptr = hptr; 00301 00302 while ( nptr >= nplist ) 00303 { 00304 if ( *hptr != *nptr ) 00305 { 00306 hptr = shptr; 00307 00308 // Try to find another domain or host in the list 00309 while(--nptr>=nplist && *nptr!=',' && *nptr!=' ') ; 00310 00311 // Strip out multiple spaces and commas 00312 while(--nptr>=nplist && (*nptr==',' || *nptr==' ')) ; 00313 } 00314 else 00315 { 00316 if ( nptr==nplist || nptr[-1]==',' || nptr[-1]==' ') 00317 return true; 00318 if ( hptr == host ) // e.g. revmatch("bugs.kde.org","mybugs.kde.org") 00319 return false; 00320 00321 hptr--; 00322 nptr--; 00323 } 00324 } 00325 00326 return false; 00327 } 00328 00329 QString KProtocolManager::slaveProtocol(const KURL &url, QString &proxy) 00330 { 00331 if (url.hasSubURL()) // We don't want the suburl's protocol 00332 { 00333 KURL::List list = KURL::split(url); 00334 KURL::List::Iterator it = list.fromLast(); 00335 return slaveProtocol(*it, proxy); 00336 } 00337 00338 if (!d) 00339 d = new KProtocolManagerPrivate; 00340 00341 if (d->url == url) 00342 { 00343 proxy = d->proxy; 00344 return d->protocol; 00345 } 00346 00347 if (useProxy()) 00348 { 00349 proxy = proxyForURL(url); 00350 if ((proxy != "DIRECT") && (!proxy.isEmpty())) 00351 { 00352 bool isRevMatch = false; 00353 KProtocolManager::ProxyType type = proxyType(); 00354 bool useRevProxy = ((type == ManualProxy) && useReverseProxy()); 00355 00356 QString noProxy; 00357 // Check no proxy information iff the proxy type is either 00358 // ManualProxy or EnvVarProxy 00359 if ( (type == ManualProxy) || (type == EnvVarProxy) ) 00360 noProxy = noProxyFor(); 00361 00362 if (!noProxy.isEmpty()) 00363 { 00364 QString qhost = url.host().lower(); 00365 const char *host = qhost.latin1(); 00366 QString qno_proxy = noProxy.stripWhiteSpace().lower(); 00367 const char *no_proxy = qno_proxy.latin1(); 00368 isRevMatch = revmatch(host, no_proxy); 00369 00370 // If no match is found and the request url has a port 00371 // number, try the combination of "host:port". This allows 00372 // users to enter host:port in the No-proxy-For list. 00373 if (!isRevMatch && url.port() > 0) 00374 { 00375 qhost += ':' + QString::number (url.port()); 00376 host = qhost.latin1(); 00377 isRevMatch = revmatch (host, no_proxy); 00378 } 00379 00380 // If the hostname does not contain a dot, check if 00381 // <local> is part of noProxy. 00382 if (!isRevMatch && host && (strchr(host, '.') == NULL)) 00383 isRevMatch = revmatch("<local>", no_proxy); 00384 } 00385 00386 if ( (!useRevProxy && !isRevMatch) || (useRevProxy && isRevMatch) ) 00387 { 00388 d->url = proxy; 00389 if ( d->url.isValid() ) 00390 { 00391 // The idea behind slave protocols is not applicable to http 00392 // and webdav protocols. 00393 QString protocol = url.protocol().lower(); 00394 if (protocol.startsWith("http") || protocol.startsWith("webdav")) 00395 d->protocol = protocol; 00396 else 00397 { 00398 d->protocol = d->url.protocol(); 00399 kdDebug () << "slaveProtocol: " << d->protocol << endl; 00400 } 00401 00402 d->url = url; 00403 d->proxy = proxy; 00404 return d->protocol; 00405 } 00406 } 00407 } 00408 } 00409 00410 d->url = url; 00411 d->proxy = proxy = QString::null; 00412 d->protocol = url.protocol(); 00413 return d->protocol; 00414 } 00415 00416 /*================================= USER-AGENT SETTINGS =====================*/ 00417 00418 QString KProtocolManager::userAgentForHost( const QString& hostname ) 00419 { 00420 QString sendUserAgent = KIO::SlaveConfig::self()->configData("http", hostname.lower(), "SendUserAgent").lower(); 00421 if (sendUserAgent == "false") 00422 return QString::null; 00423 00424 QString useragent = KIO::SlaveConfig::self()->configData("http", hostname.lower(), "UserAgent"); 00425 00426 // Return the default user-agent if none is specified 00427 // for the requested host. 00428 if (useragent.isEmpty()) 00429 return defaultUserAgent(); 00430 00431 return useragent; 00432 } 00433 00434 QString KProtocolManager::defaultUserAgent( ) 00435 { 00436 QString modifiers = KIO::SlaveConfig::self()->configData("http", QString::null, "UserAgentKeys"); 00437 return defaultUserAgent(modifiers); 00438 } 00439 00440 QString KProtocolManager::defaultUserAgent( const QString &_modifiers ) 00441 { 00442 if (!d) 00443 d = new KProtocolManagerPrivate; 00444 00445 QString modifiers = _modifiers.lower(); 00446 if (modifiers.isEmpty()) 00447 modifiers = DEFAULT_USER_AGENT_KEYS; 00448 00449 if (d->modifiers == modifiers) 00450 return d->useragent; 00451 00452 QString supp; 00453 struct utsname nam; 00454 if( uname(&nam) >= 0 ) 00455 { 00456 if( modifiers.contains('o') ) 00457 { 00458 supp += QString("; %1").arg(nam.sysname); 00459 if ( modifiers.contains('v') ) 00460 supp += QString(" %1").arg(nam.release); 00461 } 00462 if( modifiers.contains('p') ) 00463 { 00464 // TODO: determine this value instead of hardcoding it... 00465 supp += QString::fromLatin1("; X11"); 00466 } 00467 if( modifiers.contains('m') ) 00468 { 00469 supp += QString("; %1").arg(nam.machine); 00470 } 00471 if( modifiers.contains('l') ) 00472 { 00473 QStringList languageList = KGlobal::locale()->languageList(); 00474 QStringList::Iterator it = languageList.find( QString::fromLatin1("C") ); 00475 if( it != languageList.end() ) 00476 { 00477 if( languageList.contains( QString::fromLatin1("en") ) > 0 ) 00478 languageList.remove( it ); 00479 else 00480 (*it) = QString::fromLatin1("en"); 00481 } 00482 if( languageList.count() ) 00483 supp += QString("; %1").arg(languageList.join(", ")); 00484 } 00485 } 00486 d->modifiers = modifiers; 00487 d->useragent = CFG_DEFAULT_UAGENT(supp); 00488 return d->useragent; 00489 } 00490 00491 /*==================================== OTHERS ===============================*/ 00492 00493 bool KProtocolManager::markPartial() 00494 { 00495 KConfig *cfg = config(); 00496 cfg->setGroup( QString::null ); 00497 return cfg->readBoolEntry( "MarkPartial", true ); 00498 } 00499 00500 int KProtocolManager::minimumKeepSize() 00501 { 00502 KConfig *cfg = config(); 00503 cfg->setGroup( QString::null ); 00504 return cfg->readNumEntry( "MinimumKeepSize", 00505 DEFAULT_MINIMUM_KEEP_SIZE ); // 5000 byte 00506 } 00507 00508 bool KProtocolManager::autoResume() 00509 { 00510 KConfig *cfg = config(); 00511 cfg->setGroup( QString::null ); 00512 return cfg->readBoolEntry( "AutoResume", false ); 00513 } 00514 00515 bool KProtocolManager::persistentConnections() 00516 { 00517 KConfig *cfg = config(); 00518 cfg->setGroup( QString::null ); 00519 return cfg->readBoolEntry( "PersistentConnections", true ); 00520 } 00521 00522 bool KProtocolManager::persistentProxyConnection() 00523 { 00524 KConfig *cfg = config(); 00525 cfg->setGroup( QString::null ); 00526 return cfg->readBoolEntry( "PersistentProxyConnection", false ); 00527 } 00528 00529 QString KProtocolManager::proxyConfigScript() 00530 { 00531 KConfig *cfg = config(); 00532 cfg->setGroup( "Proxy Settings" ); 00533 return cfg->readEntry( "Proxy Config Script" ); 00534 }