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