• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIOSlave

kcookiejar.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE File Manager
00002 
00003    Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org)
00004    Copyright (C) 2000,2001 Dawit Alemayehu (adawit@kde.org)
00005 
00006    Permission is hereby granted, free of charge, to any person obtaining a copy
00007    of this software and associated documentation files (the "Software"), to deal
00008    in the Software without restriction, including without limitation the rights
00009    to use, copy, modify, merge, publish, distribute, and/or sell copies of the
00010    Software, and to permit persons to whom the Software is furnished to do so,
00011    subject to the following conditions:
00012 
00013    The above copyright notice and this permission notice shall be included in
00014    all copies or substantial portions of the Software.
00015 
00016    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019    AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00020    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00021    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 */
00023 //----------------------------------------------------------------------------
00024 //
00025 // KDE File Manager -- HTTP Cookies
00026 
00027 //
00028 // The cookie protocol is a mess. RFC2109 is a joke since nobody seems to
00029 // use it. Apart from that it is badly written.
00030 // We try to implement Netscape Cookies and try to behave us according to
00031 // RFC2109 as much as we can.
00032 //
00033 // We assume cookies do not contain any spaces (Netscape spec.)
00034 // According to RFC2109 this is allowed though.
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 //#include <netinet/in.h>
00057 //#include <arpa/inet.h>
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 // BR87227
00075 // Waba: Should the number of cookies be limited?
00076 // I am not convinced of the need of such limit
00077 // Mozilla seems to limit to 20 cookies / domain
00078 // but it is unclear which policy it uses to expire
00079 // cookies when it exceeds that amount
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 // Note with respect to QString::fromLatin1( )
00087 // Cookies are stored as 8 bit data and passed to kio_http as
00088 // latin1 regardless of their actual encoding.
00089 
00090 // L1 is used to indicate latin1 constants
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 // KHttpCookie
00123 
00124 //
00125 // Cookie constructor
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 // Checks if a cookie has been expired
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 // Returns a string for a HTTP-header
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 // Returns whether this cookie should be send to this location.
00190 bool KHttpCookie::match(const QString &fqdn, const QStringList &domains,
00191                         const QString &path) const
00192 {
00193     // Cookie domain match check
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         // Maybe the domain needs an extra dot.
00205         QString domain = '.' + mDomain;
00206         if ( !domains.contains( domain ) )
00207           if ( fqdn != mDomain )
00208             return false;
00209     }
00210 
00211     // Cookie path match check
00212     if (mPath.isEmpty())
00213         return true;
00214 
00215     // According to the netscape spec both http://www.acme.com/foobar,
00216     // http://www.acme.com/foo.bar and http://www.acme.com/foo/bar
00217     // match http://www.acme.com/foo.
00218     // We only match http://www.acme.com/foo/bar
00219 
00220     if( path.startsWith(mPath) &&
00221         (
00222          (path.length() == mPath.length() ) ||  // Paths are exact match
00223           mPath.endsWith('/') ||            // mPath ended with a slash
00224          (path[mPath.length()] == '/')      // A slash follows
00225          ))
00226         return true; // Path of URL starts with cookie-path
00227 
00228     return false;
00229 }
00230 
00231 // KCookieJar
00233 
00234 //
00235 // Constructs a new cookie jar
00236 //
00237 // One jar should be enough for all cookies.
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 // Destructs the cookie jar
00255 //
00256 // Poor little cookies, they will all be eaten by the cookie monster!
00257 //
00258 KCookieJar::~KCookieJar()
00259 {
00260     qDeleteAll(m_cookieDomains);
00261     // Not much to do here
00262 }
00263 
00264 // cookiePtr is modified: the window ids of the existing cookie in the list are added to it
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 // Looks for cookies in the cookie jar which are appropriate for _url.
00301 // Returned is a string containing all appropriate cookies in a format
00302 // which can be added to a HTTP-header without any additional processing.
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; // Add pending cookies
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; // No cookies for this domain
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             // If the we are setup to automatically accept all session cookies and to
00350             // treat all cookies as session cookies or the current cookie is a session
00351             // cookie, then send the cookie back regardless of domain policy.
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           // Do not send expired cookies.
00370           if ( cookie.isExpired())
00371           {
00372              // Note there is no need to actually delete the cookie here
00373              // since the cookieserver will invoke ::saveCookieJar because
00374              // of the state change below. This will then do the job of
00375              // deleting the cookie for us.
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()) // Only needed when processing pending cookies
00386              removeDuplicateFromList(&allCookies, cookie);
00387 
00388           allCookies.append(cookie);
00389        }
00390        if (it == domains.constEnd())
00391           break; // Finished.
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); // Without quotes
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 // This function parses a string like 'my_name="my_value";' and returns
00428 // 'my_name' in Name and 'my_value' in Value.
00429 //
00430 // A pointer to the end of the parsed part is returned.
00431 // This pointer points either to:
00432 // '\0' - The end of the string has reached.
00433 // ';'  - Another my_name="my_value" pair follows
00434 // ','  - Another cookie follows
00435 // '\n' - Another header follows
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     // Parse 'my_name' part
00444     for(; (*s != '='); s++)
00445     {
00446         if ((*s=='\0') || (*s==';') || (*s=='\n'))
00447         {
00448             // No '=' sign -> use string as the value, name is empty
00449             // (behavior found in Mozilla and IE)
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     // *s == '='
00463     s++;
00464 
00465     // Skip any whitespace
00466     for(; (*s == ' ') || (*s == '\t'); s++)
00467     {
00468         if ((*s=='\0') || (*s==';') || (*s=='\n'))
00469         {
00470             // End of Name
00471             Value = "";
00472             return (s);
00473         }
00474     }
00475 
00476     if ((rfcQuotes || !keepQuotes) && (*s == '\"'))
00477     {
00478         // Parse '"my_value"' part (quoted value)
00479         if (keepQuotes)
00480            header = s++;
00481         else
00482            header = ++s; // skip "
00483         for(;(*s != '\"');s++)
00484         {
00485             if ((*s=='\0') || (*s=='\n'))
00486             {
00487                 // End of Name
00488                 Value = QString::fromLatin1(header);
00489                 Value.truncate(s - header);
00490                 return (s);
00491             }
00492         }
00493         Value = QString::fromLatin1(header);
00494         // *s == '\"';
00495         if (keepQuotes)
00496            Value.truncate( ++s - header );
00497         else
00498            Value.truncate( s++ - header );
00499 
00500         // Skip any remaining garbage
00501         for(;; s++)
00502         {
00503             if ((*s=='\0') || (*s==';') || (*s=='\n'))
00504                 break;
00505         }
00506     }
00507     else
00508     {
00509         // Parse 'my_value' part (unquoted value)
00510         header = s;
00511         while ((*s != '\0') && (*s != ';') && (*s != '\n'))
00512             s++;
00513         // End of Name
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; // We file the cookie under this 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           // It's <port>:<host> so that the sorting works as expected
00559           _fqdn = QString::fromLatin1("%1:%2").arg(kurl.port()).arg(_fqdn);
00560        }
00561     }
00562 
00563     // Cookie spoofing protection.  Since there is no way a path separator
00564     // or escape encoded character is allowed in the hostname according
00565     // to RFC 2396, reject attempts to include such things there!
00566     if(_fqdn.contains('/') || _fqdn.contains('%'))
00567     {
00568         return false;  // deny everything!!
00569     }
00570 
00571     _path = kurl.path();
00572     if (_path.isEmpty())
00573        _path = QL1S("/");
00574 
00575     QRegExp exp(QL1S("[\\\\/]\\.\\.[\\\\/]"));
00576     // Weird path, cookie stealing attempt?
00577     if (exp.indexIn(_path) != -1)
00578        return false; // Deny everything!!
00579 
00580     return true;
00581 }
00582 
00583 // not static because it uses m_twoLevelTLD
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     // Return numeric IPv6 addresses as is...
00593     if (_fqdn[0] == '[')
00594     {
00595        _domains.append( _fqdn );
00596        return;
00597     }
00598     // Return numeric IPv4 addresses as is...
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()); // Remove hostname
00612 
00613     while(partList.count())
00614     {
00615 
00616        if (partList.count() == 1)
00617          break; // We only have a TLD left.
00618 
00619        if ((partList.count() == 2) && (m_twoLevelTLD.value(partList[1].toLower(), 0) == 1))
00620        {
00621           // This domain uses two-level TLDs in the form xxxx.yy
00622           break;
00623        }
00624 
00625        if ((partList.count() == 2) && (partList[1].length() == 2))
00626        {
00627           // If this is a TLD, we should stop. (e.g. co.uk)
00628           // We assume this is a TLD if it ends with .xx.yy or .x.yy
00629           if (partList[0].length() <= 2)
00630              break; // This is a TLD.
00631 
00632           // Catch some TLDs that we miss with the previous check
00633           // e.g. com.au, org.uk, mil.co
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()); // Remove part
00643     }
00644 
00645     // Always add the FQDN at the start of the list for
00646     // hostname == cookie-domainname checks!
00647     _domains.prepend( '.' + _fqdn );
00648     _domains.prepend( _fqdn );
00649 }
00650 
00651 //
00652 // This function parses cookie_headers and returns a linked list of
00653 // KHttpCookie objects for all cookies found in cookie_headers.
00654 // If no cookies could be found 0 is returned.
00655 //
00656 // cookie_headers should be a concatenation of all lines of a HTTP-header
00657 // which start with "Set-Cookie". The lines should be separated by '\n's.
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         // Error parsing _url
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     //  The hard stuff :)
00687     for(;;)
00688     {
00689         // check for "Set-Cookie"
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             // Host = FQDN
00700             // Default domain = ""
00701             // Default path according to rfc2109
00702 
00703             KHttpCookie cookie(fqdn, QL1S(""), defaultPath, Name, Value);
00704             if (windowId)
00705                cookie.mWindowIds.append(windowId);
00706             cookie.mCrossDomain = crossDomain;
00707 
00708             // Insert cookie in chain
00709             cookieList.append(cookie);
00710             lastCookie = cookieList.end(); --lastCookie;            
00711         }
00712         else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0)
00713         {
00714             // Attempt to follow rfc2965
00715             cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true);
00716 
00717             // Host = FQDN
00718             // Default domain = ""
00719             // Default path according to rfc2965
00720 
00721             KHttpCookie cookie(fqdn, QL1S(""), defaultPath, Name, Value);
00722             if (windowId)
00723                cookie.mWindowIds.append(windowId);
00724             cookie.mCrossDomain = crossDomain;
00725 
00726             // Insert cookie in chain
00727             cookieList2.append(cookie);
00728             lastCookie = cookieList2.end(); --lastCookie;
00729         }
00730         else
00731         {
00732             // This is not the start of a cookie header, skip till next line.
00733             while (*cookieStr && *cookieStr != '\n')
00734                 cookieStr++;
00735 
00736             if (*cookieStr == '\n')
00737                 cookieStr++;
00738 
00739             if (!*cookieStr)
00740                 break; // End of cookie_headers
00741             else
00742                 continue; // end of this header, continue with next.
00743         }
00744 
00745         while ((*cookieStr == ';') || (*cookieStr == ' '))
00746         {
00747             cookieStr++;
00748 
00749             // Name-Value pair follows
00750             cookieStr = parseNameValue(cookieStr, Name, Value);
00751 
00752             QString cName = Name.toLower();
00753             if (cName == "domain")
00754             {
00755                 QString dom = Value.toLower();
00756                 // RFC2965 3.2.2: If an explicitly specified value does not
00757                 // start with a dot, the user agent supplies a leading dot
00758                 if(dom.length() && dom[0] != '.')
00759                     dom.prepend(".");
00760                 // remove a trailing dot
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                 // Check for the most common cookie expire date format: Thu, 01-Jan-1970 00:00:00 GMT
00778                 KDateTime dt = KDateTime::fromString(Value, QL1S("%:A,%t%d-%:B-%Y%t%H:%M:%S%t%Z"));
00779                 if (!dt.isValid()) {
00780                     // Check for a variation of the above format: Thu, 01 Jan 1970 00:00:00 GMT
00781                     dt = KDateTime::fromString(Value, QL1S("%:A,%t%d%t%:B%t%Y%t%H:%M:%S%t%Z"));
00782                     if (!dt.isValid()) {
00783                         // Check for incorrect formats (amazon.com): Thu Jan 01 1970 00:00:00 GMT
00784                         dt = KDateTime::fromString(Value, QL1S("%:A%t%:B%t%d%t%Y%t%H:%M:%S%t%Z"));
00785                         if (!dt.isValid()) {
00786                             // Check for a variation of the above format: Thu Jan 01 00:00:00 1970 GMT (BR# 145244)
00787                             dt = KDateTime::fromString(Value, QL1S("%:A%t%:B%t%d%t%H:%M:%S%t%Y%t%Z"));
00788                             if (!dt.isValid()) {
00789                                 // Finally we try the RFC date formats as last resort
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(); // Catch "" <> QString()
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; // End of header
00828 
00829         // Skip ';' or '\n'
00830         cookieStr++;
00831     }
00832 
00833     // RFC2965 cookies come last so that they override netscape cookies.
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     // A lot copied from above
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         // Error parsing _url
00864         return KHttpCookieList();
00865     }
00866 
00867     QString Name;
00868     QString Value;
00869     //  This time it's easy
00870     while(*cookieStr)
00871     {
00872         cookieStr = parseNameValue(cookieStr, Name, Value);
00873 
00874         // Host = FQDN
00875         // Default domain = ""
00876         // Default path = ""
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++;         // Skip ';' or '\n'
00886     }
00887 
00888     return cookieList;
00889 }
00890 
00891 // KHttpCookieList sorting
00893 
00894 // We want the longest path first
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      // Too many cookies: throw one away, try to be somewhat clever
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 // This function hands a KHttpCookie object over to the cookie jar.
00920 //
00921 void KCookieJar::addCookie(KHttpCookie &cookie)
00922 {
00923     QStringList domains;
00924     KHttpCookieList *cookieList = 0L;
00925 
00926     // We always need to do this to make sure that the
00927     // that cookies of type hostname == cookie-domainname
00928     // are properly removed and/or updated as necessary!
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         // Make a new cookie list
00947         cookieList = new KHttpCookieList();
00948 
00949         // All cookies whose domain is not already
00950         // known to us should be added with KCookieDunno.
00951         // KCookieDunno means that we use the global policy.
00952         cookieList->setAdvice( KCookieDunno );
00953 
00954         m_cookieDomains.insert( domain, cookieList);
00955 
00956         // Update the list of domains
00957         m_domainList.append(domain);
00958     }
00959 
00960     // Add the cookie to the cookie list
00961     // The cookie list is sorted 'longest path first'
00962     if (!cookie.isExpired())
00963     {
00964 #ifdef MAX_COOKIE_LIMIT
00965         if (cookieList->count() >= MAX_COOKIES_PER_HOST)
00966            makeRoom(cookieList, cookie); // Delete a cookie
00967 #endif
00968         cookieList->push_back(cookie);
00969         // Use a stable sort so that unit tests are reliable.
00970         // In practice it doesn't matter though.
00971         qStableSort(cookieList->begin(), cookieList->end(), compareCookies);
00972 
00973         m_cookiesChanged = true;
00974     }
00975 }
00976 
00977 //
00978 // This function advices whether a single KHttpCookie object should
00979 // be added to the cookie jar.
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     // If the cookie specifies a domain, check whether it is valid. Otherwise,
00990     // accept the cookie anyways but removes the domain="" value to prevent
00991     // cross-site cookie injection.
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; // First is FQDN
01005     QStringList::Iterator it = domains.begin(); // Start with FQDN which first in the list.
01006     while( (advice == KCookieDunno) && (it != domains.end()))
01007     {
01008        QString domain = *it;
01009        // Check if a policy for the FQDN/domain is set.
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(); // Continue from begin of remaining list
01019     }
01020 
01021     if (advice == KCookieDunno)
01022         advice = m_globalAdvice;
01023 
01024     return advice;
01025 }
01026 
01027 //
01028 // This function gets the advice for all cookies originating from
01029 // _domain.
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 // This function sets the advice for all cookies originating from
01050 // _domain.
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            // domain is already known
01063            cookieList->setAdvice( _advice);
01064         }
01065 
01066         if ((cookieList->isEmpty()) &&
01067             (_advice == KCookieDunno))
01068         {
01069             // This deletes cookieList!
01070             delete m_cookieDomains.take(domain);
01071             m_domainList.removeAll(domain);
01072         }
01073     }
01074     else
01075     {
01076         // domain is not yet known
01077         if (_advice != KCookieDunno)
01078         {
01079             // We should create a domain entry
01080             m_configChanged = true;
01081             // Make a new cookie list
01082             cookieList = new KHttpCookieList();
01083             cookieList->setAdvice(_advice);
01084             m_cookieDomains.insert(domain, cookieList);
01085             // Update the list of domains
01086             m_domainList.append( domain);
01087         }
01088     }
01089 }
01090 
01091 //
01092 // This function sets the advice for all cookies originating from
01093 // the same domain as _cookie
01094 //
01095 void KCookieJar::setDomainAdvice(const KHttpCookie& cookie, KCookieAdvice _advice)
01096 {
01097     QString domain;
01098     stripDomain(cookie.host(), domain); // We file the cookie under this domain.
01099 
01100     setDomainAdvice(domain, _advice);
01101 }
01102 
01103 //
01104 // This function sets the global advice for cookies
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 // Get a list of all domains known to the cookie jar.
01115 //
01116 const QStringList& KCookieJar::getDomainList()
01117 {
01118     return m_domainList;
01119 }
01120 
01121 //
01122 // Get a list of all cookies in the cookie jar originating from _domain.
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 // Eat a cookie out of the jar.
01139 // cookieIterator should be one of the cookies returned by getCookieList()
01140 //
01141 void KCookieJar::eatCookie(KHttpCookieList::iterator cookieIterator)
01142 {
01143     const KHttpCookie& cookie = *cookieIterator;
01144     QString domain = stripDomain(cookie); // We file the cookie under this domain.
01145     KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01146 
01147     if (cookieList) {
01148         // This deletes cookie!
01149         cookieList->erase(cookieIterator);
01150 
01151         if ((cookieList->isEmpty()) &&
01152             (cookieList->getAdvice() == KCookieDunno))
01153         {
01154             // This deletes cookieList!
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        // This deletes cookieList!
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         // This might remove domain from m_domainList!
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 // Saves all cookies to the file '_filename'.
01235 // On succes 'true' is returned.
01236 // On failure 'false' is returned.
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                 // Delete expired cookies
01267                 cookieIterator.remove();
01268             } else if (cookie.expireDate() != 0 && !m_ignoreCookieExpirationDate) {
01269                 // Only save cookies that are not "session-only cookies"
01270                 if (!domainPrinted) {
01271                     domainPrinted = true;
01272                     ts << '[' << domain.toLocal8Bit().data() << "]\n";
01273                 }
01274                 // Store persistent cookies
01275                 QString path = QL1S("\"");
01276                 path += cookie.path();
01277                 path += '"';
01278                 QString domain = QL1S("\"");
01279                 domain += cookie.domain();
01280                 domain += '"';
01281                 // TODO: replace with direct QTextStream output ?
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         // Find terminating "
01304         buffer++;
01305         result = buffer;
01306         while((*buffer != '\"') && (*buffer))
01307             buffer++;
01308     }
01309     else
01310     {
01311         // Find first white space
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     // Skip white-space
01322     while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n'))
01323         buffer++;
01324 
01325     return result;
01326 }
01327 
01328 
01329 //
01330 // Reloads all cookies from the file '_filename'.
01331 // On succes 'true' is returned.
01332 // On failure 'false' is returned.
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             // version 1
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             // Skip lines which begin with '#' or '['
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'; // Strip LF.
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             // Parse error
01412             if (!value) continue;
01413 
01414             // Expired or parse error
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 // Save the cookie configuration
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 // Load the cookie configuration
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     // Warning: those default values are duplicated in the kcm (kio/kcookiespolicies.cpp)
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     // Reset current domain settings first.
01494     //  (must make a copy because setDomainAdvice() might delete the domain from m_domainList inside the for loop)
01495     const QStringList domains = m_domainList;
01496     Q_FOREACH( const QString &domain, domains )
01497     {
01498          setDomainAdvice(domain, KCookieDunno);
01499     }
01500 
01501     // Now apply the domain settings read from config file...
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 }

KIOSlave

Skip menu "KIOSlave"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal