KIOSlave
kcookieserver.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of KDE 00003 00004 Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org) 00005 00006 Permission is hereby granted, free of charge, to any person obtaining a copy 00007 of this software and associated documentation files (the "Software"), to deal 00008 in the Software without restriction, including without limitation the rights 00009 to use, copy, modify, merge, publish, distribute, and/or sell 00010 copies of the Software, and to permit persons to whom the Software is 00011 furnished to do so, subject to the following conditions: 00012 00013 The above copyright notice and this permission notice shall be included in 00014 all copies or substantial portions of the Software. 00015 00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00019 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00022 */ 00023 //---------------------------------------------------------------------------- 00024 // 00025 // KDE Cookie Server 00026 00027 #include "kcookieserver.h" 00028 00029 #define SAVE_DELAY 3 // Save after 3 minutes 00030 00031 #include <QtCore/QTimer> 00032 #include <QtCore/QFile> 00033 #include <QtDBus/QtDBus> 00034 00035 #include <kconfig.h> 00036 #include <kdebug.h> 00037 #include <kcmdlineargs.h> 00038 #include <kstandarddirs.h> 00039 00040 #include "kcookiejar.h" 00041 #include "kcookiewin.h" 00042 #include "kcookieserveradaptor.h" 00043 #include <kpluginfactory.h> 00044 #include <kpluginloader.h> 00045 00046 00047 #define QL1S(x) QLatin1String(x) 00048 #define QL1C(x) QLatin1Char(x) 00049 00050 K_PLUGIN_FACTORY(KdedCookieServerFactory, 00051 registerPlugin<KCookieServer>(); 00052 ) 00053 K_EXPORT_PLUGIN(KdedCookieServerFactory("kcookiejar")) 00054 00055 // Cookie field indexes 00056 enum CookieDetails { CF_DOMAIN=0, CF_PATH, CF_NAME, CF_HOST, 00057 CF_VALUE, CF_EXPIRE, CF_PROVER, CF_SECURE }; 00058 00059 00060 class CookieRequest { 00061 public: 00062 QDBusMessage reply; 00063 QString url; 00064 bool DOM; 00065 qlonglong windowId; 00066 }; 00067 00068 template class QList<CookieRequest*>; 00069 00070 class RequestList : public QList<CookieRequest*> 00071 { 00072 public: 00073 RequestList() : QList<CookieRequest*>() { } 00074 }; 00075 00076 KCookieServer::KCookieServer(QObject* parent, const QList<QVariant>&) 00077 : KDEDModule(parent) 00078 { 00079 (void)new KCookieServerAdaptor(this); 00080 mCookieJar = new KCookieJar; 00081 mPendingCookies = new KHttpCookieList; 00082 mRequestList = new RequestList; 00083 mAdvicePending = false; 00084 mTimer = new QTimer(); 00085 mTimer->setSingleShot(true); 00086 connect(mTimer, SIGNAL(timeout()), SLOT(slotSave())); 00087 mConfig = new KConfig("kcookiejarrc"); 00088 mCookieJar->loadConfig( mConfig ); 00089 00090 const QString filename = KStandardDirs::locateLocal("data", "kcookiejar/cookies"); 00091 00092 // Stay backwards compatible! 00093 const QString filenameOld = KStandardDirs::locate("data", "kfm/cookies"); 00094 if (!filenameOld.isEmpty()) 00095 { 00096 mCookieJar->loadCookies( filenameOld ); 00097 if (mCookieJar->saveCookies( filename)) 00098 { 00099 QFile::remove(filenameOld); // Remove old kfm cookie file 00100 } 00101 } 00102 else 00103 { 00104 mCookieJar->loadCookies( filename); 00105 } 00106 connect(this, SIGNAL(windowUnregistered(qlonglong)), 00107 this, SLOT(slotDeleteSessionCookies(qlonglong))); 00108 } 00109 00110 KCookieServer::~KCookieServer() 00111 { 00112 slotSave(); 00113 delete mCookieJar; 00114 delete mTimer; 00115 delete mPendingCookies; 00116 delete mConfig; 00117 } 00118 00119 bool KCookieServer::cookiesPending( const QString &url, KHttpCookieList *cookieList ) 00120 { 00121 QString fqdn; 00122 QString path; 00123 // Check whether 'url' has cookies on the pending list 00124 if (mPendingCookies->isEmpty()) 00125 return false; 00126 if (!KCookieJar::parseUrl(url, fqdn, path)) 00127 return false; 00128 00129 QStringList domains; 00130 mCookieJar->extractDomains(fqdn, domains); 00131 Q_FOREACH(const KHttpCookie& cookie, *mPendingCookies) { 00132 if (cookie.match( fqdn, domains, path)) { 00133 if (!cookieList) 00134 return true; 00135 cookieList->append(cookie); 00136 } 00137 } 00138 if (!cookieList) 00139 return false; 00140 return cookieList->isEmpty(); 00141 } 00142 00143 void KCookieServer::addCookies( const QString &url, const QByteArray &cookieHeader, 00144 qlonglong windowId, bool useDOMFormat ) 00145 { 00146 KHttpCookieList cookieList; 00147 if (useDOMFormat) 00148 cookieList = mCookieJar->makeDOMCookies(url, cookieHeader, windowId); 00149 else 00150 cookieList = mCookieJar->makeCookies(url, cookieHeader, windowId); 00151 00152 checkCookies(&cookieList); 00153 00154 *mPendingCookies += cookieList; 00155 00156 if (!mAdvicePending) 00157 { 00158 mAdvicePending = true; 00159 while (!mPendingCookies->isEmpty()) 00160 { 00161 checkCookies(0); 00162 } 00163 mAdvicePending = false; 00164 } 00165 } 00166 00167 void KCookieServer::checkCookies(KHttpCookieList *cookieList) 00168 { 00169 KHttpCookieList *list; 00170 00171 if (cookieList) 00172 list = cookieList; 00173 else 00174 list = mPendingCookies; 00175 00176 QMutableListIterator<KHttpCookie> cookieIterator(*list); 00177 while (cookieIterator.hasNext()) { 00178 KHttpCookie& cookie = cookieIterator.next(); 00179 const KCookieAdvice advice = mCookieJar->cookieAdvice(cookie); 00180 switch(advice) { 00181 case KCookieAccept: 00182 mCookieJar->addCookie(cookie); 00183 cookieIterator.remove(); 00184 break; 00185 case KCookieReject: 00186 cookieIterator.remove(); 00187 break; 00188 default: 00189 break; 00190 } 00191 } 00192 00193 if (cookieList || list->isEmpty()) 00194 return; 00195 00196 // Collect all pending cookies with the same host as the first pending cookie 00197 const KHttpCookie& currentCookie = mPendingCookies->first(); 00198 KHttpCookieList currentList; 00199 currentList.append(currentCookie); 00200 const QString currentHost = currentCookie.host(); 00201 QList<int> shownCookies; shownCookies << 0; 00202 for (int i = 1 /*first already done*/; i < mPendingCookies->count(); ++i) { 00203 const KHttpCookie& cookie = (*mPendingCookies)[i]; 00204 if (cookie.host() == currentHost) { 00205 currentList.append(cookie); 00206 shownCookies << i; 00207 } 00208 } 00209 //kDebug() << shownCookies; 00210 00211 KCookieWin *kw = new KCookieWin( 0L, currentList, 00212 mCookieJar->preferredDefaultPolicy(), 00213 mCookieJar->showCookieDetails() ); 00214 KCookieAdvice userAdvice = kw->advice(mCookieJar, currentCookie); 00215 delete kw; 00216 // Save the cookie config if it has changed 00217 mCookieJar->saveConfig( mConfig ); 00218 00219 // Apply the user's choice to all cookies that are currently 00220 // queued for this host (or just the first one, if the user asks for that). 00221 QMutableListIterator<KHttpCookie> cookieIterator2(*mPendingCookies); 00222 int pendingCookieIndex = -1; 00223 while (cookieIterator2.hasNext()) { 00224 ++pendingCookieIndex; 00225 KHttpCookie& cookie = cookieIterator2.next(); 00226 if (cookie.host() != currentHost) 00227 continue; 00228 if (mCookieJar->preferredDefaultPolicy() == KCookieJar::ApplyToShownCookiesOnly 00229 && !shownCookies.contains(pendingCookieIndex)) { 00230 // User chose "only those cookies", and this one was added while the dialog was up -> skip 00231 break; 00232 } 00233 switch(userAdvice) { 00234 case KCookieAccept: 00235 mCookieJar->addCookie(cookie); 00236 cookieIterator2.remove(); 00237 break; 00238 00239 case KCookieReject: 00240 cookieIterator2.remove(); 00241 break; 00242 00243 default: 00244 kWarning() << "userAdvice not accept or reject, this should never happen!"; 00245 break; 00246 } 00247 } 00248 00249 // Check if we can handle any request 00250 QMutableListIterator<CookieRequest *> requestIterator(*mRequestList); 00251 while (requestIterator.hasNext()) { 00252 CookieRequest *request = requestIterator.next(); 00253 if (!cookiesPending(request->url)) { 00254 const QString res = mCookieJar->findCookies(request->url, request->DOM, request->windowId); 00255 00256 QDBusConnection::sessionBus().send(request->reply.createReply(res)); 00257 delete request; 00258 requestIterator.remove(); 00259 } 00260 } 00261 00262 saveCookieJar(); 00263 } 00264 00265 void KCookieServer::slotSave() 00266 { 00267 if (mCookieJar->changed()) 00268 { 00269 QString filename = KStandardDirs::locateLocal("data", "kcookiejar/cookies"); 00270 mCookieJar->saveCookies(filename); 00271 } 00272 } 00273 00274 void KCookieServer::saveCookieJar() 00275 { 00276 if( mTimer->isActive() ) 00277 return; 00278 00279 mTimer->start( 1000*60*SAVE_DELAY ); 00280 } 00281 00282 void KCookieServer::putCookie( QStringList& out, const KHttpCookie& cookie, 00283 const QList<int>& fields ) 00284 { 00285 foreach ( int i, fields ) { 00286 switch(i) 00287 { 00288 case CF_DOMAIN : 00289 out << cookie.domain(); 00290 break; 00291 case CF_NAME : 00292 out << cookie.name(); 00293 break; 00294 case CF_PATH : 00295 out << cookie.path(); 00296 break; 00297 case CF_HOST : 00298 out << cookie.host(); 00299 break; 00300 case CF_VALUE : 00301 out << cookie.value(); 00302 break; 00303 case CF_EXPIRE : 00304 out << QString::number(cookie.expireDate()); 00305 break; 00306 case CF_PROVER : 00307 out << QString::number(cookie.protocolVersion()); 00308 break; 00309 case CF_SECURE : 00310 out << QString::number(cookie.isSecure() ? 1 : 0); 00311 break; 00312 default : 00313 out << QString(); 00314 } 00315 } 00316 } 00317 00318 bool KCookieServer::cookieMatches(const KHttpCookie& c, 00319 const QString &domain, const QString &fqdn, 00320 const QString &path, const QString &name) 00321 { 00322 const bool hasDomain = !domain.isEmpty(); 00323 return (((hasDomain && c.domain() == domain) || fqdn == c.host()) && 00324 (c.path() == path) && (c.name() == name) && 00325 (!c.isExpired())); 00326 } 00327 00328 00329 // DBUS function 00330 QString KCookieServer::listCookies(const QString &url) 00331 { 00332 return findCookies(url, 0); 00333 } 00334 00335 // DBUS function 00336 QString KCookieServer::findCookies(const QString &url, qlonglong windowId) 00337 { 00338 if (cookiesPending(url)) 00339 { 00340 CookieRequest *request = new CookieRequest; 00341 message().setDelayedReply(true); 00342 request->reply = message(); 00343 request->url = url; 00344 request->DOM = false; 00345 request->windowId = windowId; 00346 mRequestList->append( request ); 00347 return QString(); // Talk to you later :-) 00348 } 00349 00350 QString cookies = mCookieJar->findCookies(url, false, windowId); 00351 saveCookieJar(); 00352 return cookies; 00353 } 00354 00355 // DBUS function 00356 QStringList 00357 KCookieServer::findDomains() 00358 { 00359 QStringList result; 00360 QStringListIterator it (mCookieJar->getDomainList()); 00361 while (it.hasNext()) 00362 { 00363 // Ignore domains that have policy set for but contain 00364 // no cookies whatsoever... 00365 const QString domain = it.next(); 00366 const KHttpCookieList* list = mCookieJar->getCookieList(domain, ""); 00367 if ( list && !list->isEmpty() ) 00368 result << domain; 00369 } 00370 return result; 00371 } 00372 00373 // DBUS function 00374 QStringList 00375 KCookieServer::findCookies(const QList<int> &fields, 00376 const QString &_domain, 00377 const QString &fqdn, 00378 const QString &path, 00379 const QString &name) 00380 { 00381 QStringList result; 00382 const bool allCookies = name.isEmpty(); 00383 const QStringList domainList = _domain.split(QLatin1Char(' ')); 00384 00385 if (allCookies) 00386 { 00387 Q_FOREACH(const QString& domain, domainList) 00388 { 00389 const KHttpCookieList* list = mCookieJar->getCookieList(domain, fqdn); 00390 if (!list) 00391 continue; 00392 Q_FOREACH(const KHttpCookie& cookie, *list) 00393 { 00394 if (cookie.isExpired()) 00395 continue; 00396 putCookie(result, cookie, fields); 00397 } 00398 } 00399 } 00400 else 00401 { 00402 Q_FOREACH(const QString& domain, domainList) 00403 { 00404 const KHttpCookieList* list = mCookieJar->getCookieList(domain, fqdn); 00405 if (!list) 00406 continue; 00407 Q_FOREACH(const KHttpCookie& cookie, *list) 00408 { 00409 if (cookie.isExpired()) 00410 continue; 00411 if (cookieMatches(cookie, domain, fqdn, path, name)) 00412 { 00413 putCookie(result, cookie, fields); 00414 break; 00415 } 00416 } 00417 } 00418 } 00419 00420 return result; 00421 } 00422 00423 // DBUS function 00424 QString 00425 KCookieServer::findDOMCookies(const QString &url) 00426 { 00427 return findDOMCookies(url, 0); 00428 } 00429 00430 // DBUS function 00431 QString 00432 KCookieServer::findDOMCookies(const QString &url, qlonglong windowId) 00433 { 00434 // We don't wait for pending cookies because it locks up konqueror 00435 // which can cause a deadlock if it happens to have a popup-menu up. 00436 // Instead we just return pending cookies as if they had been accepted already. 00437 KHttpCookieList pendingCookies; 00438 cookiesPending(url, &pendingCookies); 00439 00440 return mCookieJar->findCookies(url, true, windowId, &pendingCookies); 00441 } 00442 00443 // DBUS function 00444 void 00445 KCookieServer::addCookies(const QString &arg1, const QByteArray &arg2, qlonglong arg3) 00446 { 00447 addCookies(arg1, arg2, arg3, false); 00448 } 00449 00450 // DBUS function 00451 void 00452 KCookieServer::deleteCookie(const QString &domain, const QString &fqdn, 00453 const QString &path, const QString &name) 00454 { 00455 KHttpCookieList* cookieList = mCookieJar->getCookieList( domain, fqdn ); 00456 if (cookieList && !cookieList->isEmpty()) { 00457 KHttpCookieList::Iterator itEnd = cookieList->end(); 00458 for (KHttpCookieList::Iterator it = cookieList->begin(); it != itEnd; ++it) 00459 { 00460 if (cookieMatches(*it, domain, fqdn, path, name)) { 00461 mCookieJar->eatCookie(it); 00462 saveCookieJar(); 00463 break; 00464 } 00465 } 00466 } 00467 } 00468 00469 // DBUS function 00470 void 00471 KCookieServer::deleteCookiesFromDomain(const QString &domain) 00472 { 00473 mCookieJar->eatCookiesForDomain(domain); 00474 saveCookieJar(); 00475 } 00476 00477 00478 // Qt function 00479 void 00480 KCookieServer::slotDeleteSessionCookies( qlonglong windowId ) 00481 { 00482 deleteSessionCookies(windowId); 00483 } 00484 00485 // DBUS function 00486 void 00487 KCookieServer::deleteSessionCookies( qlonglong windowId ) 00488 { 00489 mCookieJar->eatSessionCookies( windowId ); 00490 saveCookieJar(); 00491 } 00492 00493 void 00494 KCookieServer::deleteSessionCookiesFor(const QString &fqdn, qlonglong windowId) 00495 { 00496 mCookieJar->eatSessionCookies( fqdn, windowId ); 00497 saveCookieJar(); 00498 } 00499 00500 // DBUS function 00501 void 00502 KCookieServer::deleteAllCookies() 00503 { 00504 mCookieJar->eatAllCookies(); 00505 saveCookieJar(); 00506 } 00507 00508 // DBUS function 00509 void 00510 KCookieServer::addDOMCookies(const QString &url, const QByteArray &cookieHeader, qlonglong windowId) 00511 { 00512 addCookies(url, cookieHeader, windowId, true); 00513 } 00514 00515 // DBUS function 00516 bool 00517 KCookieServer::setDomainAdvice(const QString &url, const QString &advice) 00518 { 00519 QString fqdn; 00520 QString dummy; 00521 if (KCookieJar::parseUrl(url, fqdn, dummy)) 00522 { 00523 QStringList domains; 00524 mCookieJar->extractDomains(fqdn, domains); 00525 00526 mCookieJar->setDomainAdvice(domains[domains.count() > 3 ? 3 : 0], 00527 KCookieJar::strToAdvice(advice)); 00528 // Save the cookie config if it has changed 00529 mCookieJar->saveConfig( mConfig ); 00530 return true; 00531 } 00532 return false; 00533 } 00534 00535 // DBUS function 00536 QString 00537 KCookieServer::getDomainAdvice(const QString &url) 00538 { 00539 KCookieAdvice advice = KCookieDunno; 00540 QString fqdn; 00541 QString dummy; 00542 if (KCookieJar::parseUrl(url, fqdn, dummy)) 00543 { 00544 QStringList domains; 00545 mCookieJar->extractDomains(fqdn, domains); 00546 00547 QStringListIterator it (domains); 00548 while ( (advice == KCookieDunno) && it.hasNext() ) 00549 { 00550 // Always check advice in both ".domain" and "domain". Note 00551 // that we only want to check "domain" if it matches the 00552 // fqdn of the requested URL. 00553 const QString& domain = it.next(); 00554 if ( domain.at(0) == '.' || domain == fqdn ) 00555 advice = mCookieJar->getDomainAdvice(domain); 00556 } 00557 if (advice == KCookieDunno) 00558 advice = mCookieJar->getGlobalAdvice(); 00559 } 00560 return KCookieJar::adviceToStr(advice); 00561 } 00562 00563 // DBUS function 00564 void 00565 KCookieServer::reloadPolicy() 00566 { 00567 mCookieJar->loadConfig( mConfig, true ); 00568 } 00569 00570 // DBUS function 00571 void 00572 KCookieServer::shutdown() 00573 { 00574 deleteLater(); 00575 } 00576 00577 #include "kcookieserver.moc" 00578
KDE 4.6 API Reference