• 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 L1(x) QLatin1String(x)
00092 
00093 QString KCookieJar::adviceToStr(KCookieAdvice _advice)
00094 {
00095     switch( _advice )
00096     {
00097     case KCookieAccept: return L1("Accept");
00098     case KCookieReject: return L1("Reject");
00099     case KCookieAsk: return L1("Ask");
00100     default: return L1("Dunno");
00101     }
00102 }
00103 
00104 KCookieAdvice KCookieJar::strToAdvice(const QString &_str)
00105 {
00106     if (_str.isEmpty())
00107         return KCookieDunno;
00108 
00109     QString advice = _str.toLower();
00110 
00111     if (advice == QLatin1String("accept"))
00112         return KCookieAccept;
00113     else if (advice == QLatin1String("reject"))
00114         return KCookieReject;
00115     else if (advice == QLatin1String("ask"))
00116         return KCookieAsk;
00117 
00118     return KCookieDunno;
00119 }
00120 
00121 // 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                  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 // Checks if a cookie has been expired
00152 //
00153 bool    KHttpCookie::isExpired(time_t currentDate) const
00154 {
00155     return (mExpireDate != 0) && (mExpireDate < currentDate);
00156 }
00157 
00158 //
00159 // Returns a string for a HTTP-header
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 // Returns whether this cookie should be send to this location.
00184 bool KHttpCookie::match(const QString &fqdn, const QStringList &domains,
00185                         const QString &path) const
00186 {
00187     // Cookie domain match check
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         // Maybe the domain needs an extra dot.
00199         QString domain = '.' + mDomain;
00200         if ( !domains.contains( domain ) )
00201           if ( fqdn != mDomain )
00202             return false;
00203     }
00204 
00205     // Cookie path match check
00206     if (mPath.isEmpty())
00207         return true;
00208 
00209     // According to the netscape spec both http://www.acme.com/foobar,
00210     // http://www.acme.com/foo.bar and http://www.acme.com/foo/bar
00211     // match http://www.acme.com/foo.
00212     // We only match http://www.acme.com/foo/bar
00213 
00214     if( path.startsWith(mPath) &&
00215         (
00216          (path.length() == mPath.length() ) ||  // Paths are exact match
00217           mPath.endsWith('/') ||            // mPath ended with a slash
00218          (path[mPath.length()] == '/')      // A slash follows
00219          ))
00220         return true; // Path of URL starts with cookie-path
00221 
00222     return false;
00223 }
00224 
00225 // KCookieJar
00227 
00228 //
00229 // Constructs a new cookie jar
00230 //
00231 // One jar should be enough for all cookies.
00232 //
00233 KCookieJar::KCookieJar()
00234 {
00235     m_globalAdvice = KCookieDunno;
00236     m_configChanged = false;
00237     m_cookiesChanged = false;
00238 
00239     KConfig cfg( "khtml/domain_info", KConfig::NoGlobals, "data" );
00240     KConfigGroup group( &cfg, QString() );
00241     QStringList countries = group.readEntry( "twoLevelTLD", QStringList() );
00242     Q_FOREACH ( const QString& country, countries ) {
00243        m_twoLevelTLD.insert( country, 1 );
00244     }
00245 }
00246 
00247 //
00248 // Destructs the cookie jar
00249 //
00250 // Poor little cookies, they will all be eaten by the cookie monster!
00251 //
00252 KCookieJar::~KCookieJar()
00253 {
00254     qDeleteAll(m_cookieDomains);
00255     // Not much to do here
00256 }
00257 
00258 // cookiePtr is modified: the window ids of the existing cookie in the list are added to it
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 // Looks for cookies in the cookie jar which are appropriate for _url.
00295 // Returned is a string containing all appropriate cookies in a format
00296 // which can be added to a HTTP-header without any additional processing.
00297 //
00298 QString KCookieJar::findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies)
00299 {
00300     QString cookieStr;
00301     QStringList domains;
00302     QString fqdn;
00303     QString path;
00304     KCookieAdvice advice = m_globalAdvice;
00305 
00306     if (!parseUrl(_url, fqdn, path))
00307         return cookieStr;
00308 
00309     bool secureRequest = _url.startsWith( L1("https://"), Qt::CaseInsensitive ) ||
00310                          _url.startsWith( L1("webdavs://"), Qt::CaseInsensitive );
00311 
00312     extractDomains(fqdn, domains);
00313 
00314     KHttpCookieList allCookies;
00315 
00316     for(QStringList::ConstIterator it = domains.constBegin();
00317         true;
00318         ++it)
00319     {
00320        KHttpCookieList *cookieList;
00321        if (it == domains.constEnd())
00322        {
00323           cookieList = pendingCookies; // Add pending cookies
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; // No cookies for this domain
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             // If the we are setup to automatically accept all session cookies and to
00344             // treat all cookies as session cookies or the current cookie is a session
00345             // cookie, then send the cookie back regardless of domain policy.
00346             if (advice == KCookieReject &&
00347                 !(m_autoAcceptSessionCookies &&
00348                   (m_ignoreCookieExpirationDate || cookie.expireDate() == 0))) {
00349                 continue;
00350             }
00351 
00352           if (!cookie.match(fqdn, domains, path))
00353              continue;
00354 
00355           if( cookie.isSecure() && !secureRequest ) {
00356              continue;
00357           }
00358 
00359           if( cookie.isHttpOnly() && useDOMFormat ) {
00360              continue;
00361           }
00362 
00363           // Do not send expired cookies.
00364           if ( cookie.isExpired (time(0)) )
00365           {
00366              // Note there is no need to actually delete the cookie here
00367              // since the cookieserver will invoke ::saveCookieJar because
00368              // of the state change below. This will then do the job of
00369              // deleting the cookie for us.
00370              m_cookiesChanged = true;
00371              continue;
00372           }
00373 
00374           if (windowId && (cookie.windowIds().indexOf(windowId) == -1))
00375           {
00376              cookie.windowIds().append(windowId);
00377           }
00378 
00379           if (it == domains.constEnd()) // Only needed when processing pending cookies
00380              removeDuplicateFromList(&allCookies, cookie);
00381 
00382           allCookies.append(cookie);
00383        }
00384        if (it == domains.constEnd())
00385           break; // Finished.
00386     }
00387 
00388     int cookieCount = 0;
00389 
00390     int protVersion=0;
00391     Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00392         if (cookie.protocolVersion() > protVersion)
00393             protVersion = cookie.protocolVersion();
00394     }
00395 
00396     Q_FOREACH(const KHttpCookie& cookie, allCookies) {
00397         if (useDOMFormat) {
00398             if (cookieCount > 0)
00399                 cookieStr += L1("; ");
00400             cookieStr += cookie.cookieStr(true);
00401         } else {
00402             if (cookieCount == 0) {
00403                 cookieStr += L1("Cookie: ");
00404                 if (protVersion > 0) {
00405                     QString version;
00406                     version.sprintf("$Version=%d; ", protVersion); // Without quotes
00407                     cookieStr += version;
00408                 }
00409             } else {
00410                 cookieStr += L1("; ");
00411             }
00412             cookieStr += cookie.cookieStr(false);
00413         }
00414         cookieCount++;
00415     }
00416 
00417     return cookieStr;
00418 }
00419 
00420 //
00421 // This function parses a string like 'my_name="my_value";' and returns
00422 // 'my_name' in Name and 'my_value' in Value.
00423 //
00424 // A pointer to the end of the parsed part is returned.
00425 // This pointer points either to:
00426 // '\0' - The end of the string has reached.
00427 // ';'  - Another my_name="my_value" pair follows
00428 // ','  - Another cookie follows
00429 // '\n' - Another header follows
00430 static const char * parseNameValue(const char *header,
00431                                   QString &Name,
00432                                   QString &Value,
00433                                   bool keepQuotes=false,
00434                                   bool rfcQuotes=false)
00435 {
00436     const char *s = header;
00437     // Parse 'my_name' part
00438     for(; (*s != '='); s++)
00439     {
00440         if ((*s=='\0') || (*s==';') || (*s=='\n'))
00441         {
00442             // No '=' sign -> use string as the value, name is empty
00443             // (behavior found in Mozilla and IE)
00444             Name = "";
00445             Value = QString::fromLatin1(header);
00446             Value.truncate( s - header );
00447             Value = Value.trimmed();
00448             return (s);
00449         }
00450     }
00451 
00452     Name = header;
00453     Name.truncate( s - header );
00454     Name = Name.trimmed();
00455 
00456     // *s == '='
00457     s++;
00458 
00459     // Skip any whitespace
00460     for(; (*s == ' ') || (*s == '\t'); s++)
00461     {
00462         if ((*s=='\0') || (*s==';') || (*s=='\n'))
00463         {
00464             // End of Name
00465             Value = "";
00466             return (s);
00467         }
00468     }
00469 
00470     if ((rfcQuotes || !keepQuotes) && (*s == '\"'))
00471     {
00472         // Parse '"my_value"' part (quoted value)
00473         if (keepQuotes)
00474            header = s++;
00475         else
00476            header = ++s; // skip "
00477         for(;(*s != '\"');s++)
00478         {
00479             if ((*s=='\0') || (*s=='\n'))
00480             {
00481                 // End of Name
00482                 Value = QString::fromLatin1(header);
00483                 Value.truncate(s - header);
00484                 return (s);
00485             }
00486         }
00487         Value = QString::fromLatin1(header);
00488         // *s == '\"';
00489         if (keepQuotes)
00490            Value.truncate( ++s - header );
00491         else
00492            Value.truncate( s++ - header );
00493 
00494         // Skip any remaining garbage
00495         for(;; s++)
00496         {
00497             if ((*s=='\0') || (*s==';') || (*s=='\n'))
00498                 break;
00499         }
00500     }
00501     else
00502     {
00503         // Parse 'my_value' part (unquoted value)
00504         header = s;
00505         while ((*s != '\0') && (*s != ';') && (*s != '\n'))
00506             s++;
00507         // End of Name
00508         Value = QString::fromLatin1(header);
00509         Value.truncate( s - header );
00510         Value = Value.trimmed();
00511     }
00512     return (s);
00513 
00514 }
00515 
00516 void KCookieJar::stripDomain(const QString &_fqdn, QString &_domain)
00517 {
00518    QStringList domains;
00519    extractDomains(_fqdn, domains);
00520    if (domains.count() > 3)
00521       _domain = domains[3];
00522    else if ( domains.count() > 0 )
00523       _domain = domains[0];
00524    else
00525       _domain = L1("");
00526 }
00527 
00528 QString KCookieJar::stripDomain(const KHttpCookie& cookie)
00529 {
00530     QString domain; // We file the cookie under this domain.
00531     if (cookie.domain().isEmpty())
00532        stripDomain( cookie.host(), domain);
00533     else
00534        stripDomain( cookie.domain(), domain);
00535     return domain;
00536 }
00537 
00538 bool KCookieJar::parseUrl(const QString &_url,
00539                           QString &_fqdn,
00540                           QString &_path)
00541 {
00542     KUrl kurl(_url);
00543     if (!kurl.isValid() || kurl.protocol().isEmpty())
00544        return false;
00545 
00546     _fqdn = kurl.host().toLower();
00547     if (kurl.port() > 0)
00548     {
00549        if (((kurl.protocol() == L1("http")) && (kurl.port() != 80)) ||
00550            ((kurl.protocol() == L1("https")) && (kurl.port() != 443)))
00551        {
00552           // It's <port>:<host> so that the sorting works as expected
00553           _fqdn = QString::fromLatin1("%1:%2").arg(kurl.port()).arg(_fqdn);
00554        }
00555     }
00556 
00557     // Cookie spoofing protection.  Since there is no way a path separator
00558     // or escape encoded character is allowed in the hostname according
00559     // to RFC 2396, reject attempts to include such things there!
00560     if(_fqdn.contains('/') || _fqdn.contains('%'))
00561     {
00562         return false;  // deny everything!!
00563     }
00564 
00565     _path = kurl.path();
00566     if (_path.isEmpty())
00567        _path = L1("/");
00568 
00569     QRegExp exp(L1("[\\\\/]\\.\\.[\\\\/]"));
00570     // Weird path, cookie stealing attempt?
00571     if (exp.indexIn(_path) != -1)
00572        return false; // Deny everything!!
00573 
00574     return true;
00575 }
00576 
00577 // not static because it uses m_twoLevelTLD
00578 void KCookieJar::extractDomains(const QString &_fqdn,
00579                                 QStringList &_domains) const
00580 {
00581     if (_fqdn.isEmpty()) {
00582         _domains.append( L1("localhost") );
00583         return;
00584     }
00585 
00586     // Return numeric IPv6 addresses as is...
00587     if (_fqdn[0] == '[')
00588     {
00589        _domains.append( _fqdn );
00590        return;
00591     }
00592     // Return numeric IPv4 addresses as is...
00593     if ((_fqdn[0] >= '0') && (_fqdn[0] <= '9'))
00594     {
00595        if (_fqdn.indexOf(QRegExp(IP_ADDRESS_EXPRESSION)) > -1)
00596        {
00597           _domains.append( _fqdn );
00598           return;
00599        }
00600     }
00601 
00602     QStringList partList = _fqdn.split('.', QString::SkipEmptyParts);
00603 
00604     if (partList.count())
00605         partList.erase(partList.begin()); // Remove hostname
00606 
00607     while(partList.count())
00608     {
00609 
00610        if (partList.count() == 1)
00611          break; // We only have a TLD left.
00612 
00613        if ((partList.count() == 2) && (m_twoLevelTLD.value(partList[1].toLower(), 0) == 1))
00614        {
00615           // This domain uses two-level TLDs in the form xxxx.yy
00616           break;
00617        }
00618 
00619        if ((partList.count() == 2) && (partList[1].length() == 2))
00620        {
00621           // If this is a TLD, we should stop. (e.g. co.uk)
00622           // We assume this is a TLD if it ends with .xx.yy or .x.yy
00623           if (partList[0].length() <= 2)
00624              break; // This is a TLD.
00625 
00626           // Catch some TLDs that we miss with the previous check
00627           // e.g. com.au, org.uk, mil.co
00628           const QString t = partList[0].toLower();
00629           if ((t == "com") || (t == "net") || (t == "org") || (t == "gov") || (t == "edu") || (t == "mil") || (t == "int"))
00630               break;
00631        }
00632 
00633        QString domain = partList.join(L1("."));
00634        _domains.append(domain);
00635        _domains.append('.' + domain);
00636        partList.erase(partList.begin()); // Remove part
00637     }
00638 
00639     // Always add the FQDN at the start of the list for
00640     // hostname == cookie-domainname checks!
00641     _domains.prepend( '.' + _fqdn );
00642     _domains.prepend( _fqdn );
00643 }
00644 
00645 /*
00646    Changes dates in from the following format
00647 
00648       Wed Sep 12 07:00:00 2007 GMT
00649    to
00650       Wed Sep 12 2007 07:00:00 GMT
00651 
00652    to allow KDateTime::fromString to properly parse expiration date formats
00653    used in cookies by some servers such as amazon.com. See BR# 145244.
00654 */
00655 static QString fixupDateTime(const QString& date)
00656 {
00657   QStringList list = date.split(' ');
00658   const int index = list.indexOf(QRegExp("[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}"));
00659 
00660   if (index > -1 && (index+1) < list.count())
00661   {
00662     list.insert(index+1, list.takeAt(index));
00663     return list.join(" ");
00664   }
00665 
00666   return date;
00667 }
00668 
00669 //
00670 // This function parses cookie_headers and returns a linked list of
00671 // KHttpCookie objects for all cookies found in cookie_headers.
00672 // If no cookies could be found 0 is returned.
00673 //
00674 // cookie_headers should be a concatenation of all lines of a HTTP-header
00675 // which start with "Set-Cookie". The lines should be separated by '\n's.
00676 //
00677 KHttpCookieList KCookieJar::makeCookies(const QString &_url,
00678                                        const QByteArray &cookie_headers,
00679                                        long windowId)
00680 {
00681     KHttpCookieList cookieList;
00682     KHttpCookieList cookieList2;
00683     KHttpCookieList::iterator lastCookie = cookieList.end();
00684     const char *cookieStr = cookie_headers.data();
00685     QString Name;
00686     QString Value;
00687     QString fqdn;
00688     QString path;
00689     bool crossDomain = false;
00690 
00691     if (!parseUrl(_url, fqdn, path))
00692     {
00693         // Error parsing _url
00694         return KHttpCookieList();
00695     }
00696     QString defaultPath;
00697     int i = path.lastIndexOf('/');
00698     if (i > 0)
00699        defaultPath = path.left(i);
00700 
00701     //  The hard stuff :)
00702     for(;;)
00703     {
00704         // check for "Set-Cookie"
00705         if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0)
00706         {
00707             cookieStr += 13;
00708             crossDomain = true;
00709         }
00710         else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0)
00711         {
00712             cookieStr = parseNameValue(cookieStr+11, Name, Value, true);
00713 
00714             // Host = FQDN
00715             // Default domain = ""
00716             // Default path according to rfc2109
00717 
00718             KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00719             if (windowId)
00720                cookie.mWindowIds.append(windowId);
00721             cookie.mCrossDomain = crossDomain;
00722 
00723             // Insert cookie in chain
00724             cookieList.append(cookie);
00725             lastCookie = cookieList.end(); --lastCookie;
00726         }
00727         else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0)
00728         {
00729             // Attempt to follow rfc2965
00730             cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true);
00731 
00732             // Host = FQDN
00733             // Default domain = ""
00734             // Default path according to rfc2965
00735 
00736             KHttpCookie cookie(fqdn, L1(""), defaultPath, Name, Value);
00737             if (windowId)
00738                cookie.mWindowIds.append(windowId);
00739             cookie.mCrossDomain = crossDomain;
00740 
00741             // Insert cookie in chain
00742             cookieList2.append(cookie);
00743             lastCookie = cookieList2.end(); --lastCookie;
00744         }
00745         else
00746         {
00747             // This is not the start of a cookie header, skip till next line.
00748             while (*cookieStr && *cookieStr != '\n')
00749                 cookieStr++;
00750 
00751             if (*cookieStr == '\n')
00752                 cookieStr++;
00753 
00754             if (!*cookieStr)
00755                 break; // End of cookie_headers
00756             else
00757                 continue; // end of this header, continue with next.
00758         }
00759 
00760         while ((*cookieStr == ';') || (*cookieStr == ' '))
00761         {
00762             cookieStr++;
00763 
00764             // Name-Value pair follows
00765             cookieStr = parseNameValue(cookieStr, Name, Value);
00766 
00767             QString cName = Name.toLower();
00768             if (cName == "domain")
00769             {
00770                 QString dom = Value.toLower();
00771                 // RFC2965 3.2.2: If an explicitly specified value does not
00772                 // start with a dot, the user agent supplies a leading dot
00773                 if(dom.length() && dom[0] != '.')
00774                     dom.prepend(".");
00775                 // remove a trailing dot
00776                 if(dom.length() > 2 && dom[dom.length()-1] == '.')
00777                     dom = dom.left(dom.length()-1);
00778 
00779                 if(dom.count('.') > 1 || dom == ".local")
00780                     lastCookie->mDomain = dom;
00781             }
00782             else if (cName == "max-age")
00783             {
00784                 int max_age = Value.toInt();
00785                 if (max_age == 0)
00786                     lastCookie->mExpireDate = 1;
00787                 else
00788                     lastCookie->mExpireDate = time(0)+max_age;
00789             }
00790             else if (cName == "expires")
00791             {
00792                 // Parse brain-dead netscape cookie-format
00793                 lastCookie->mExpireDate = KDateTime::fromString(Value, KDateTime::RFCDate).toTime_t();
00794 
00795                 // Workaround for servers that send the expiration date in
00796                 // 'Wed Sep 12 07:00:00 2007 GMT' format. See BR# 145244.
00797                 if (lastCookie->mExpireDate == -1)
00798                   lastCookie->mExpireDate = KDateTime::fromString(fixupDateTime(Value), KDateTime::RFCDate).toTime_t();
00799 
00800                 // We encode parse error/invalid as 0, but KDateTime likes -1, so convert
00801                 if (lastCookie->mExpireDate == -1)
00802                   lastCookie->mExpireDate = 0;
00803             }
00804             else if (cName == "path")
00805             {
00806                 if (Value.isEmpty())
00807                    lastCookie->mPath.clear(); // Catch "" <> QString()
00808                 else
00809                    lastCookie->mPath = QUrl::fromPercentEncoding(Value.toLatin1());
00810                 lastCookie->mExplicitPath = true;
00811             }
00812             else if (cName == "version")
00813             {
00814                 lastCookie->mProtocolVersion = Value.toInt();
00815             }
00816             else if ((cName == "secure") ||
00817                      (cName.isEmpty() && Value.toLower() == L1("secure")))
00818             {
00819                 lastCookie->mSecure = true;
00820             }
00821             else if ((cName == "httponly") ||
00822                      (cName.isEmpty() && Value.toLower() == L1("httponly")))
00823             {
00824                 lastCookie->mHttpOnly = true;
00825             }
00826         }
00827 
00828         if (*cookieStr == '\0')
00829             break; // End of header
00830 
00831         // Skip ';' or '\n'
00832         cookieStr++;
00833     }
00834 
00835     // RFC2965 cookies come last so that they override netscape cookies.
00836     while(!cookieList2.isEmpty()) {
00837         lastCookie = cookieList2.begin();
00838         removeDuplicateFromList(&cookieList, *lastCookie, true);
00839         cookieList.append(*lastCookie);
00840         cookieList2.removeFirst();
00841     }
00842 
00843     return cookieList;
00844 }
00845 
00852 KHttpCookieList KCookieJar::makeDOMCookies(const QString &_url,
00853                                            const QByteArray &cookie_domstring,
00854                                            long windowId)
00855 {
00856     // A lot copied from above
00857     KHttpCookieList cookieList;
00858 
00859     const char *cookieStr = cookie_domstring.data();
00860     QString fqdn;
00861     QString path;
00862 
00863     if (!parseUrl(_url, fqdn, path))
00864     {
00865         // Error parsing _url
00866         return KHttpCookieList();
00867     }
00868 
00869     QString Name;
00870     QString Value;
00871     //  This time it's easy
00872     while(*cookieStr)
00873     {
00874         cookieStr = parseNameValue(cookieStr, Name, Value);
00875 
00876         // Host = FQDN
00877         // Default domain = ""
00878         // Default path = ""
00879         KHttpCookie cookie(fqdn, QString(), QString(),
00880                            Name, Value );
00881         if (windowId)
00882             cookie.mWindowIds.append(windowId);
00883 
00884         cookieList.append(cookie);
00885 
00886         if (*cookieStr != '\0')
00887             cookieStr++;         // Skip ';' or '\n'
00888     }
00889 
00890     return cookieList;
00891 }
00892 
00893 // KHttpCookieList sorting
00895 
00896 // We want the longest path first
00897 static bool compareCookies(const KHttpCookie& item1, const KHttpCookie& item2)
00898 {
00899     return item1.path().length() > item2.path().length();
00900 }
00901 
00902 
00903 #ifdef MAX_COOKIE_LIMIT
00904 static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr)
00905 {
00906      // Too many cookies: throw one away, try to be somewhat clever
00907      KHttpCookiePtr lastCookie = 0;
00908      for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
00909      {
00910          if (compareCookies(cookie, cookiePtr))
00911             break;
00912          lastCookie = cookie;
00913      }
00914      if (!lastCookie)
00915          lastCookie = cookieList->first();
00916      cookieList->removeRef(lastCookie);
00917 }
00918 #endif
00919 
00920 //
00921 // This function hands a KHttpCookie object over to the cookie jar.
00922 //
00923 void KCookieJar::addCookie(KHttpCookie &cookie)
00924 {
00925     QStringList domains;
00926     KHttpCookieList *cookieList = 0L;
00927 
00928     // We always need to do this to make sure that the
00929     // that cookies of type hostname == cookie-domainname
00930     // are properly removed and/or updated as necessary!
00931     extractDomains( cookie.host(), domains );
00932     for ( QStringList::ConstIterator it = domains.constBegin();
00933           (it != domains.constEnd() && !cookieList);
00934           ++it )
00935     {
00936         QString key = (*it).isNull() ? QString::fromLatin1("") : (*it);
00937         KHttpCookieList *list= m_cookieDomains.value(key);
00938         if ( !list ) continue;
00939 
00940         removeDuplicateFromList(list, cookie, false, true);
00941     }
00942 
00943     QString domain = stripDomain( cookie );
00944     QString key = domain.isNull() ? QString::fromLatin1("") : domain;
00945     cookieList = m_cookieDomains.value(key);
00946     if (!cookieList)
00947     {
00948         // Make a new cookie list
00949         cookieList = new KHttpCookieList();
00950 
00951         // All cookies whose domain is not already
00952         // known to us should be added with KCookieDunno.
00953         // KCookieDunno means that we use the global policy.
00954         cookieList->setAdvice( KCookieDunno );
00955 
00956         m_cookieDomains.insert( domain, cookieList);
00957 
00958         // Update the list of domains
00959         m_domainList.append(domain);
00960     }
00961 
00962     // Add the cookie to the cookie list
00963     // The cookie list is sorted 'longest path first'
00964     if (!cookie.isExpired(time(0)))
00965     {
00966 #ifdef MAX_COOKIE_LIMIT
00967         if (cookieList->count() >= MAX_COOKIES_PER_HOST)
00968            makeRoom(cookieList, cookie); // Delete a cookie
00969 #endif
00970         cookieList->push_back(cookie);
00971         // Use a stable sort so that unit tests are reliable.
00972         // In practice it doesn't matter though.
00973         qStableSort(cookieList->begin(), cookieList->end(), compareCookies);
00974 
00975         m_cookiesChanged = true;
00976     }
00977 }
00978 
00979 //
00980 // This function advices whether a single KHttpCookie object should
00981 // be added to the cookie jar.
00982 //
00983 KCookieAdvice KCookieJar::cookieAdvice(KHttpCookie& cookie)
00984 {
00985     if (m_rejectCrossDomainCookies && cookie.isCrossDomain())
00986        return KCookieReject;
00987 
00988     QStringList domains;
00989     extractDomains(cookie.host(), domains);
00990 
00991     // If the cookie specifies a domain, check whether it is valid. Otherwise,
00992     // accept the cookie anyways but removes the domain="" value to prevent
00993     // cross-site cookie injection.
00994     if (!cookie.domain().isEmpty())
00995     {
00996       if (!domains.contains(cookie.domain()) &&
00997           !cookie.domain().endsWith('.'+cookie.host()))
00998          cookie.fixDomain(QString());
00999     }
01000 
01001     if (m_autoAcceptSessionCookies && (cookie.expireDate() == 0 ||
01002         m_ignoreCookieExpirationDate))
01003        return KCookieAccept;
01004 
01005     KCookieAdvice advice = KCookieDunno;
01006     bool isFQDN = true; // First is FQDN
01007     QStringList::Iterator it = domains.begin(); // Start with FQDN which first in the list.
01008     while( (advice == KCookieDunno) && (it != domains.end()))
01009     {
01010        QString domain = *it;
01011        // Check if a policy for the FQDN/domain is set.
01012        if ( domain.startsWith('.') || isFQDN )
01013        {
01014           isFQDN = false;
01015           KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01016           if (cookieList)
01017              advice = cookieList->getAdvice();
01018        }
01019        domains.erase(it);
01020        it = domains.begin(); // Continue from begin of remaining list
01021     }
01022 
01023     if (advice == KCookieDunno)
01024         advice = m_globalAdvice;
01025 
01026     return advice;
01027 }
01028 
01029 //
01030 // This function gets the advice for all cookies originating from
01031 // _domain.
01032 //
01033 KCookieAdvice KCookieJar::getDomainAdvice(const QString &_domain)
01034 {
01035     KHttpCookieList *cookieList = m_cookieDomains.value(_domain);
01036     KCookieAdvice advice;
01037 
01038     if (cookieList)
01039     {
01040         advice = cookieList->getAdvice();
01041     }
01042     else
01043     {
01044         advice = KCookieDunno;
01045     }
01046 
01047     return advice;
01048 }
01049 
01050 //
01051 // This function sets the advice for all cookies originating from
01052 // _domain.
01053 //
01054 void KCookieJar::setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
01055 {
01056     QString domain(_domain);
01057     KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01058 
01059     if (cookieList)
01060     {
01061         if (cookieList->getAdvice() != _advice)
01062         {
01063            m_configChanged = true;
01064            // domain is already known
01065            cookieList->setAdvice( _advice);
01066         }
01067 
01068         if ((cookieList->isEmpty()) &&
01069             (_advice == KCookieDunno))
01070         {
01071             // This deletes cookieList!
01072             delete m_cookieDomains.take(domain);
01073             m_domainList.removeAll(domain);
01074         }
01075     }
01076     else
01077     {
01078         // domain is not yet known
01079         if (_advice != KCookieDunno)
01080         {
01081             // We should create a domain entry
01082             m_configChanged = true;
01083             // Make a new cookie list
01084             cookieList = new KHttpCookieList();
01085             cookieList->setAdvice(_advice);
01086             m_cookieDomains.insert(domain, cookieList);
01087             // Update the list of domains
01088             m_domainList.append( domain);
01089         }
01090     }
01091 }
01092 
01093 //
01094 // This function sets the advice for all cookies originating from
01095 // the same domain as _cookie
01096 //
01097 void KCookieJar::setDomainAdvice(const KHttpCookie& cookie, KCookieAdvice _advice)
01098 {
01099     QString domain;
01100     stripDomain(cookie.host(), domain); // We file the cookie under this domain.
01101 
01102     setDomainAdvice(domain, _advice);
01103 }
01104 
01105 //
01106 // This function sets the global advice for cookies
01107 //
01108 void KCookieJar::setGlobalAdvice(KCookieAdvice _advice)
01109 {
01110     if (m_globalAdvice != _advice)
01111        m_configChanged = true;
01112     m_globalAdvice = _advice;
01113 }
01114 
01115 //
01116 // Get a list of all domains known to the cookie jar.
01117 //
01118 const QStringList& KCookieJar::getDomainList()
01119 {
01120     return m_domainList;
01121 }
01122 
01123 //
01124 // Get a list of all cookies in the cookie jar originating from _domain.
01125 //
01126 KHttpCookieList *KCookieJar::getCookieList(const QString & _domain,
01127                                            const QString & _fqdn )
01128 {
01129     QString domain;
01130 
01131     if (_domain.isEmpty())
01132         stripDomain(_fqdn, domain);
01133     else
01134         stripDomain (_domain, domain);
01135 
01136     return m_cookieDomains.value(domain);
01137 }
01138 
01139 //
01140 // Eat a cookie out of the jar.
01141 // cookieIterator should be one of the cookies returned by getCookieList()
01142 //
01143 void KCookieJar::eatCookie(KHttpCookieList::iterator cookieIterator)
01144 {
01145     const KHttpCookie& cookie = *cookieIterator;
01146     QString domain = stripDomain(cookie); // We file the cookie under this domain.
01147     KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01148 
01149     if (cookieList) {
01150         // This deletes cookie!
01151         cookieList->erase(cookieIterator);
01152 
01153         if ((cookieList->isEmpty()) &&
01154             (cookieList->getAdvice() == KCookieDunno))
01155         {
01156             // This deletes cookieList!
01157             delete m_cookieDomains.take(domain);
01158 
01159             m_domainList.removeAll(domain);
01160         }
01161     }
01162 }
01163 
01164 void KCookieJar::eatCookiesForDomain(const QString &domain)
01165 {
01166    KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01167    if (!cookieList || cookieList->isEmpty()) return;
01168 
01169    cookieList->clear();
01170    if (cookieList->getAdvice() == KCookieDunno)
01171    {
01172        // This deletes cookieList!
01173        delete m_cookieDomains.take(domain);
01174        m_domainList.removeAll(domain);
01175    }
01176    m_cookiesChanged = true;
01177 }
01178 
01179 void KCookieJar::eatSessionCookies( long windowId )
01180 {
01181     if (!windowId)
01182         return;
01183 
01184     QStringList::const_iterator it=m_domainList.constBegin();
01185     for ( ; it != m_domainList.constEnd(); ++it )
01186         eatSessionCookies( *it, windowId, false );
01187 }
01188 
01189 void KCookieJar::eatAllCookies()
01190 {
01191     Q_FOREACH(const QString& domain, m_domainList) {
01192         // This might remove domain from m_domainList!
01193         eatCookiesForDomain(domain);
01194     }
01195 }
01196 
01197 void KCookieJar::eatSessionCookies( const QString& fqdn, long windowId,
01198                                     bool isFQDN )
01199 {
01200     KHttpCookieList* cookieList;
01201     if ( !isFQDN )
01202         cookieList = m_cookieDomains.value(fqdn);
01203     else {
01204         QString domain;
01205         stripDomain( fqdn, domain );
01206         cookieList = m_cookieDomains.value(domain);
01207     }
01208 
01209     if (cookieList) {
01210         QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01211         while (cookieIterator.hasNext()) {
01212             KHttpCookie& cookie = cookieIterator.next();
01213             if ((cookie.expireDate() != 0) && !m_ignoreCookieExpirationDate) {
01214                continue;
01215             }
01216 
01217             QList<long> &ids = cookie.windowIds();
01218 
01219 #ifndef NDEBUG
01220             if (ids.contains(windowId)) {
01221                 if (ids.count() > 1)
01222                     kDebug() << "removing window id" << windowId << "from session cookie";
01223                 else
01224                     kDebug() << "deleting session cookie";
01225             }
01226 #endif
01227             if (!ids.removeAll(windowId) || !ids.isEmpty()) {
01228                continue;
01229             }
01230             cookieIterator.remove();
01231         }
01232     }
01233 }
01234 
01235 //
01236 // Saves all cookies to the file '_filename'.
01237 // On succes 'true' is returned.
01238 // On failure 'false' is returned.
01239 bool KCookieJar::saveCookies(const QString &_filename)
01240 {
01241     KSaveFile saveFile(_filename);
01242 
01243     if (!saveFile.open())
01244        return false;
01245     saveFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
01246 
01247     QTextStream ts(&saveFile);
01248 
01249     time_t curTime = time(0);
01250 
01251     ts << "# KDE Cookie File v2\n#\n";
01252 
01253     QString s;
01254     s.sprintf("%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n",
01255               "# Host", "Domain", "Path", "Exp.date", "Prot",
01256               "Name", "Sec", "Value");
01257     ts << s.toLatin1().constData();
01258 
01259     for ( QStringList::const_iterator it=m_domainList.constBegin(); it != m_domainList.constEnd();
01260           it++ )
01261     {
01262         const QString &domain = *it;
01263         bool domainPrinted = false;
01264 
01265         KHttpCookieList *cookieList = m_cookieDomains.value(domain);
01266         QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
01267         while (cookieIterator.hasNext()) {
01268             const KHttpCookie& cookie = cookieIterator.next();
01269             if (cookie.isExpired(curTime)) {
01270                 // Delete expired cookies
01271                 cookieIterator.remove();
01272             } else if (cookie.expireDate() != 0 && !m_ignoreCookieExpirationDate) {
01273                 // Only save cookies that are not "session-only cookies"
01274                 if (!domainPrinted) {
01275                     domainPrinted = true;
01276                     ts << '[' << domain.toLocal8Bit().data() << "]\n";
01277                 }
01278                 // Store persistent cookies
01279                 QString path = L1("\"");
01280                 path += cookie.path();
01281                 path += '"';
01282                 QString domain = L1("\"");
01283                 domain += cookie.domain();
01284                 domain += '"';
01285                 // TODO: replace with direct QTextStream output ?
01286                 s.sprintf("%-20s %-20s %-12s %10lu  %3d %-20s %-4i %s\n",
01287                         cookie.host().toLatin1().constData(), domain.toLatin1().constData(),
01288                         path.toLatin1().constData(), (unsigned long) cookie.expireDate(),
01289                         cookie.protocolVersion(),
01290                         cookie.name().isEmpty() ? cookie.value().toLatin1().constData() : cookie.name().toLatin1().constData(),
01291                         (cookie.isSecure() ? 1 : 0) + (cookie.isHttpOnly() ? 2 : 0) +
01292                         (cookie.hasExplicitPath() ? 4 : 0) + (cookie.name().isEmpty() ? 8 : 0),
01293                         cookie.value().toLatin1().constData());
01294                 ts << s.toLatin1().constData();
01295             }
01296         }
01297     }
01298 
01299     return saveFile.finalize();
01300 }
01301 
01302 static const char *parseField(char* &buffer, bool keepQuotes=false)
01303 {
01304     char *result;
01305     if (!keepQuotes && (*buffer == '\"'))
01306     {
01307         // Find terminating "
01308         buffer++;
01309         result = buffer;
01310         while((*buffer != '\"') && (*buffer))
01311             buffer++;
01312     }
01313     else
01314     {
01315         // Find first white space
01316         result = buffer;
01317         while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer))
01318             buffer++;
01319     }
01320 
01321     if (!*buffer)
01322         return result; //
01323     *buffer++ = '\0';
01324 
01325     // Skip white-space
01326     while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n'))
01327         buffer++;
01328 
01329     return result;
01330 }
01331 
01332 
01333 //
01334 // Reloads all cookies from the file '_filename'.
01335 // On succes 'true' is returned.
01336 // On failure 'false' is returned.
01337 bool KCookieJar::loadCookies(const QString &_filename)
01338 {
01339     FILE *fStream = fopen( QFile::encodeName(_filename), "r");
01340     if (fStream == 0)
01341     {
01342         return false;
01343     }
01344 
01345     time_t curTime = time(0);
01346 
01347     char *buffer = new char[READ_BUFFER_SIZE];
01348 
01349     bool err = false;
01350     err = (fgets(buffer, READ_BUFFER_SIZE, fStream) == 0);
01351 
01352     int version = 1;
01353     if (!err)
01354     {
01355         if (strcmp(buffer, "# KDE Cookie File\n") == 0)
01356         {
01357             // version 1
01358         }
01359         else if (sscanf(buffer, "# KDE Cookie File v%d\n", &version) != 1)
01360         {
01361             err = true;
01362         }
01363     }
01364 
01365     if (!err)
01366     {
01367         while(fgets(buffer, READ_BUFFER_SIZE, fStream) != 0)
01368         {
01369             char *line = buffer;
01370             // Skip lines which begin with '#' or '['
01371             if ((line[0] == '#') || (line[0] == '['))
01372                 continue;
01373 
01374             const QString host = QString::fromLatin1( parseField(line) );
01375             const QString domain = QString::fromLatin1( parseField(line) );
01376             if (host.isEmpty() && domain.isEmpty())
01377                 continue;
01378             const QString path = QString::fromLatin1( parseField(line) );
01379             const QString expStr = QString::fromLatin1( parseField(line) );
01380             if (expStr.isEmpty()) continue;
01381             const int expDate = expStr.toInt();
01382             const QString verStr = QString::fromLatin1( parseField(line) );
01383             if (verStr.isEmpty()) continue;
01384             int protVer  = verStr.toInt();
01385             QString name = QString::fromLatin1( parseField(line) );
01386             bool keepQuotes = false;
01387             bool secure = false;
01388             bool httpOnly = false;
01389             bool explicitPath = false;
01390             const char *value = 0;
01391             if ((version == 2) || (protVer >= 200))
01392             {
01393                 if (protVer >= 200)
01394                     protVer -= 200;
01395                 int i = atoi( parseField(line) );
01396                 secure = i & 1;
01397                 httpOnly = i & 2;
01398                 explicitPath = i & 4;
01399                 if (i & 8)
01400                     name = "";
01401                 line[strlen(line)-1] = '\0'; // Strip LF.
01402                 value = line;
01403             }
01404             else
01405             {
01406                 if (protVer >= 100)
01407                 {
01408                     protVer -= 100;
01409                     keepQuotes = true;
01410                 }
01411                 value = parseField(line, keepQuotes);
01412                 secure = atoi( parseField(line) );
01413             }
01414 
01415             // Parse error
01416             if (!value) continue;
01417 
01418             // Expired or parse error
01419             if ((expDate == 0) || (expDate < curTime))
01420                 continue;
01421 
01422             KHttpCookie cookie(host,
01423                                domain,
01424                                path,
01425                                name,
01426                                value,
01427                                expDate, protVer,
01428                                secure, httpOnly, explicitPath);
01429             addCookie(cookie);
01430         }
01431     }
01432     delete [] buffer;
01433     m_cookiesChanged = false;
01434 
01435     fclose( fStream);
01436     return err;
01437 }
01438 
01439 //
01440 // Save the cookie configuration
01441 //
01442 
01443 void KCookieJar::saveConfig(KConfig *_config)
01444 {
01445     if (!m_configChanged)
01446         return;
01447 
01448     KConfigGroup dlgGroup(_config, "Cookie Dialog");
01449     dlgGroup.writeEntry("PreferredPolicy", static_cast<int>(m_preferredPolicy));
01450     dlgGroup.writeEntry("ShowCookieDetails", m_showCookieDetails );
01451     KConfigGroup policyGroup(_config,"Cookie Policy");
01452     policyGroup.writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice));
01453 
01454     QStringList domainSettings;
01455     for ( QStringList::const_iterator it=m_domainList.constBegin();
01456           it != m_domainList.constEnd();
01457           ++it )
01458     {
01459          const QString &domain = *it;
01460          KCookieAdvice advice = getDomainAdvice( domain);
01461          if (advice != KCookieDunno)
01462          {
01463              QString value(domain);
01464              value += ':';
01465              value += adviceToStr(advice);
01466              domainSettings.append(value);
01467          }
01468     }
01469     policyGroup.writeEntry("CookieDomainAdvice", domainSettings);
01470     _config->sync();
01471     m_configChanged = false;
01472 }
01473 
01474 
01475 //
01476 // Load the cookie configuration
01477 //
01478 
01479 void KCookieJar::loadConfig(KConfig *_config, bool reparse )
01480 {
01481     if ( reparse )
01482         _config->reparseConfiguration();
01483 
01484     KConfigGroup dlgGroup(_config, "Cookie Dialog");
01485     m_showCookieDetails = dlgGroup.readEntry( "ShowCookieDetails" , false );
01486     m_preferredPolicy = static_cast<KCookieDefaultPolicy>(dlgGroup.readEntry("PreferredPolicy", 0));
01487 
01488     KConfigGroup policyGroup(_config,"Cookie Policy");
01489     const QStringList domainSettings = policyGroup.readEntry("CookieDomainAdvice", QStringList());
01490     // Warning: those default values are duplicated in the kcm (kio/kcookiespolicies.cpp)
01491     m_rejectCrossDomainCookies = policyGroup.readEntry("RejectCrossDomainCookies", true);
01492     m_autoAcceptSessionCookies = policyGroup.readEntry("AcceptSessionCookies", true);
01493     m_ignoreCookieExpirationDate = policyGroup.readEntry("IgnoreExpirationDate", false);
01494     QString value = policyGroup.readEntry("CookieGlobalAdvice", QString::fromLatin1("Accept"));
01495     m_globalAdvice = strToAdvice(value);
01496 
01497     // Reset current domain settings first.
01498     //  (must make a copy because setDomainAdvice() might delete the domain from m_domainList inside the for loop)
01499     const QStringList domains = m_domainList;
01500     Q_FOREACH( const QString &domain, domains )
01501     {
01502          setDomainAdvice(domain, KCookieDunno);
01503     }
01504 
01505     // Now apply the domain settings read from config file...
01506     for ( QStringList::const_iterator it=domainSettings.begin();
01507           it != domainSettings.end(); )
01508     {
01509         const QString &value = *it++;
01510 
01511         int sepPos = value.lastIndexOf(':');
01512 
01513         if (sepPos <= 0)
01514           continue;
01515 
01516         QString domain(value.left(sepPos));
01517         KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) );
01518         setDomainAdvice(domain, advice);
01519     }
01520 }
01521 
01522 QDebug operator<<(QDebug dbg, const KHttpCookie& cookie)
01523 {
01524     dbg.nospace() << cookie.cookieStr(false);
01525     return dbg.space();
01526 }
01527 
01528 QDebug operator<<(QDebug dbg, const KHttpCookieList& list)
01529 {
01530     Q_FOREACH(const KHttpCookie& cookie, list)
01531         dbg << cookie;
01532     return dbg;
01533 }

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