00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "kcookiejar.h"
00038
00039 #include <config.h>
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #ifdef HAVE_SYS_PARAM_H
00043 #include <sys/param.h>
00044 #endif
00045 #include <fcntl.h>
00046 #include <unistd.h>
00047 #include <stdio.h>
00048 #include <string.h>
00049
00050 #ifdef USE_SOLARIS
00051 #include <strings.h>
00052 #endif
00053
00054 #include <stdlib.h>
00055
00056
00057
00058
00059 #include <QtCore/QString>
00060 #include <QtCore/QFile>
00061 #include <QtCore/QDir>
00062 #include <QtCore/QRegExp>
00063 #include <QtCore/QTextStream>
00064
00065 #include <kurl.h>
00066 #include <kdatetime.h>
00067 #include <kconfig.h>
00068 #include <kconfiggroup.h>
00069 #include <ksavefile.h>
00070 #include <kdebug.h>
00071
00072 #include <algorithm>
00073
00074
00075
00076
00077
00078
00079
00080 #undef MAX_COOKIE_LIMIT
00081
00082 #define MAX_COOKIES_PER_HOST 25
00083 #define READ_BUFFER_SIZE 8192
00084 #define IP_ADDRESS_EXPRESSION "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
00085
00086
00087
00088
00089
00090
00091 #define L1(x) QString::fromLatin1(x)
00092
00093 QString KCookieJar::adviceToStr(KCookieAdvice _advice)
00094 {
00095 switch( _advice )
00096 {
00097 case KCookieAccept: return L1("Accept");
00098 case KCookieReject: return L1("Reject");
00099 case KCookieAsk: return L1("Ask");
00100 default: return L1("Dunno");
00101 }
00102 }
00103
00104 KCookieAdvice KCookieJar::strToAdvice(const QString &_str)
00105 {
00106 if (_str.isEmpty())
00107 return KCookieDunno;
00108
00109 QString advice = _str.toLower();
00110
00111 if (advice == QLatin1String("accept"))
00112 return KCookieAccept;
00113 else if (advice == QLatin1String("reject"))
00114 return KCookieReject;
00115 else if (advice == QLatin1String("ask"))
00116 return KCookieAsk;
00117
00118 return KCookieDunno;
00119 }
00120
00121
00123
00124
00125
00126
00127 KHttpCookie::KHttpCookie(const QString &_host,
00128 const QString &_domain,
00129 const QString &_path,
00130 const QString &_name,
00131 const QString &_value,
00132 time_t _expireDate,
00133 int _protocolVersion,
00134 bool _secure,
00135 bool _httpOnly,
00136 bool _explicitPath) :
00137 mHost(_host),
00138 mDomain(_domain),
00139 mPath(_path.isEmpty() ? QString() : _path),
00140 mName(_name),
00141 mValue(_value),
00142 mExpireDate(_expireDate),
00143 mProtocolVersion(_protocolVersion),
00144 mSecure(_secure),
00145 mHttpOnly(_httpOnly),
00146 mExplicitPath(_explicitPath)
00147 {
00148 }
00149
00150
00151
00152
00153 bool KHttpCookie::isExpired(time_t currentDate) const
00154 {
00155 return (mExpireDate != 0) && (mExpireDate < currentDate);
00156 }
00157
00158
00159
00160
00161 QString KHttpCookie::cookieStr(bool useDOMFormat) const
00162 {
00163 QString result;
00164
00165 if (useDOMFormat || (mProtocolVersion == 0))
00166 {
00167 if ( !mName.isEmpty() )
00168 result = mName + '=';
00169 result += mValue;
00170 }
00171 else
00172 {
00173 result = mName + '=' + mValue;
00174 if (mExplicitPath)
00175 result += L1("; $Path=\"") + mPath + L1("\"");
00176 if (!mDomain.isEmpty())
00177 result += L1("; $Domain=\"") + mDomain + L1("\"");
00178 }
00179 return result;
00180 }
00181
00182
00183
00184 bool KHttpCookie::match(const QString &fqdn, const QStringList &domains,
00185 const QString &path) const
00186 {
00187
00188 if (mDomain.isEmpty())
00189 {
00190 if (fqdn != mHost)
00191 return false;
00192 }
00193 else if (!domains.contains(mDomain))
00194 {
00195 if (mDomain[0] == '.')
00196 return false;
00197
00198
00199 QString domain = '.' + mDomain;
00200 if ( !domains.contains( domain ) )
00201 if ( fqdn != mDomain )
00202 return false;
00203 }
00204
00205
00206 if (mPath.isEmpty())
00207 return true;
00208
00209
00210
00211
00212
00213
00214 if( path.startsWith(mPath) &&
00215 (
00216 (path.length() == mPath.length() ) ||
00217 mPath.endsWith('/') ||
00218 (path[mPath.length()] == '/')
00219 ))
00220 return true;
00221
00222 return false;
00223 }
00224
00225
00227
00228
00229
00230
00231
00232
00233 KCookieJar::KCookieJar()
00234 {
00235 m_globalAdvice = KCookieDunno;
00236 m_configChanged = false;
00237 m_cookiesChanged = false;
00238
00239 KConfig cfg( "khtml/domain_info", KConfig::NoGlobals, "data" );
00240 KConfigGroup group( &cfg, QString() );
00241 QStringList countries = group.readEntry( "twoLevelTLD", QStringList() );
00242 foreach ( const QString& country, countries ) {
00243 m_twoLevelTLD.insert( country, 1 );
00244 }
00245 }
00246
00247
00248
00249
00250
00251
00252 KCookieJar::~KCookieJar()
00253 {
00254 qDeleteAll(m_cookieDomains);
00255
00256 }
00257
00258
00259 static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie& cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false)
00260 {
00261 QString domain1 = cookiePtr.domain();
00262 if (domain1.isEmpty())
00263 domain1 = cookiePtr.host();
00264
00265 QMutableListIterator<KHttpCookie> cookieIterator(*list);
00266 while (cookieIterator.hasNext()) {
00267 const KHttpCookie& cookie = cookieIterator.next();
00268 QString domain2 = cookie.domain();
00269 if (domain2.isEmpty())
00270 domain2 = cookie.host();
00271
00272 if (
00273 (cookiePtr.name() == cookie.name()) &&
00274 (
00275 nameMatchOnly ||
00276 ( (domain1 == domain2) && (cookiePtr.path() == cookie.path()) )
00277 )
00278 ) {
00279 if (updateWindowId) {
00280 Q_FOREACH(long windowId, cookie.windowIds()) {
00281 if (windowId && (!cookiePtr.windowIds().contains(windowId))) {
00282 cookiePtr.windowIds().append(windowId);
00283 }
00284 }
00285 }
00286 cookieIterator.remove();
00287 break;
00288 }
00289 }
00290 }
00291
00292
00293
00294
00295
00296
00297
00298 QString KCookieJar::findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies)
00299 {
00300 QString cookieStr;
00301 QStringList domains;
00302 QString fqdn;
00303 QString path;
00304 KCookieAdvice advice = m_globalAdvice;
00305
00306 if (!parseUrl(_url, fqdn, path))
00307 return cookieStr;
00308
00309 bool secureRequest = _url.startsWith( L1("https://"), Qt::CaseInsensitive ) ||
00310 _url.startsWith( L1("webdavs://"), Qt::CaseInsensitive );
00311
00312 extractDomains(fqdn, domains);
00313
00314 KHttpCookieList allCookies;
00315
00316 for(QStringList::ConstIterator it = domains.begin();
00317 true;
00318 ++it)
00319 {
00320 KHttpCookieList *cookieList;
00321 if (it == domains.end())
00322 {
00323 cookieList = pendingCookies;
00324 pendingCookies = 0;
00325 if (!cookieList)
00326 break;
00327 }
00328 else
00329 {
00330 QString key = (*it).isNull() ? L1("") : (*it);
00331 cookieList = m_cookieDomains.value(key);
00332 if (!cookieList)
00333 continue;
00334 }
00335
00336 if (cookieList->getAdvice() != KCookieDunno)
00337 advice = cookieList->getAdvice();
00338
00339 for (KHttpCookieList::iterator cookieIterator = cookieList->begin();
00340 cookieIterator != cookieList->end();
00341 ++cookieIterator ) {
00342 KHttpCookie& cookie = *cookieIterator;
00343
00344
00345
00346 if (advice == KCookieReject &&
00347 !(m_autoAcceptSessionCookies &&
00348 (m_ignoreCookieExpirationDate || cookie.expireDate() == 0)))
00349 continue;
00350
00351 if (!cookie.match(fqdn, domains, path))
00352 continue;
00353
00354 if( cookie.isSecure() && !secureRequest )
00355 continue;
00356
00357 if( cookie.isHttpOnly() && useDOMFormat )
00358 continue;
00359
00360
00361 if ( cookie.isExpired (time(0)) )
00362 {
00363
00364
00365
00366
00367 m_cookiesChanged = true;
00368 continue;
00369 }
00370
00371 if (windowId && (cookie.windowIds().indexOf(windowId) == -1))
00372 {
00373 cookie.windowIds().append(windowId);
00374 }
00375
00376 if (it == domains.end())
00377 removeDuplicateFromList(&allCookies, cookie);
00378
00379 allCookies.append(cookie);
00380 }
00381 if (it == domains.end())
00382 break;
00383 }
00384
00385 int cookieCount = 0;
00386
00387 int protVersion=0;
00388 Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00389 if (cookie.protocolVersion() > protVersion)
00390 protVersion = cookie.protocolVersion();
00391 }
00392
00393 Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00394 if (useDOMFormat) {
00395 if (cookieCount > 0)
00396 cookieStr += L1("; ");
00397 cookieStr += cookie.cookieStr(true);
00398 } else {
00399 if (cookieCount == 0) {
00400 cookieStr += L1("Cookie: ");
00401 if (protVersion > 0) {
00402 QString version;
00403 version.sprintf("$Version=%d; ", protVersion);
00404 cookieStr += version;
00405 }
00406 } else {
00407 cookieStr += L1("; ");
00408 }
00409 cookieStr += cookie.cookieStr(false);
00410 }
00411 cookieCount++;
00412 }
00413
00414 return cookieStr;
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 static const char * parseNameValue(const char *header,
00428 QString &Name,
00429 QString &Value,
00430 bool keepQuotes=false,
00431 bool rfcQuotes=false)
00432 {
00433 const char *s = header;
00434
00435 for(; (*s != '='); s++)
00436 {
00437 if ((*s=='\0') || (*s==';') || (*s=='\n'))
00438 {
00439
00440
00441 Name = "";
00442 Value = QString::fromLatin1(header);
00443 Value.truncate( s - header );
00444 Value = Value.trimmed();
00445 return (s);
00446 }
00447 }
00448
00449 Name = header;
00450 Name.truncate( s - header );
00451 Name = Name.trimmed();
00452
00453
00454 s++;
00455
00456
00457 for(; (*s == ' ') || (*s == '\t'); s++)
00458 {
00459 if ((*s=='\0') || (*s==';') || (*s=='\n'))
00460 {
00461
00462 Value = "";
00463 return (s);
00464 }
00465 }
00466
00467 if ((rfcQuotes || !keepQuotes) && (*s == '\"'))
00468 {
00469
00470 if (keepQuotes)
00471 header = s++;
00472 else
00473 header = ++s;
00474 for(;(*s != '\"');s++)
00475 {
00476 if ((*s=='\0') || (*s=='\n'))
00477 {
00478
00479 Value = QString::fromLatin1(header);
00480 Value.truncate(s - header);
00481 return (s);
00482 }
00483 }
00484 Value = QString::fromLatin1(header);
00485
00486 if (keepQuotes)
00487 Value.truncate( ++s - header );
00488 else
00489 Value.truncate( s++ - header );
00490
00491
00492 for(;; s++)
00493 {
00494 if ((*s=='\0') || (*s==';') || (*s=='\n'))
00495 break;
00496 }
00497 }
00498 else
00499 {
00500
00501 header = s;
00502 while ((*s != '\0') && (*s != ';') && (*s != '\n'))
00503 s++;
00504
00505 Value = QString::fromLatin1(header);
00506 Value.truncate( s - header );
00507 Value = Value.trimmed();
00508 }
00509 return (s);
00510
00511 }
00512
00513 void KCookieJar::stripDomain(const QString &_fqdn, QString &_domain)
00514 {
00515 QStringList domains;
00516 extractDomains(_fqdn, domains);
00517 if (domains.count() > 3)
00518 _domain = domains[3];
00519 else if ( domains.count() > 0 )
00520 _domain = domains[0];
00521 else
00522 _domain = L1("");
00523 }
00524
00525 QString KCookieJar::stripDomain(const KHttpCookie& cookie)
00526 {
00527 QString domain;
00528 if (cookie.domain().isEmpty())
00529 stripDomain( cookie.host(), domain);
00530 else
00531 stripDomain( cookie.domain(), domain);
00532 return domain;
00533 }
00534
00535 bool KCookieJar::parseUrl(const QString &_url,
00536 QString &_fqdn,
00537 QString &_path)
00538 {
00539 KUrl kurl(_url);
00540 if (!kurl.isValid())
00541 return false;
00542
00543 _fqdn = kurl.host().toLower();
00544 if (kurl.port() > 0)
00545 {
00546 if (((kurl.protocol() == L1("http")) && (kurl.port() != 80)) ||
00547 ((kurl.protocol() == L1("https")) && (kurl.port() != 443)))
00548 {
00549
00550 _fqdn = L1("%1:%2").arg(kurl.port()).arg(_fqdn);
00551 }
00552 }
00553
00554
00555
00556
00557 if(_fqdn.contains('/') || _fqdn.contains('%'))
00558 {
00559 return false;
00560 }
00561
00562 _path = kurl.path();
00563 if (_path.isEmpty())
00564 _path = L1("/");
00565
00566 QRegExp exp(L1("[\\\\/]\\.\\.[\\\\/]"));
00567
00568 if (exp.indexIn(_path) != -1)
00569 return false;
00570
00571 return true;
00572 }
00573
00574 void KCookieJar::extractDomains(const QString &_fqdn,
00575 QStringList &_domains) const
00576 {
00577 if (_fqdn.isEmpty())
00578 return;
00579
00580
00581 if (_fqdn[0] == '[')
00582 {
00583 _domains.append( _fqdn );
00584 return;
00585 }
00586
00587 if ((_fqdn[0] >= '0') && (_fqdn[0] <= '9'))
00588 {
00589 if (_fqdn.indexOf(QRegExp(IP_ADDRESS_EXPRESSION)) > -1)
00590 {
00591 _domains.append( _fqdn );
00592 return;
00593 }
00594 }
00595
00596 QStringList partList = _fqdn.split('.', QString::SkipEmptyParts);
00597
00598 if (partList.count())
00599 partList.erase(partList.begin());
00600
00601 while(partList.count())
00602 {
00603
00604 if (partList.count() == 1)
00605 break;
00606
00607 if ((partList.count() == 2) && (m_twoLevelTLD.value(partList[1].toLower(), 0) == 1))
00608 {
00609
00610 break;
00611 }
00612
00613 if ((partList.count() == 2) && (partList[1].length() == 2))
00614 {
00615
00616
00617 if (partList[0].length() <= 2)
00618 break;
00619
00620
00621
00622 const QString t = partList[0].toLower();
00623 if ((t == "com") || (t == "net") || (t == "org") || (t == "gov") || (t == "edu") || (t == "mil") || (t == "int"))
00624 break;
00625 }
00626
00627 QString domain = partList.join(L1("."));
00628 _domains.append(domain);
00629 _domains.append('.' + domain);
00630 partList.erase(partList.begin());
00631 }
00632
00633
00634
00635 _domains.prepend( '.' + _fqdn );
00636 _domains.prepend( _fqdn );
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649 static QString fixupDateTime(const QString& date)
00650 {
00651 QStringList list = date.split(' ');
00652 const int index = list.indexOf(QRegExp("[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}"));
00653
00654 if (index > -1 && (index+1) < list.count())
00655 {
00656 list.insert(index+1, list.takeAt(index));
00657 return list.join(" ");
00658 }
00659
00660 return date;
00661 }
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 KHttpCookieList KCookieJar::makeCookies(const QString &_url,
00672 const QByteArray &cookie_headers,
00673 long windowId)
00674 {
00675 KHttpCookieList cookieList;
00676 KHttpCookieList cookieList2;
00677 KHttpCookieList::iterator lastCookie = cookieList.end();
00678 const char *cookieStr = cookie_headers.data();
00679 QString Name;
00680 QString Value;
00681 QString fqdn;
00682 QString path;
00683 bool crossDomain = false;
00684
00685 if (!parseUrl(_url, fqdn, path))
00686 {
00687
00688 return KHttpCookieList();
00689 }
00690 QString defaultPath;
00691 int i = path.lastIndexOf('/');
00692 if (i > 0)
00693 defaultPath = path.left(i);
00694
00695
00696 for(;;)
00697 {
00698
00699 if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0)
00700 {
00701 cookieStr += 13;
00702 crossDomain = true;
00703 }
00704 else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0)
00705 {
00706 cookieStr = parseNameValue(cookieStr+11, Name, Value, true);
00707
00708
00709
00710
00711
00712 KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00713 if (windowId)
00714 cookie.mWindowIds.append(windowId);
00715 cookie.mCrossDomain = crossDomain;
00716
00717
00718 cookieList.append(cookie);
00719 lastCookie = cookieList.end(); --lastCookie;
00720 }
00721 else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0)
00722 {
00723
00724 cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true);
00725
00726
00727
00728
00729
00730 KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00731 if (windowId)
00732 cookie.mWindowIds.append(windowId);
00733 cookie.mCrossDomain = crossDomain;
00734
00735
00736 cookieList2.append(cookie);
00737 lastCookie = cookieList2.end(); --lastCookie;
00738 }
00739 else
00740 {
00741
00742 while (*cookieStr && *cookieStr != '\n')
00743 cookieStr++;
00744
00745 if (*cookieStr == '\n')
00746 cookieStr++;
00747
00748 if (!*cookieStr)
00749 break;
00750 else
00751 continue;
00752 }
00753
00754 while ((*cookieStr == ';') || (*cookieStr == ' '))
00755 {
00756 cookieStr++;
00757
00758
00759 cookieStr = parseNameValue(cookieStr, Name, Value);
00760
00761 QString cName = Name.toLower();
00762 if (cName == "domain")
00763 {
00764 QString dom = Value.toLower();
00765
00766
00767 if(dom.length() && dom[0] != '.')
00768 dom.prepend(".");
00769
00770 if(dom.length() > 2 && dom[dom.length()-1] == '.')
00771 dom = dom.left(dom.length()-1);
00772
00773 if(dom.count('.') > 1 || dom == ".local")
00774 lastCookie->mDomain = dom;
00775 }
00776 else if (cName == "max-age")
00777 {
00778 int max_age = Value.toInt();
00779 if (max_age == 0)
00780 lastCookie->mExpireDate = 1;
00781 else
00782 lastCookie->mExpireDate = time(0)+max_age;
00783 }
00784 else if (cName == "expires")
00785 {
00786
00787 lastCookie->mExpireDate = KDateTime::fromString(Value, KDateTime::RFCDate).toTime_t();
00788
00789
00790
00791 if (lastCookie->mExpireDate == -1)
00792 lastCookie->mExpireDate = KDateTime::fromString(fixupDateTime(Value), KDateTime::RFCDate).toTime_t();
00793
00794
00795 if (lastCookie->mExpireDate == -1)
00796 lastCookie->mExpireDate = 0;
00797 }
00798 else if (cName == "path")
00799 {
00800 if (Value.isEmpty())
00801 lastCookie->mPath = QString();
00802 else
00803 lastCookie->mPath = QUrl::fromPercentEncoding(Value.toLatin1());
00804 lastCookie->mExplicitPath = true;
00805 }
00806 else if (cName == "version")
00807 {
00808 lastCookie->mProtocolVersion = Value.toInt();
00809 }
00810 else if ((cName == "secure") ||
00811 (cName.isEmpty() && Value.toLower() == L1("secure")))
00812 {
00813 lastCookie->mSecure = true;
00814 }
00815 else if ((cName == "httponly") ||
00816 (cName.isEmpty() && Value.toLower() == L1("httponly")))
00817 {
00818 lastCookie->mHttpOnly = true;
00819 }
00820 }
00821
00822 if (*cookieStr == '\0')
00823 break;
00824
00825
00826 cookieStr++;
00827 }
00828
00829
00830 while(!cookieList2.isEmpty()) {
00831 lastCookie = cookieList2.begin();
00832 removeDuplicateFromList(&cookieList, *lastCookie, true);
00833 cookieList.append(*lastCookie);
00834 cookieList2.removeFirst();
00835 }
00836
00837 return cookieList;
00838 }
00839
00846 KHttpCookieList KCookieJar::makeDOMCookies(const QString &_url,
00847 const QByteArray &cookie_domstring,
00848 long windowId)
00849 {
00850
00851 KHttpCookieList cookieList;
00852
00853 const char *cookieStr = cookie_domstring.data();
00854 QString fqdn;
00855 QString path;
00856
00857 if (!parseUrl(_url, fqdn, path))
00858 {
00859
00860 return KHttpCookieList();
00861 }
00862
00863 QString Name;
00864 QString Value;
00865
00866 while(*cookieStr)
00867 {
00868 cookieStr = parseNameValue(cookieStr, Name, Value);
00869
00870
00871
00872
00873 KHttpCookie cookie(fqdn, QString(), QString(),
00874 Name, Value );
00875 if (windowId)
00876 cookie.mWindowIds.append(windowId);
00877
00878 cookieList.append(cookie);
00879
00880 if (*cookieStr != '\0')
00881 cookieStr++;
00882 }
00883
00884 return cookieList;
00885 }
00886
00887
00889
00890
00891 static bool compareCookies(const KHttpCookie& item1, const KHttpCookie& item2)
00892 {
00893 return item1.path().length() > item2.path().length();
00894 }
00895
00896
00897 #ifdef MAX_COOKIE_LIMIT
00898 static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr)
00899 {
00900
00901 KHttpCookiePtr lastCookie = 0;
00902 for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
00903 {
00904 if (compareCookies(cookie, cookiePtr))
00905 break;
00906 lastCookie = cookie;
00907 }
00908 if (!lastCookie)
00909 lastCookie = cookieList->first();
00910 cookieList->removeRef(lastCookie);
00911 }
00912 #endif
00913
00914
00915
00916
00917 void KCookieJar::addCookie(KHttpCookie &cookie)
00918 {
00919 QStringList domains;
00920 KHttpCookieList *cookieList = 0L;
00921
00922
00923
00924
00925 extractDomains( cookie.host(), domains );
00926 for ( QStringList::ConstIterator it = domains.begin();
00927 (it != domains.end() && !cookieList);
00928 ++it )
00929 {
00930 QString key = (*it).isNull() ? L1("") : (*it);
00931 KHttpCookieList *list= m_cookieDomains.value(key);
00932 if ( !list ) continue;
00933
00934 removeDuplicateFromList(list, cookie, false, true);
00935 }
00936
00937 QString domain = stripDomain( cookie );
00938 QString key = domain.isNull() ? L1("") : domain;
00939 cookieList = m_cookieDomains.value(key);
00940 if (!cookieList)
00941 {
00942
00943 cookieList = new KHttpCookieList();
00944
00945
00946
00947
00948 cookieList->setAdvice( KCookieDunno );
00949
00950 m_cookieDomains.insert( domain, cookieList);
00951
00952
00953 m_domainList.append(domain);
00954 }
00955
00956
00957
00958 if (!cookie.isExpired(time(0)))
00959 {
00960 #ifdef MAX_COOKIE_LIMIT
00961 if (cookieList->count() >= MAX_COOKIES_PER_HOST)
00962 makeRoom(cookieList, cookie);
00963 #endif
00964 cookieList->push_back(cookie);
00965
00966
00967 qStableSort(cookieList->begin(), cookieList->end(), compareCookies);
00968
00969 m_cookiesChanged = true;
00970 }
00971 }
00972
00973
00974
00975
00976
00977 KCookieAdvice KCookieJar::cookieAdvice(KHttpCookie& cookie)
00978 {
00979 if (m_rejectCrossDomainCookies && cookie.isCrossDomain())
00980 return KCookieReject;
00981
00982 QStringList domains;
00983 extractDomains(cookie.host(), domains);
00984
00985
00986
00987
00988 if (!cookie.domain().isEmpty())
00989 {
00990 if (!domains.contains(cookie.domain()) &&
00991 !cookie.domain().endsWith('.'+cookie.host()))
00992 cookie.fixDomain(QString());
00993 }
00994
00995 if (m_autoAcceptSessionCookies && (cookie.expireDate() == 0 ||
00996 m_ignoreCookieExpirationDate))
00997 return KCookieAccept;
00998
00999 KCookieAdvice advice = KCookieDunno;
01000 bool isFQDN = true;
01001 QStringList::Iterator it = domains.begin();
01002 while( (advice == KCookieDunno) && (it != domains.end()))
01003 {
01004 QString domain = *it;
01005
01006 if ( domain.startsWith('.') || isFQDN )
01007 {
01008 isFQDN = false;
01009 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01010 if (cookieList)
01011 advice = cookieList->getAdvice();
01012 }
01013 domains.erase(it);
01014 it = domains.begin();
01015 }
01016
01017 if (advice == KCookieDunno)
01018 advice = m_globalAdvice;
01019
01020 return advice;
01021 }
01022
01023
01024
01025
01026
01027 KCookieAdvice KCookieJar::getDomainAdvice(const QString &_domain)
01028 {
01029 KHttpCookieList *cookieList = m_cookieDomains.value(_domain);
01030 KCookieAdvice advice;
01031
01032 if (cookieList)
01033 {
01034 advice = cookieList->getAdvice();
01035 }
01036 else
01037 {
01038 advice = KCookieDunno;
01039 }
01040
01041 return advice;
01042 }
01043
01044
01045
01046
01047
01048 void KCookieJar::setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
01049 {
01050 QString domain(_domain);
01051 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01052
01053 if (cookieList)
01054 {
01055 if (cookieList->getAdvice() != _advice)
01056 {
01057 m_configChanged = true;
01058
01059 cookieList->setAdvice( _advice);
01060 }
01061
01062 if ((cookieList->isEmpty()) &&
01063 (_advice == KCookieDunno))
01064 {
01065
01066 delete m_cookieDomains.take(domain);
01067 m_domainList.removeAll(domain);
01068 }
01069 }
01070 else
01071 {
01072
01073 if (_advice != KCookieDunno)
01074 {
01075
01076 m_configChanged = true;
01077
01078 cookieList = new KHttpCookieList();
01079 cookieList->setAdvice(_advice);
01080 m_cookieDomains.insert(domain, cookieList);
01081
01082 m_domainList.append( domain);
01083 }
01084 }
01085 }
01086
01087
01088
01089
01090
01091 void KCookieJar::setDomainAdvice(const KHttpCookie& cookie, KCookieAdvice _advice)
01092 {
01093 QString domain;
01094 stripDomain(cookie.host(), domain);
01095
01096 setDomainAdvice(domain, _advice);
01097 }
01098
01099
01100
01101
01102 void KCookieJar::setGlobalAdvice(KCookieAdvice _advice)
01103 {
01104 if (m_globalAdvice != _advice)
01105 m_configChanged = true;
01106 m_globalAdvice = _advice;
01107 }
01108
01109
01110
01111
01112 const QStringList& KCookieJar::getDomainList()
01113 {
01114 return m_domainList;
01115 }
01116
01117
01118
01119
01120 KHttpCookieList *KCookieJar::getCookieList(const QString & _domain,
01121 const QString & _fqdn )
01122 {
01123 QString domain;
01124
01125 if (_domain.isEmpty())
01126 stripDomain( _fqdn, domain );
01127 else
01128 domain = _domain;
01129
01130 return m_cookieDomains.value(domain);
01131 }
01132
01133
01134
01135
01136
01137 void KCookieJar::eatCookie(KHttpCookieList::iterator cookieIterator)
01138 {
01139 const KHttpCookie& cookie = *cookieIterator;
01140 QString domain = stripDomain(cookie);
01141 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01142
01143 if (cookieList) {
01144
01145 cookieList->erase(cookieIterator);
01146
01147 if ((cookieList->isEmpty()) &&
01148 (cookieList->getAdvice() == KCookieDunno))
01149 {
01150
01151 delete m_cookieDomains.take(domain);
01152
01153 m_domainList.removeAll(domain);
01154 }
01155 }
01156 }
01157
01158 void KCookieJar::eatCookiesForDomain(const QString &domain)
01159 {
01160 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01161 if (!cookieList || cookieList->isEmpty()) return;
01162
01163 cookieList->clear();
01164 if (cookieList->getAdvice() == KCookieDunno)
01165 {
01166
01167 delete m_cookieDomains.take(domain);
01168 m_domainList.removeAll(domain);
01169 }
01170 m_cookiesChanged = true;
01171 }
01172
01173 void KCookieJar::eatSessionCookies( long windowId )
01174 {
01175 if (!windowId)
01176 return;
01177
01178 QStringList::Iterator it=m_domainList.begin();
01179 for ( ; it != m_domainList.end(); ++it )
01180 eatSessionCookies( *it, windowId, false );
01181 }
01182
01183 void KCookieJar::eatAllCookies()
01184 {
01185 for ( QStringList::Iterator it=m_domainList.begin();
01186 it != m_domainList.end();)
01187 {
01188 QString domain = *it++;
01189
01190 eatCookiesForDomain(domain);
01191 }
01192 }
01193
01194 void KCookieJar::eatSessionCookies( const QString& fqdn, long windowId,
01195 bool isFQDN )
01196 {
01197 KHttpCookieList* cookieList;
01198 if ( !isFQDN )
01199 cookieList = m_cookieDomains.value(fqdn);
01200 else {
01201 QString domain;
01202 stripDomain( fqdn, domain );
01203 cookieList = m_cookieDomains.value(domain);
01204 }
01205
01206 if (cookieList) {
01207 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01208 while (cookieIterator.hasNext()) {
01209 KHttpCookie& cookie = cookieIterator.next();
01210 if ((cookie.expireDate() != 0) && !m_ignoreCookieExpirationDate) {
01211 continue;
01212 }
01213
01214 QList<long> &ids = cookie.windowIds();
01215
01216 #ifndef NDEBUG
01217 if (ids.contains(windowId)) {
01218 if (ids.count() > 1)
01219 kDebug() << "removing window id" << windowId << "from session cookie";
01220 else
01221 kDebug() << "deleting session cookie";
01222 }
01223 #endif
01224 if (!ids.removeAll(windowId) || !ids.isEmpty()) {
01225 continue;
01226 }
01227 cookieIterator.remove();
01228 }
01229 }
01230 }
01231
01232
01233
01234
01235
01236 bool KCookieJar::saveCookies(const QString &_filename)
01237 {
01238 KSaveFile saveFile(_filename);
01239
01240 if (!saveFile.open())
01241 return false;
01242 saveFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
01243
01244 QTextStream ts(&saveFile);
01245
01246 time_t curTime = time(0);
01247
01248 ts << "# KDE Cookie File v2\n#\n";
01249
01250 QString s;
01251 s.sprintf("%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n",
01252 "# Host", "Domain", "Path", "Exp.date", "Prot",
01253 "Name", "Sec", "Value");
01254 ts << s.toLatin1().constData();
01255
01256 for ( QStringList::Iterator it=m_domainList.begin(); it != m_domainList.end();
01257 it++ )
01258 {
01259 const QString &domain = *it;
01260 bool domainPrinted = false;
01261
01262 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01263 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01264 while (cookieIterator.hasNext()) {
01265 const KHttpCookie& cookie = cookieIterator.next();
01266 if (cookie.isExpired(curTime)) {
01267
01268 cookieIterator.remove();
01269 } else if (cookie.expireDate() != 0 && !m_ignoreCookieExpirationDate) {
01270
01271 if (!domainPrinted) {
01272 domainPrinted = true;
01273 ts << '[' << domain.toLocal8Bit().data() << "]\n";
01274 }
01275
01276 QString path = L1("\"");
01277 path += cookie.path();
01278 path += '"';
01279 QString domain = L1("\"");
01280 domain += cookie.domain();
01281 domain += '"';
01282
01283 s.sprintf("%-20s %-20s %-12s %10lu %3d %-20s %-4i %s\n",
01284 cookie.host().toLatin1().constData(), domain.toLatin1().constData(),
01285 path.toLatin1().constData(), (unsigned long) cookie.expireDate(),
01286 cookie.protocolVersion(),
01287 cookie.name().isEmpty() ? cookie.value().toLatin1().constData() : cookie.name().toLatin1().constData(),
01288 (cookie.isSecure() ? 1 : 0) + (cookie.isHttpOnly() ? 2 : 0) +
01289 (cookie.hasExplicitPath() ? 4 : 0) + (cookie.name().isEmpty() ? 8 : 0),
01290 cookie.value().toLatin1().constData());
01291 ts << s.toLatin1().constData();
01292 }
01293 }
01294 }
01295
01296 return saveFile.finalize();
01297 }
01298
01299 static const char *parseField(char* &buffer, bool keepQuotes=false)
01300 {
01301 char *result;
01302 if (!keepQuotes && (*buffer == '\"'))
01303 {
01304
01305 buffer++;
01306 result = buffer;
01307 while((*buffer != '\"') && (*buffer))
01308 buffer++;
01309 }
01310 else
01311 {
01312
01313 result = buffer;
01314 while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer))
01315 buffer++;
01316 }
01317
01318 if (!*buffer)
01319 return result;
01320 *buffer++ = '\0';
01321
01322
01323 while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n'))
01324 buffer++;
01325
01326 return result;
01327 }
01328
01329
01330
01331
01332
01333
01334 bool KCookieJar::loadCookies(const QString &_filename)
01335 {
01336 FILE *fStream = fopen( QFile::encodeName(_filename), "r");
01337 if (fStream == 0)
01338 {
01339 return false;
01340 }
01341
01342 time_t curTime = time(0);
01343
01344 char *buffer = new char[READ_BUFFER_SIZE];
01345
01346 bool err = false;
01347 err = (fgets(buffer, READ_BUFFER_SIZE, fStream) == 0);
01348
01349 int version = 1;
01350 if (!err)
01351 {
01352 if (strcmp(buffer, "# KDE Cookie File\n") == 0)
01353 {
01354
01355 }
01356 else if (sscanf(buffer, "# KDE Cookie File v%d\n", &version) != 1)
01357 {
01358 err = true;
01359 }
01360 }
01361
01362 if (!err)
01363 {
01364 while(fgets(buffer, READ_BUFFER_SIZE, fStream) != 0)
01365 {
01366 char *line = buffer;
01367
01368 if ((line[0] == '#') || (line[0] == '['))
01369 continue;
01370
01371 const QString host = QString::fromLatin1( parseField(line) );
01372 const QString domain = QString::fromLatin1( parseField(line) );
01373 if (host.isEmpty() && domain.isEmpty())
01374 continue;
01375 const QString path = QString::fromLatin1( parseField(line) );
01376 const QString expStr = QString::fromLatin1( parseField(line) );
01377 if (expStr.isEmpty()) continue;
01378 const int expDate = expStr.toInt();
01379 const QString verStr = QString::fromLatin1( parseField(line) );
01380 if (verStr.isEmpty()) continue;
01381 int protVer = verStr.toInt();
01382 QString name = QString::fromLatin1( parseField(line) );
01383 bool keepQuotes = false;
01384 bool secure = false;
01385 bool httpOnly = false;
01386 bool explicitPath = false;
01387 const char *value = 0;
01388 if ((version == 2) || (protVer >= 200))
01389 {
01390 if (protVer >= 200)
01391 protVer -= 200;
01392 int i = atoi( parseField(line) );
01393 secure = i & 1;
01394 httpOnly = i & 2;
01395 explicitPath = i & 4;
01396 if (i & 8)
01397 name = "";
01398 line[strlen(line)-1] = '\0';
01399 value = line;
01400 }
01401 else
01402 {
01403 if (protVer >= 100)
01404 {
01405 protVer -= 100;
01406 keepQuotes = true;
01407 }
01408 value = parseField(line, keepQuotes);
01409 secure = atoi( parseField(line) );
01410 }
01411
01412
01413 if (!value) continue;
01414
01415
01416 if ((expDate == 0) || (expDate < curTime))
01417 continue;
01418
01419 KHttpCookie cookie(host,
01420 domain,
01421 path,
01422 name,
01423 value,
01424 expDate, protVer,
01425 secure, httpOnly, explicitPath);
01426 addCookie(cookie);
01427 }
01428 }
01429 delete [] buffer;
01430 m_cookiesChanged = false;
01431
01432 fclose( fStream);
01433 return err;
01434 }
01435
01436
01437
01438
01439
01440 void KCookieJar::saveConfig(KConfig *_config)
01441 {
01442 if (!m_configChanged)
01443 return;
01444
01445 KConfigGroup dlgGroup(_config, "Cookie Dialog");
01446 dlgGroup.writeEntry("PreferredPolicy", m_preferredPolicy);
01447 dlgGroup.writeEntry("ShowCookieDetails", m_showCookieDetails );
01448 KConfigGroup policyGroup(_config,"Cookie Policy");
01449 policyGroup.writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice));
01450
01451 QStringList domainSettings;
01452 for ( QStringList::Iterator it=m_domainList.begin();
01453 it != m_domainList.end();
01454 it++ )
01455 {
01456 const QString &domain = *it;
01457 KCookieAdvice advice = getDomainAdvice( domain);
01458 if (advice != KCookieDunno)
01459 {
01460 QString value(domain);
01461 value += ':';
01462 value += adviceToStr(advice);
01463 domainSettings.append(value);
01464 }
01465 }
01466 policyGroup.writeEntry("CookieDomainAdvice", domainSettings);
01467 _config->sync();
01468 m_configChanged = false;
01469 }
01470
01471
01472
01473
01474
01475
01476 void KCookieJar::loadConfig(KConfig *_config, bool reparse )
01477 {
01478 if ( reparse )
01479 _config->reparseConfiguration();
01480
01481 KConfigGroup dlgGroup(_config, "Cookie Dialog");
01482 m_showCookieDetails = dlgGroup.readEntry( "ShowCookieDetails" , false );
01483 m_preferredPolicy = dlgGroup.readEntry( "PreferredPolicy", 0 );
01484
01485 KConfigGroup policyGroup(_config,"Cookie Policy");
01486 QStringList domainSettings = policyGroup.readEntry("CookieDomainAdvice", QStringList());
01487 m_rejectCrossDomainCookies = policyGroup.readEntry("RejectCrossDomainCookies", true);
01488 m_autoAcceptSessionCookies = policyGroup.readEntry("AcceptSessionCookies", true);
01489 m_ignoreCookieExpirationDate = policyGroup.readEntry("IgnoreExpirationDate", false);
01490 QString value = policyGroup.readEntry("CookieGlobalAdvice", L1("Accept"));
01491 m_globalAdvice = strToAdvice(value);
01492
01493
01494
01495 const QStringList domains = m_domainList;
01496 foreach( const QString &domain, domains )
01497 {
01498 setDomainAdvice(domain, KCookieDunno);
01499 }
01500
01501
01502 for ( QStringList::Iterator it=domainSettings.begin();
01503 it != domainSettings.end(); )
01504 {
01505 const QString &value = *it++;
01506
01507 int sepPos = value.lastIndexOf(':');
01508
01509 if (sepPos <= 0)
01510 continue;
01511
01512 QString domain(value.left(sepPos));
01513 KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) );
01514 setDomainAdvice(domain, advice);
01515 }
01516 }
01517
01518 QDebug operator<<(QDebug dbg, const KHttpCookie& cookie)
01519 {
01520 dbg.nospace() << cookie.cookieStr(false);
01521 return dbg.space();
01522 }
01523
01524 QDebug operator<<(QDebug dbg, const KHttpCookieList& list)
01525 {
01526 Q_FOREACH(const KHttpCookie& cookie, list)
01527 dbg << cookie;
01528 return dbg;
01529 }