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) QLatin1String(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 Q_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.constBegin();
00317 true;
00318 ++it)
00319 {
00320 KHttpCookieList *cookieList;
00321 if (it == domains.constEnd())
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
00352 if (!cookie.match(fqdn, domains, path))
00353 continue;
00354
00355 if( cookie.isSecure() && !secureRequest ) {
00356 continue;
00357 }
00358
00359 if( cookie.isHttpOnly() && useDOMFormat ) {
00360 continue;
00361 }
00362
00363
00364 if ( cookie.isExpired (time(0)) )
00365 {
00366
00367
00368
00369
00370 m_cookiesChanged = true;
00371 continue;
00372 }
00373
00374 if (windowId && (cookie.windowIds().indexOf(windowId) == -1))
00375 {
00376 cookie.windowIds().append(windowId);
00377 }
00378
00379 if (it == domains.constEnd())
00380 removeDuplicateFromList(&allCookies, cookie);
00381
00382 allCookies.append(cookie);
00383 }
00384 if (it == domains.constEnd())
00385 break;
00386 }
00387
00388 int cookieCount = 0;
00389
00390 int protVersion=0;
00391 Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00392 if (cookie.protocolVersion() > protVersion)
00393 protVersion = cookie.protocolVersion();
00394 }
00395
00396 Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00397 if (useDOMFormat) {
00398 if (cookieCount > 0)
00399 cookieStr += L1("; ");
00400 cookieStr += cookie.cookieStr(true);
00401 } else {
00402 if (cookieCount == 0) {
00403 cookieStr += L1("Cookie: ");
00404 if (protVersion > 0) {
00405 QString version;
00406 version.sprintf("$Version=%d; ", protVersion);
00407 cookieStr += version;
00408 }
00409 } else {
00410 cookieStr += L1("; ");
00411 }
00412 cookieStr += cookie.cookieStr(false);
00413 }
00414 cookieCount++;
00415 }
00416
00417 return cookieStr;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 static const char * parseNameValue(const char *header,
00431 QString &Name,
00432 QString &Value,
00433 bool keepQuotes=false,
00434 bool rfcQuotes=false)
00435 {
00436 const char *s = header;
00437
00438 for(; (*s != '='); s++)
00439 {
00440 if ((*s=='\0') || (*s==';') || (*s=='\n'))
00441 {
00442
00443
00444 Name = "";
00445 Value = QString::fromLatin1(header);
00446 Value.truncate( s - header );
00447 Value = Value.trimmed();
00448 return (s);
00449 }
00450 }
00451
00452 Name = header;
00453 Name.truncate( s - header );
00454 Name = Name.trimmed();
00455
00456
00457 s++;
00458
00459
00460 for(; (*s == ' ') || (*s == '\t'); s++)
00461 {
00462 if ((*s=='\0') || (*s==';') || (*s=='\n'))
00463 {
00464
00465 Value = "";
00466 return (s);
00467 }
00468 }
00469
00470 if ((rfcQuotes || !keepQuotes) && (*s == '\"'))
00471 {
00472
00473 if (keepQuotes)
00474 header = s++;
00475 else
00476 header = ++s;
00477 for(;(*s != '\"');s++)
00478 {
00479 if ((*s=='\0') || (*s=='\n'))
00480 {
00481
00482 Value = QString::fromLatin1(header);
00483 Value.truncate(s - header);
00484 return (s);
00485 }
00486 }
00487 Value = QString::fromLatin1(header);
00488
00489 if (keepQuotes)
00490 Value.truncate( ++s - header );
00491 else
00492 Value.truncate( s++ - header );
00493
00494
00495 for(;; s++)
00496 {
00497 if ((*s=='\0') || (*s==';') || (*s=='\n'))
00498 break;
00499 }
00500 }
00501 else
00502 {
00503
00504 header = s;
00505 while ((*s != '\0') && (*s != ';') && (*s != '\n'))
00506 s++;
00507
00508 Value = QString::fromLatin1(header);
00509 Value.truncate( s - header );
00510 Value = Value.trimmed();
00511 }
00512 return (s);
00513
00514 }
00515
00516 void KCookieJar::stripDomain(const QString &_fqdn, QString &_domain)
00517 {
00518 QStringList domains;
00519 extractDomains(_fqdn, domains);
00520 if (domains.count() > 3)
00521 _domain = domains[3];
00522 else if ( domains.count() > 0 )
00523 _domain = domains[0];
00524 else
00525 _domain = L1("");
00526 }
00527
00528 QString KCookieJar::stripDomain(const KHttpCookie& cookie)
00529 {
00530 QString domain;
00531 if (cookie.domain().isEmpty())
00532 stripDomain( cookie.host(), domain);
00533 else
00534 stripDomain( cookie.domain(), domain);
00535 return domain;
00536 }
00537
00538 bool KCookieJar::parseUrl(const QString &_url,
00539 QString &_fqdn,
00540 QString &_path)
00541 {
00542 KUrl kurl(_url);
00543 if (!kurl.isValid() || kurl.protocol().isEmpty())
00544 return false;
00545
00546 _fqdn = kurl.host().toLower();
00547 if (kurl.port() > 0)
00548 {
00549 if (((kurl.protocol() == L1("http")) && (kurl.port() != 80)) ||
00550 ((kurl.protocol() == L1("https")) && (kurl.port() != 443)))
00551 {
00552
00553 _fqdn = QString::fromLatin1("%1:%2").arg(kurl.port()).arg(_fqdn);
00554 }
00555 }
00556
00557
00558
00559
00560 if(_fqdn.contains('/') || _fqdn.contains('%'))
00561 {
00562 return false;
00563 }
00564
00565 _path = kurl.path();
00566 if (_path.isEmpty())
00567 _path = L1("/");
00568
00569 QRegExp exp(L1("[\\\\/]\\.\\.[\\\\/]"));
00570
00571 if (exp.indexIn(_path) != -1)
00572 return false;
00573
00574 return true;
00575 }
00576
00577
00578 void KCookieJar::extractDomains(const QString &_fqdn,
00579 QStringList &_domains) const
00580 {
00581 if (_fqdn.isEmpty()) {
00582 _domains.append( L1("localhost") );
00583 return;
00584 }
00585
00586
00587 if (_fqdn[0] == '[')
00588 {
00589 _domains.append( _fqdn );
00590 return;
00591 }
00592
00593 if ((_fqdn[0] >= '0') && (_fqdn[0] <= '9'))
00594 {
00595 if (_fqdn.indexOf(QRegExp(IP_ADDRESS_EXPRESSION)) > -1)
00596 {
00597 _domains.append( _fqdn );
00598 return;
00599 }
00600 }
00601
00602 QStringList partList = _fqdn.split('.', QString::SkipEmptyParts);
00603
00604 if (partList.count())
00605 partList.erase(partList.begin());
00606
00607 while(partList.count())
00608 {
00609
00610 if (partList.count() == 1)
00611 break;
00612
00613 if ((partList.count() == 2) && (m_twoLevelTLD.value(partList[1].toLower(), 0) == 1))
00614 {
00615
00616 break;
00617 }
00618
00619 if ((partList.count() == 2) && (partList[1].length() == 2))
00620 {
00621
00622
00623 if (partList[0].length() <= 2)
00624 break;
00625
00626
00627
00628 const QString t = partList[0].toLower();
00629 if ((t == "com") || (t == "net") || (t == "org") || (t == "gov") || (t == "edu") || (t == "mil") || (t == "int"))
00630 break;
00631 }
00632
00633 QString domain = partList.join(L1("."));
00634 _domains.append(domain);
00635 _domains.append('.' + domain);
00636 partList.erase(partList.begin());
00637 }
00638
00639
00640
00641 _domains.prepend( '.' + _fqdn );
00642 _domains.prepend( _fqdn );
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 static QString fixupDateTime(const QString& date)
00656 {
00657 QStringList list = date.split(' ');
00658 const int index = list.indexOf(QRegExp("[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}"));
00659
00660 if (index > -1 && (index+1) < list.count())
00661 {
00662 list.insert(index+1, list.takeAt(index));
00663 return list.join(" ");
00664 }
00665
00666 return date;
00667 }
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 KHttpCookieList KCookieJar::makeCookies(const QString &_url,
00678 const QByteArray &cookie_headers,
00679 long windowId)
00680 {
00681 KHttpCookieList cookieList;
00682 KHttpCookieList cookieList2;
00683 KHttpCookieList::iterator lastCookie = cookieList.end();
00684 const char *cookieStr = cookie_headers.data();
00685 QString Name;
00686 QString Value;
00687 QString fqdn;
00688 QString path;
00689 bool crossDomain = false;
00690
00691 if (!parseUrl(_url, fqdn, path))
00692 {
00693
00694 return KHttpCookieList();
00695 }
00696 QString defaultPath;
00697 int i = path.lastIndexOf('/');
00698 if (i > 0)
00699 defaultPath = path.left(i);
00700
00701
00702 for(;;)
00703 {
00704
00705 if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0)
00706 {
00707 cookieStr += 13;
00708 crossDomain = true;
00709 }
00710 else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0)
00711 {
00712 cookieStr = parseNameValue(cookieStr+11, Name, Value, true);
00713
00714
00715
00716
00717
00718 KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00719 if (windowId)
00720 cookie.mWindowIds.append(windowId);
00721 cookie.mCrossDomain = crossDomain;
00722
00723
00724 cookieList.append(cookie);
00725 lastCookie = cookieList.end(); --lastCookie;
00726 }
00727 else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0)
00728 {
00729
00730 cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true);
00731
00732
00733
00734
00735
00736 KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00737 if (windowId)
00738 cookie.mWindowIds.append(windowId);
00739 cookie.mCrossDomain = crossDomain;
00740
00741
00742 cookieList2.append(cookie);
00743 lastCookie = cookieList2.end(); --lastCookie;
00744 }
00745 else
00746 {
00747
00748 while (*cookieStr && *cookieStr != '\n')
00749 cookieStr++;
00750
00751 if (*cookieStr == '\n')
00752 cookieStr++;
00753
00754 if (!*cookieStr)
00755 break;
00756 else
00757 continue;
00758 }
00759
00760 while ((*cookieStr == ';') || (*cookieStr == ' '))
00761 {
00762 cookieStr++;
00763
00764
00765 cookieStr = parseNameValue(cookieStr, Name, Value);
00766
00767 QString cName = Name.toLower();
00768 if (cName == "domain")
00769 {
00770 QString dom = Value.toLower();
00771
00772
00773 if(dom.length() && dom[0] != '.')
00774 dom.prepend(".");
00775
00776 if(dom.length() > 2 && dom[dom.length()-1] == '.')
00777 dom = dom.left(dom.length()-1);
00778
00779 if(dom.count('.') > 1 || dom == ".local")
00780 lastCookie->mDomain = dom;
00781 }
00782 else if (cName == "max-age")
00783 {
00784 int max_age = Value.toInt();
00785 if (max_age == 0)
00786 lastCookie->mExpireDate = 1;
00787 else
00788 lastCookie->mExpireDate = time(0)+max_age;
00789 }
00790 else if (cName == "expires")
00791 {
00792
00793 lastCookie->mExpireDate = KDateTime::fromString(Value, KDateTime::RFCDate).toTime_t();
00794
00795
00796
00797 if (lastCookie->mExpireDate == -1)
00798 lastCookie->mExpireDate = KDateTime::fromString(fixupDateTime(Value), KDateTime::RFCDate).toTime_t();
00799
00800
00801 if (lastCookie->mExpireDate == -1)
00802 lastCookie->mExpireDate = 0;
00803 }
00804 else if (cName == "path")
00805 {
00806 if (Value.isEmpty())
00807 lastCookie->mPath.clear();
00808 else
00809 lastCookie->mPath = QUrl::fromPercentEncoding(Value.toLatin1());
00810 lastCookie->mExplicitPath = true;
00811 }
00812 else if (cName == "version")
00813 {
00814 lastCookie->mProtocolVersion = Value.toInt();
00815 }
00816 else if ((cName == "secure") ||
00817 (cName.isEmpty() && Value.toLower() == L1("secure")))
00818 {
00819 lastCookie->mSecure = true;
00820 }
00821 else if ((cName == "httponly") ||
00822 (cName.isEmpty() && Value.toLower() == L1("httponly")))
00823 {
00824 lastCookie->mHttpOnly = true;
00825 }
00826 }
00827
00828 if (*cookieStr == '\0')
00829 break;
00830
00831
00832 cookieStr++;
00833 }
00834
00835
00836 while(!cookieList2.isEmpty()) {
00837 lastCookie = cookieList2.begin();
00838 removeDuplicateFromList(&cookieList, *lastCookie, true);
00839 cookieList.append(*lastCookie);
00840 cookieList2.removeFirst();
00841 }
00842
00843 return cookieList;
00844 }
00845
00852 KHttpCookieList KCookieJar::makeDOMCookies(const QString &_url,
00853 const QByteArray &cookie_domstring,
00854 long windowId)
00855 {
00856
00857 KHttpCookieList cookieList;
00858
00859 const char *cookieStr = cookie_domstring.data();
00860 QString fqdn;
00861 QString path;
00862
00863 if (!parseUrl(_url, fqdn, path))
00864 {
00865
00866 return KHttpCookieList();
00867 }
00868
00869 QString Name;
00870 QString Value;
00871
00872 while(*cookieStr)
00873 {
00874 cookieStr = parseNameValue(cookieStr, Name, Value);
00875
00876
00877
00878
00879 KHttpCookie cookie(fqdn, QString(), QString(),
00880 Name, Value );
00881 if (windowId)
00882 cookie.mWindowIds.append(windowId);
00883
00884 cookieList.append(cookie);
00885
00886 if (*cookieStr != '\0')
00887 cookieStr++;
00888 }
00889
00890 return cookieList;
00891 }
00892
00893
00895
00896
00897 static bool compareCookies(const KHttpCookie& item1, const KHttpCookie& item2)
00898 {
00899 return item1.path().length() > item2.path().length();
00900 }
00901
00902
00903 #ifdef MAX_COOKIE_LIMIT
00904 static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr)
00905 {
00906
00907 KHttpCookiePtr lastCookie = 0;
00908 for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
00909 {
00910 if (compareCookies(cookie, cookiePtr))
00911 break;
00912 lastCookie = cookie;
00913 }
00914 if (!lastCookie)
00915 lastCookie = cookieList->first();
00916 cookieList->removeRef(lastCookie);
00917 }
00918 #endif
00919
00920
00921
00922
00923 void KCookieJar::addCookie(KHttpCookie &cookie)
00924 {
00925 QStringList domains;
00926 KHttpCookieList *cookieList = 0L;
00927
00928
00929
00930
00931 extractDomains( cookie.host(), domains );
00932 for ( QStringList::ConstIterator it = domains.constBegin();
00933 (it != domains.constEnd() && !cookieList);
00934 ++it )
00935 {
00936 QString key = (*it).isNull() ? QString::fromLatin1("") : (*it);
00937 KHttpCookieList *list= m_cookieDomains.value(key);
00938 if ( !list ) continue;
00939
00940 removeDuplicateFromList(list, cookie, false, true);
00941 }
00942
00943 QString domain = stripDomain( cookie );
00944 QString key = domain.isNull() ? QString::fromLatin1("") : domain;
00945 cookieList = m_cookieDomains.value(key);
00946 if (!cookieList)
00947 {
00948
00949 cookieList = new KHttpCookieList();
00950
00951
00952
00953
00954 cookieList->setAdvice( KCookieDunno );
00955
00956 m_cookieDomains.insert( domain, cookieList);
00957
00958
00959 m_domainList.append(domain);
00960 }
00961
00962
00963
00964 if (!cookie.isExpired(time(0)))
00965 {
00966 #ifdef MAX_COOKIE_LIMIT
00967 if (cookieList->count() >= MAX_COOKIES_PER_HOST)
00968 makeRoom(cookieList, cookie);
00969 #endif
00970 cookieList->push_back(cookie);
00971
00972
00973 qStableSort(cookieList->begin(), cookieList->end(), compareCookies);
00974
00975 m_cookiesChanged = true;
00976 }
00977 }
00978
00979
00980
00981
00982
00983 KCookieAdvice KCookieJar::cookieAdvice(KHttpCookie& cookie)
00984 {
00985 if (m_rejectCrossDomainCookies && cookie.isCrossDomain())
00986 return KCookieReject;
00987
00988 QStringList domains;
00989 extractDomains(cookie.host(), domains);
00990
00991
00992
00993
00994 if (!cookie.domain().isEmpty())
00995 {
00996 if (!domains.contains(cookie.domain()) &&
00997 !cookie.domain().endsWith('.'+cookie.host()))
00998 cookie.fixDomain(QString());
00999 }
01000
01001 if (m_autoAcceptSessionCookies && (cookie.expireDate() == 0 ||
01002 m_ignoreCookieExpirationDate))
01003 return KCookieAccept;
01004
01005 KCookieAdvice advice = KCookieDunno;
01006 bool isFQDN = true;
01007 QStringList::Iterator it = domains.begin();
01008 while( (advice == KCookieDunno) && (it != domains.end()))
01009 {
01010 QString domain = *it;
01011
01012 if ( domain.startsWith('.') || isFQDN )
01013 {
01014 isFQDN = false;
01015 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01016 if (cookieList)
01017 advice = cookieList->getAdvice();
01018 }
01019 domains.erase(it);
01020 it = domains.begin();
01021 }
01022
01023 if (advice == KCookieDunno)
01024 advice = m_globalAdvice;
01025
01026 return advice;
01027 }
01028
01029
01030
01031
01032
01033 KCookieAdvice KCookieJar::getDomainAdvice(const QString &_domain)
01034 {
01035 KHttpCookieList *cookieList = m_cookieDomains.value(_domain);
01036 KCookieAdvice advice;
01037
01038 if (cookieList)
01039 {
01040 advice = cookieList->getAdvice();
01041 }
01042 else
01043 {
01044 advice = KCookieDunno;
01045 }
01046
01047 return advice;
01048 }
01049
01050
01051
01052
01053
01054 void KCookieJar::setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
01055 {
01056 QString domain(_domain);
01057 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01058
01059 if (cookieList)
01060 {
01061 if (cookieList->getAdvice() != _advice)
01062 {
01063 m_configChanged = true;
01064
01065 cookieList->setAdvice( _advice);
01066 }
01067
01068 if ((cookieList->isEmpty()) &&
01069 (_advice == KCookieDunno))
01070 {
01071
01072 delete m_cookieDomains.take(domain);
01073 m_domainList.removeAll(domain);
01074 }
01075 }
01076 else
01077 {
01078
01079 if (_advice != KCookieDunno)
01080 {
01081
01082 m_configChanged = true;
01083
01084 cookieList = new KHttpCookieList();
01085 cookieList->setAdvice(_advice);
01086 m_cookieDomains.insert(domain, cookieList);
01087
01088 m_domainList.append( domain);
01089 }
01090 }
01091 }
01092
01093
01094
01095
01096
01097 void KCookieJar::setDomainAdvice(const KHttpCookie& cookie, KCookieAdvice _advice)
01098 {
01099 QString domain;
01100 stripDomain(cookie.host(), domain);
01101
01102 setDomainAdvice(domain, _advice);
01103 }
01104
01105
01106
01107
01108 void KCookieJar::setGlobalAdvice(KCookieAdvice _advice)
01109 {
01110 if (m_globalAdvice != _advice)
01111 m_configChanged = true;
01112 m_globalAdvice = _advice;
01113 }
01114
01115
01116
01117
01118 const QStringList& KCookieJar::getDomainList()
01119 {
01120 return m_domainList;
01121 }
01122
01123
01124
01125
01126 KHttpCookieList *KCookieJar::getCookieList(const QString & _domain,
01127 const QString & _fqdn )
01128 {
01129 QString domain;
01130
01131 if (_domain.isEmpty())
01132 stripDomain(_fqdn, domain);
01133 else
01134 stripDomain (_domain, domain);
01135
01136 return m_cookieDomains.value(domain);
01137 }
01138
01139
01140
01141
01142
01143 void KCookieJar::eatCookie(KHttpCookieList::iterator cookieIterator)
01144 {
01145 const KHttpCookie& cookie = *cookieIterator;
01146 QString domain = stripDomain(cookie);
01147 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01148
01149 if (cookieList) {
01150
01151 cookieList->erase(cookieIterator);
01152
01153 if ((cookieList->isEmpty()) &&
01154 (cookieList->getAdvice() == KCookieDunno))
01155 {
01156
01157 delete m_cookieDomains.take(domain);
01158
01159 m_domainList.removeAll(domain);
01160 }
01161 }
01162 }
01163
01164 void KCookieJar::eatCookiesForDomain(const QString &domain)
01165 {
01166 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01167 if (!cookieList || cookieList->isEmpty()) return;
01168
01169 cookieList->clear();
01170 if (cookieList->getAdvice() == KCookieDunno)
01171 {
01172
01173 delete m_cookieDomains.take(domain);
01174 m_domainList.removeAll(domain);
01175 }
01176 m_cookiesChanged = true;
01177 }
01178
01179 void KCookieJar::eatSessionCookies( long windowId )
01180 {
01181 if (!windowId)
01182 return;
01183
01184 QStringList::const_iterator it=m_domainList.constBegin();
01185 for ( ; it != m_domainList.constEnd(); ++it )
01186 eatSessionCookies( *it, windowId, false );
01187 }
01188
01189 void KCookieJar::eatAllCookies()
01190 {
01191 Q_FOREACH(const QString& domain, m_domainList) {
01192
01193 eatCookiesForDomain(domain);
01194 }
01195 }
01196
01197 void KCookieJar::eatSessionCookies( const QString& fqdn, long windowId,
01198 bool isFQDN )
01199 {
01200 KHttpCookieList* cookieList;
01201 if ( !isFQDN )
01202 cookieList = m_cookieDomains.value(fqdn);
01203 else {
01204 QString domain;
01205 stripDomain( fqdn, domain );
01206 cookieList = m_cookieDomains.value(domain);
01207 }
01208
01209 if (cookieList) {
01210 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01211 while (cookieIterator.hasNext()) {
01212 KHttpCookie& cookie = cookieIterator.next();
01213 if ((cookie.expireDate() != 0) && !m_ignoreCookieExpirationDate) {
01214 continue;
01215 }
01216
01217 QList<long> &ids = cookie.windowIds();
01218
01219 #ifndef NDEBUG
01220 if (ids.contains(windowId)) {
01221 if (ids.count() > 1)
01222 kDebug() << "removing window id" << windowId << "from session cookie";
01223 else
01224 kDebug() << "deleting session cookie";
01225 }
01226 #endif
01227 if (!ids.removeAll(windowId) || !ids.isEmpty()) {
01228 continue;
01229 }
01230 cookieIterator.remove();
01231 }
01232 }
01233 }
01234
01235
01236
01237
01238
01239 bool KCookieJar::saveCookies(const QString &_filename)
01240 {
01241 KSaveFile saveFile(_filename);
01242
01243 if (!saveFile.open())
01244 return false;
01245 saveFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
01246
01247 QTextStream ts(&saveFile);
01248
01249 time_t curTime = time(0);
01250
01251 ts << "# KDE Cookie File v2\n#\n";
01252
01253 QString s;
01254 s.sprintf("%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n",
01255 "# Host", "Domain", "Path", "Exp.date", "Prot",
01256 "Name", "Sec", "Value");
01257 ts << s.toLatin1().constData();
01258
01259 for ( QStringList::const_iterator it=m_domainList.constBegin(); it != m_domainList.constEnd();
01260 it++ )
01261 {
01262 const QString &domain = *it;
01263 bool domainPrinted = false;
01264
01265 KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01266 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01267 while (cookieIterator.hasNext()) {
01268 const KHttpCookie& cookie = cookieIterator.next();
01269 if (cookie.isExpired(curTime)) {
01270
01271 cookieIterator.remove();
01272 } else if (cookie.expireDate() != 0 && !m_ignoreCookieExpirationDate) {
01273
01274 if (!domainPrinted) {
01275 domainPrinted = true;
01276 ts << '[' << domain.toLocal8Bit().data() << "]\n";
01277 }
01278
01279 QString path = L1("\"");
01280 path += cookie.path();
01281 path += '"';
01282 QString domain = L1("\"");
01283 domain += cookie.domain();
01284 domain += '"';
01285
01286 s.sprintf("%-20s %-20s %-12s %10lu %3d %-20s %-4i %s\n",
01287 cookie.host().toLatin1().constData(), domain.toLatin1().constData(),
01288 path.toLatin1().constData(), (unsigned long) cookie.expireDate(),
01289 cookie.protocolVersion(),
01290 cookie.name().isEmpty() ? cookie.value().toLatin1().constData() : cookie.name().toLatin1().constData(),
01291 (cookie.isSecure() ? 1 : 0) + (cookie.isHttpOnly() ? 2 : 0) +
01292 (cookie.hasExplicitPath() ? 4 : 0) + (cookie.name().isEmpty() ? 8 : 0),
01293 cookie.value().toLatin1().constData());
01294 ts << s.toLatin1().constData();
01295 }
01296 }
01297 }
01298
01299 return saveFile.finalize();
01300 }
01301
01302 static const char *parseField(char* &buffer, bool keepQuotes=false)
01303 {
01304 char *result;
01305 if (!keepQuotes && (*buffer == '\"'))
01306 {
01307
01308 buffer++;
01309 result = buffer;
01310 while((*buffer != '\"') && (*buffer))
01311 buffer++;
01312 }
01313 else
01314 {
01315
01316 result = buffer;
01317 while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer))
01318 buffer++;
01319 }
01320
01321 if (!*buffer)
01322 return result;
01323 *buffer++ = '\0';
01324
01325
01326 while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n'))
01327 buffer++;
01328
01329 return result;
01330 }
01331
01332
01333
01334
01335
01336
01337 bool KCookieJar::loadCookies(const QString &_filename)
01338 {
01339 FILE *fStream = fopen( QFile::encodeName(_filename), "r");
01340 if (fStream == 0)
01341 {
01342 return false;
01343 }
01344
01345 time_t curTime = time(0);
01346
01347 char *buffer = new char[READ_BUFFER_SIZE];
01348
01349 bool err = false;
01350 err = (fgets(buffer, READ_BUFFER_SIZE, fStream) == 0);
01351
01352 int version = 1;
01353 if (!err)
01354 {
01355 if (strcmp(buffer, "# KDE Cookie File\n") == 0)
01356 {
01357
01358 }
01359 else if (sscanf(buffer, "# KDE Cookie File v%d\n", &version) != 1)
01360 {
01361 err = true;
01362 }
01363 }
01364
01365 if (!err)
01366 {
01367 while(fgets(buffer, READ_BUFFER_SIZE, fStream) != 0)
01368 {
01369 char *line = buffer;
01370
01371 if ((line[0] == '#') || (line[0] == '['))
01372 continue;
01373
01374 const QString host = QString::fromLatin1( parseField(line) );
01375 const QString domain = QString::fromLatin1( parseField(line) );
01376 if (host.isEmpty() && domain.isEmpty())
01377 continue;
01378 const QString path = QString::fromLatin1( parseField(line) );
01379 const QString expStr = QString::fromLatin1( parseField(line) );
01380 if (expStr.isEmpty()) continue;
01381 const int expDate = expStr.toInt();
01382 const QString verStr = QString::fromLatin1( parseField(line) );
01383 if (verStr.isEmpty()) continue;
01384 int protVer = verStr.toInt();
01385 QString name = QString::fromLatin1( parseField(line) );
01386 bool keepQuotes = false;
01387 bool secure = false;
01388 bool httpOnly = false;
01389 bool explicitPath = false;
01390 const char *value = 0;
01391 if ((version == 2) || (protVer >= 200))
01392 {
01393 if (protVer >= 200)
01394 protVer -= 200;
01395 int i = atoi( parseField(line) );
01396 secure = i & 1;
01397 httpOnly = i & 2;
01398 explicitPath = i & 4;
01399 if (i & 8)
01400 name = "";
01401 line[strlen(line)-1] = '\0';
01402 value = line;
01403 }
01404 else
01405 {
01406 if (protVer >= 100)
01407 {
01408 protVer -= 100;
01409 keepQuotes = true;
01410 }
01411 value = parseField(line, keepQuotes);
01412 secure = atoi( parseField(line) );
01413 }
01414
01415
01416 if (!value) continue;
01417
01418
01419 if ((expDate == 0) || (expDate < curTime))
01420 continue;
01421
01422 KHttpCookie cookie(host,
01423 domain,
01424 path,
01425 name,
01426 value,
01427 expDate, protVer,
01428 secure, httpOnly, explicitPath);
01429 addCookie(cookie);
01430 }
01431 }
01432 delete [] buffer;
01433 m_cookiesChanged = false;
01434
01435 fclose( fStream);
01436 return err;
01437 }
01438
01439
01440
01441
01442
01443 void KCookieJar::saveConfig(KConfig *_config)
01444 {
01445 if (!m_configChanged)
01446 return;
01447
01448 KConfigGroup dlgGroup(_config, "Cookie Dialog");
01449 dlgGroup.writeEntry("PreferredPolicy", static_cast<int>(m_preferredPolicy));
01450 dlgGroup.writeEntry("ShowCookieDetails", m_showCookieDetails );
01451 KConfigGroup policyGroup(_config,"Cookie Policy");
01452 policyGroup.writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice));
01453
01454 QStringList domainSettings;
01455 for ( QStringList::const_iterator it=m_domainList.constBegin();
01456 it != m_domainList.constEnd();
01457 ++it )
01458 {
01459 const QString &domain = *it;
01460 KCookieAdvice advice = getDomainAdvice( domain);
01461 if (advice != KCookieDunno)
01462 {
01463 QString value(domain);
01464 value += ':';
01465 value += adviceToStr(advice);
01466 domainSettings.append(value);
01467 }
01468 }
01469 policyGroup.writeEntry("CookieDomainAdvice", domainSettings);
01470 _config->sync();
01471 m_configChanged = false;
01472 }
01473
01474
01475
01476
01477
01478
01479 void KCookieJar::loadConfig(KConfig *_config, bool reparse )
01480 {
01481 if ( reparse )
01482 _config->reparseConfiguration();
01483
01484 KConfigGroup dlgGroup(_config, "Cookie Dialog");
01485 m_showCookieDetails = dlgGroup.readEntry( "ShowCookieDetails" , false );
01486 m_preferredPolicy = static_cast<KCookieDefaultPolicy>(dlgGroup.readEntry("PreferredPolicy", 0));
01487
01488 KConfigGroup policyGroup(_config,"Cookie Policy");
01489 const QStringList domainSettings = policyGroup.readEntry("CookieDomainAdvice", QStringList());
01490
01491 m_rejectCrossDomainCookies = policyGroup.readEntry("RejectCrossDomainCookies", true);
01492 m_autoAcceptSessionCookies = policyGroup.readEntry("AcceptSessionCookies", true);
01493 m_ignoreCookieExpirationDate = policyGroup.readEntry("IgnoreExpirationDate", false);
01494 QString value = policyGroup.readEntry("CookieGlobalAdvice", QString::fromLatin1("Accept"));
01495 m_globalAdvice = strToAdvice(value);
01496
01497
01498
01499 const QStringList domains = m_domainList;
01500 Q_FOREACH( const QString &domain, domains )
01501 {
01502 setDomainAdvice(domain, KCookieDunno);
01503 }
01504
01505
01506 for ( QStringList::const_iterator it=domainSettings.begin();
01507 it != domainSettings.end(); )
01508 {
01509 const QString &value = *it++;
01510
01511 int sepPos = value.lastIndexOf(':');
01512
01513 if (sepPos <= 0)
01514 continue;
01515
01516 QString domain(value.left(sepPos));
01517 KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) );
01518 setDomainAdvice(domain, advice);
01519 }
01520 }
01521
01522 QDebug operator<<(QDebug dbg, const KHttpCookie& cookie)
01523 {
01524 dbg.nospace() << cookie.cookieStr(false);
01525 return dbg.space();
01526 }
01527
01528 QDebug operator<<(QDebug dbg, const KHttpCookieList& list)
01529 {
01530 Q_FOREACH(const KHttpCookie& cookie, list)
01531 dbg << cookie;
01532 return dbg;
01533 }