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