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 Q_FOREACH(const QString& domain, mCookieJar->getDomainList()) 00361 { 00362 // Ignore domains that have policy set for but contain 00363 // no cookies whatsoever... 00364 const KHttpCookieList* list = mCookieJar->getCookieList(domain, ""); 00365 if ( list && !list->isEmpty() ) 00366 result << domain; 00367 } 00368 return result; 00369 } 00370 00371 // DBUS function 00372 QStringList 00373 KCookieServer::findCookies(const QList<int> &fields, 00374 const QString &_domain, 00375 const QString &fqdn, 00376 const QString &path, 00377 const QString &name) 00378 { 00379 QStringList result; 00380 const bool allCookies = name.isEmpty(); 00381 const QStringList domainList = _domain.split(QLatin1Char(' ')); 00382 00383 if (allCookies) 00384 { 00385 Q_FOREACH(const QString& domain, domainList) 00386 { 00387 const KHttpCookieList* list = mCookieJar->getCookieList(domain, fqdn); 00388 if (!list) 00389 continue; 00390 Q_FOREACH(const KHttpCookie& cookie, *list) 00391 { 00392 if (cookie.isExpired()) 00393 continue; 00394 putCookie(result, cookie, fields); 00395 } 00396 } 00397 } 00398 else 00399 { 00400 Q_FOREACH(const QString& domain, domainList) 00401 { 00402 const KHttpCookieList* list = mCookieJar->getCookieList(domain, fqdn); 00403 if (!list) 00404 continue; 00405 Q_FOREACH(const KHttpCookie& cookie, *list) 00406 { 00407 if (cookie.isExpired()) 00408 continue; 00409 if (cookieMatches(cookie, domain, fqdn, path, name)) 00410 { 00411 putCookie(result, cookie, fields); 00412 break; 00413 } 00414 } 00415 } 00416 } 00417 00418 return result; 00419 } 00420 00421 // DBUS function 00422 QString 00423 KCookieServer::findDOMCookies(const QString &url) 00424 { 00425 return findDOMCookies(url, 0); 00426 } 00427 00428 // DBUS function 00429 QString 00430 KCookieServer::findDOMCookies(const QString &url, qlonglong windowId) 00431 { 00432 // We don't wait for pending cookies because it locks up konqueror 00433 // which can cause a deadlock if it happens to have a popup-menu up. 00434 // Instead we just return pending cookies as if they had been accepted already. 00435 KHttpCookieList pendingCookies; 00436 cookiesPending(url, &pendingCookies); 00437 00438 return mCookieJar->findCookies(url, true, windowId, &pendingCookies); 00439 } 00440 00441 // DBUS function 00442 void 00443 KCookieServer::addCookies(const QString &arg1, const QByteArray &arg2, qlonglong arg3) 00444 { 00445 addCookies(arg1, arg2, arg3, false); 00446 } 00447 00448 // DBUS function 00449 void 00450 KCookieServer::deleteCookie(const QString &domain, const QString &fqdn, 00451 const QString &path, const QString &name) 00452 { 00453 KHttpCookieList* cookieList = mCookieJar->getCookieList( domain, fqdn ); 00454 if (cookieList && !cookieList->isEmpty()) { 00455 KHttpCookieList::Iterator itEnd = cookieList->end(); 00456 for (KHttpCookieList::Iterator it = cookieList->begin(); it != itEnd; ++it) 00457 { 00458 if (cookieMatches(*it, domain, fqdn, path, name)) { 00459 mCookieJar->eatCookie(it); 00460 saveCookieJar(); 00461 break; 00462 } 00463 } 00464 } 00465 } 00466 00467 // DBUS function 00468 void 00469 KCookieServer::deleteCookiesFromDomain(const QString &domain) 00470 { 00471 mCookieJar->eatCookiesForDomain(domain); 00472 saveCookieJar(); 00473 } 00474 00475 00476 // Qt function 00477 void 00478 KCookieServer::slotDeleteSessionCookies( qlonglong windowId ) 00479 { 00480 deleteSessionCookies(windowId); 00481 } 00482 00483 // DBUS function 00484 void 00485 KCookieServer::deleteSessionCookies( qlonglong windowId ) 00486 { 00487 mCookieJar->eatSessionCookies( windowId ); 00488 saveCookieJar(); 00489 } 00490 00491 void 00492 KCookieServer::deleteSessionCookiesFor(const QString &fqdn, qlonglong windowId) 00493 { 00494 mCookieJar->eatSessionCookies( fqdn, windowId ); 00495 saveCookieJar(); 00496 } 00497 00498 // DBUS function 00499 void 00500 KCookieServer::deleteAllCookies() 00501 { 00502 mCookieJar->eatAllCookies(); 00503 saveCookieJar(); 00504 } 00505 00506 // DBUS function 00507 void 00508 KCookieServer::addDOMCookies(const QString &url, const QByteArray &cookieHeader, qlonglong windowId) 00509 { 00510 addCookies(url, cookieHeader, windowId, true); 00511 } 00512 00513 // DBUS function 00514 bool 00515 KCookieServer::setDomainAdvice(const QString &url, const QString &advice) 00516 { 00517 QString fqdn; 00518 QString dummy; 00519 if (KCookieJar::parseUrl(url, fqdn, dummy)) 00520 { 00521 QStringList domains; 00522 mCookieJar->extractDomains(fqdn, domains); 00523 00524 mCookieJar->setDomainAdvice(domains[domains.count() > 3 ? 3 : 0], 00525 KCookieJar::strToAdvice(advice)); 00526 // Save the cookie config if it has changed 00527 mCookieJar->saveConfig( mConfig ); 00528 return true; 00529 } 00530 return false; 00531 } 00532 00533 // DBUS function 00534 QString 00535 KCookieServer::getDomainAdvice(const QString &url) 00536 { 00537 KCookieAdvice advice = KCookieDunno; 00538 QString fqdn; 00539 QString dummy; 00540 if (KCookieJar::parseUrl(url, fqdn, dummy)) 00541 { 00542 QStringList domains; 00543 mCookieJar->extractDomains(fqdn, domains); 00544 00545 QStringListIterator it (domains); 00546 while ( (advice == KCookieDunno) && it.hasNext() ) 00547 { 00548 // Always check advice in both ".domain" and "domain". Note 00549 // that we only want to check "domain" if it matches the 00550 // fqdn of the requested URL. 00551 const QString& domain = it.next(); 00552 if ( domain.at(0) == '.' || domain == fqdn ) 00553 advice = mCookieJar->getDomainAdvice(domain); 00554 } 00555 if (advice == KCookieDunno) 00556 advice = mCookieJar->getGlobalAdvice(); 00557 } 00558 return KCookieJar::adviceToStr(advice); 00559 } 00560 00561 // DBUS function 00562 void 00563 KCookieServer::reloadPolicy() 00564 { 00565 mCookieJar->loadConfig( mConfig, true ); 00566 } 00567 00568 // DBUS function 00569 void 00570 KCookieServer::shutdown() 00571 { 00572 deleteLater(); 00573 } 00574 00575 #include "kcookieserver.moc" 00576
KDE 4.7 API Reference