• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

KIOSlave

  • kioslave
  • http
  • kcookiejar
kcookiejar.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE File Manager
2 
3  Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org)
4  Copyright (C) 2000,2001 Dawit Alemayehu (adawit@kde.org)
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, and/or sell copies of the
10  Software, and to permit persons to whom the Software is furnished to do so,
11  subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 //----------------------------------------------------------------------------
24 //
25 // KDE File Manager -- HTTP Cookies
26 
27 //
28 // The cookie protocol is a mess. RFC2109 is a joke since nobody seems to
29 // use it. Apart from that it is badly written.
30 // We try to implement Netscape Cookies and try to behave us according to
31 // RFC2109 as much as we can.
32 //
33 // We assume cookies do not contain any spaces (Netscape spec.)
34 // According to RFC2109 this is allowed though.
35 //
36 
37 #include "kcookiejar.h"
38 
39 #include <kurl.h>
40 #include <kdatetime.h>
41 #include <ksystemtimezone.h>
42 #include <kconfig.h>
43 #include <kconfiggroup.h>
44 #include <ksavefile.h>
45 #include <kdebug.h>
46 
47 #include <QtCore/QString>
48 #include <QtCore/QFile>
49 #include <QtCore/QDir>
50 #include <QtCore/QRegExp>
51 #include <QtCore/QTextStream>
52 
53 // BR87227
54 // Waba: Should the number of cookies be limited?
55 // I am not convinced of the need of such limit
56 // Mozilla seems to limit to 20 cookies / domain
57 // but it is unclear which policy it uses to expire
58 // cookies when it exceeds that amount
59 #undef MAX_COOKIE_LIMIT
60 
61 #define MAX_COOKIES_PER_HOST 25
62 #define READ_BUFFER_SIZE 8192
63 #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]?)"
64 
65 // Note with respect to QLatin1String( )....
66 // Cookies are stored as 8 bit data and passed to kio_http as Latin1
67 // regardless of their actual encoding.
68 #define QL1S(x) QLatin1String(x)
69 #define QL1C(x) QLatin1Char(x)
70 
71 
72 static KDateTime parseDate(const QString& value)
73 {
74  KTimeZones *zones = KSystemTimeZones::timeZones();
75  // Check for the most common cookie expire date format: Thu, 01-Jan-1970 00:00:00 GMT
76  KDateTime dt = KDateTime::fromString(value, QL1S("%:A,%t%d-%:B-%Y%t%H:%M:%S%t%Z"), zones);
77  if (dt.isValid())
78  return dt;
79 
80  // Check for incorrect formats (amazon.com): Thu Jan 01 1970 00:00:00 GMT
81  dt = KDateTime::fromString(value, QL1S("%:A%t%:B%t%d%t%Y%t%H:%M:%S%t%Z"), zones);
82  if (dt.isValid())
83  return dt;
84 
85  // Check for a variation of the above format: Thu Jan 01 00:00:00 1970 GMT (BR# 145244)
86  dt = KDateTime::fromString(value, QL1S("%:A%t%:B%t%d%t%H:%M:%S%t%Y%t%Z"), zones);
87  if (dt.isValid())
88  return dt;
89 
90  // Finally we try the RFC date formats as last resort
91  return KDateTime::fromString(value, KDateTime::RFCDate);
92 }
93 
94 static qint64 epoch()
95 {
96  KDateTime epoch;
97  epoch.setTime_t(0);
98  return epoch.secsTo_long(KDateTime::currentUtcDateTime());
99 }
100 
101 
102 QString KCookieJar::adviceToStr(KCookieAdvice _advice)
103 {
104  switch( _advice )
105  {
106  case KCookieAccept: return QL1S("Accept");
107  case KCookieReject: return QL1S("Reject");
108  case KCookieAsk: return QL1S("Ask");
109  default: return QL1S("Dunno");
110  }
111 }
112 
113 KCookieAdvice KCookieJar::strToAdvice(const QString &_str)
114 {
115  if (_str.isEmpty())
116  return KCookieDunno;
117 
118  QString advice = _str.toLower();
119 
120  if (advice == QL1S("accept"))
121  return KCookieAccept;
122  else if (advice == QL1S("reject"))
123  return KCookieReject;
124  else if (advice == QL1S("ask"))
125  return KCookieAsk;
126 
127  return KCookieDunno;
128 }
129 
130 // KHttpCookie
132 
133 //
134 // Cookie constructor
135 //
136 KHttpCookie::KHttpCookie(const QString &_host,
137  const QString &_domain,
138  const QString &_path,
139  const QString &_name,
140  const QString &_value,
141  qint64 _expireDate,
142  int _protocolVersion,
143  bool _secure,
144  bool _httpOnly,
145  bool _explicitPath) :
146  mHost(_host),
147  mDomain(_domain),
148  mPath(_path.isEmpty() ? QString() : _path),
149  mName(_name),
150  mValue(_value),
151  mExpireDate(_expireDate),
152  mProtocolVersion(_protocolVersion),
153  mSecure(_secure),
154  mHttpOnly(_httpOnly),
155  mExplicitPath(_explicitPath)
156 {
157 }
158 
159 //
160 // Checks if a cookie has been expired
161 //
162 bool KHttpCookie::isExpired(qint64 currentDate) const
163 {
164  if (currentDate == -1)
165  currentDate = epoch();
166 
167  return (mExpireDate != 0) && (mExpireDate < currentDate);
168 }
169 
170 //
171 // Returns a string for a HTTP-header
172 //
173 QString KHttpCookie::cookieStr(bool useDOMFormat) const
174 {
175  QString result;
176 
177  if (useDOMFormat || (mProtocolVersion == 0)) {
178  if ( mName.isEmpty() )
179  result = mValue;
180  else
181  result = mName + QL1C('=') + mValue;
182  } else {
183  result = mName + QL1C('=') + mValue;
184  if (mExplicitPath)
185  result += QL1S("; $Path=\"") + mPath + QL1C('"');
186  if (!mDomain.isEmpty())
187  result += QL1S("; $Domain=\"") + mDomain + QL1C('"');
188  if (!mPorts.isEmpty()) {
189  if (mPorts.length() == 2 && mPorts.at(0) == -1)
190  result += QL1S("; $Port");
191  else {
192  QString portNums;
193  Q_FOREACH(int port, mPorts)
194  portNums += QString::number(port) + QL1C(' ');
195  result += QL1S("; $Port=\"") + portNums.trimmed() + QL1C('"');
196  }
197  }
198  }
199  return result;
200 }
201 
202 //
203 // Returns whether this cookie should be send to this location.
204 bool KHttpCookie::match(const QString &fqdn, const QStringList &domains,
205  const QString &path, int port) const
206 {
207  // Cookie domain match check
208  if (mDomain.isEmpty())
209  {
210  if (fqdn != mHost)
211  return false;
212  }
213  else if (!domains.contains(mDomain))
214  {
215  if (mDomain[0] == '.')
216  return false;
217 
218  // Maybe the domain needs an extra dot.
219  const QString domain = QL1C('.') + mDomain;
220  if ( !domains.contains( domain ) )
221  if ( fqdn != mDomain )
222  return false;
223  }
224  else if (mProtocolVersion != 0 && port != -1 &&
225  !mPorts.isEmpty() && !mPorts.contains(port))
226  {
227  return false;
228  }
229 
230  // Cookie path match check
231  if (mPath.isEmpty())
232  return true;
233 
234  // According to the netscape spec http://www.acme.com/foobar,
235  // http://www.acme.com/foo.bar and http://www.acme.com/foo/bar
236  // should all match http://www.acme.com/foo...
237  // We only match http://www.acme.com/foo/bar
238  if( path.startsWith(mPath) &&
239  (
240  (path.length() == mPath.length() ) || // Paths are exact match
241  mPath.endsWith(QL1C('/')) || // mPath ended with a slash
242  (path[mPath.length()] == QL1C('/')) // A slash follows
243  ))
244  return true; // Path of URL starts with cookie-path
245 
246  return false;
247 }
248 
249 // KCookieJar
251 
252 //
253 // Constructs a new cookie jar
254 //
255 // One jar should be enough for all cookies.
256 //
257 KCookieJar::KCookieJar()
258 {
259  m_globalAdvice = KCookieDunno;
260  m_configChanged = false;
261  m_cookiesChanged = false;
262 
263  KConfig cfg( "khtml/domain_info", KConfig::NoGlobals, "data" );
264  KConfigGroup group( &cfg, QString() );
265  m_gTLDs = QSet<QString>::fromList(group.readEntry("gTLDs", QStringList()));
266  m_twoLevelTLD = QSet<QString>::fromList(group.readEntry("twoLevelTLD", QStringList()));
267 }
268 
269 //
270 // Destructs the cookie jar
271 //
272 // Poor little cookies, they will all be eaten by the cookie monster!
273 //
274 KCookieJar::~KCookieJar()
275 {
276  qDeleteAll(m_cookieDomains);
277  // Not much to do here
278 }
279 
280 // cookiePtr is modified: the window ids of the existing cookie in the list are added to it
281 static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie& cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false)
282 {
283  QString domain1 = cookiePtr.domain();
284  if (domain1.isEmpty())
285  domain1 = cookiePtr.host();
286 
287  QMutableListIterator<KHttpCookie> cookieIterator(*list);
288  while (cookieIterator.hasNext()) {
289  const KHttpCookie& cookie = cookieIterator.next();
290  QString domain2 = cookie.domain();
291  if (domain2.isEmpty())
292  domain2 = cookie.host();
293 
294  if (cookiePtr.name() == cookie.name() &&
295  (nameMatchOnly || (domain1 == domain2 && cookiePtr.path() == cookie.path())))
296  {
297  if (updateWindowId) {
298  Q_FOREACH(long windowId, cookie.windowIds()) {
299  if (windowId && (!cookiePtr.windowIds().contains(windowId))) {
300  cookiePtr.windowIds().append(windowId);
301  }
302  }
303  }
304  cookieIterator.remove();
305  break;
306  }
307  }
308 }
309 
310 
311 //
312 // Looks for cookies in the cookie jar which are appropriate for _url.
313 // Returned is a string containing all appropriate cookies in a format
314 // which can be added to a HTTP-header without any additional processing.
315 //
316 QString KCookieJar::findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies)
317 {
318  QString cookieStr, fqdn, path;
319  QStringList domains;
320  int port = -1;
321  KCookieAdvice advice = m_globalAdvice;
322 
323  if (!parseUrl(_url, fqdn, path, &port))
324  return cookieStr;
325 
326  const bool secureRequest = (_url.startsWith(QL1S("https://"), Qt::CaseInsensitive) ||
327  _url.startsWith(QL1S("webdavs://"), Qt::CaseInsensitive));
328  if (port == -1)
329  port = (secureRequest ? 443 : 80);
330 
331  extractDomains(fqdn, domains);
332 
333  KHttpCookieList allCookies;
334  for (QStringList::ConstIterator it = domains.constBegin(), itEnd = domains.constEnd();;++it)
335  {
336  KHttpCookieList *cookieList = 0;
337  if (it == itEnd)
338  {
339  cookieList = pendingCookies; // Add pending cookies
340  pendingCookies = 0;
341  if (!cookieList)
342  break;
343  }
344  else
345  {
346  if ((*it).isNull())
347  cookieList = m_cookieDomains.value(QL1S(""));
348  else
349  cookieList = m_cookieDomains.value(*it);
350 
351  if (!cookieList)
352  continue; // No cookies for this domain
353  }
354 
355  if (cookieList->getAdvice() != KCookieDunno)
356  advice = cookieList->getAdvice();
357 
358  QMutableListIterator<KHttpCookie> cookieIt (*cookieList);
359  while (cookieIt.hasNext())
360  {
361  KHttpCookie& cookie = cookieIt.next();
362  // If the we are setup to automatically accept all session cookies and to
363  // treat all cookies as session cookies or the current cookie is a session
364  // cookie, then send the cookie back regardless of domain policy.
365  if (advice == KCookieReject &&
366  !(m_autoAcceptSessionCookies &&
367  (m_ignoreCookieExpirationDate || cookie.expireDate() == 0)))
368  continue;
369 
370  if (!cookie.match(fqdn, domains, path, port))
371  continue;
372 
373  if( cookie.isSecure() && !secureRequest )
374  continue;
375 
376  if( cookie.isHttpOnly() && useDOMFormat )
377  continue;
378 
379  // Do not send expired cookies.
380  if ( cookie.isExpired())
381  {
382  // NOTE: there is no need to delete the cookie here because the
383  // cookieserver will invoke its saveCookieJar function as a result
384  // of the state change below. This will then result in the cookie
385  // being deleting at that point.
386  m_cookiesChanged = true;
387  continue;
388  }
389 
390  if (windowId && (cookie.windowIds().indexOf(windowId) == -1))
391  cookie.windowIds().append(windowId);
392 
393  if (it == itEnd) // Only needed when processing pending cookies
394  removeDuplicateFromList(&allCookies, cookie);
395 
396  allCookies.append(cookie);
397  }
398 
399  if (it == itEnd)
400  break; // Finished.
401  }
402 
403  int protVersion = 0;
404  Q_FOREACH(const KHttpCookie& cookie, allCookies) {
405  if (cookie.protocolVersion() > protVersion)
406  protVersion = cookie.protocolVersion();
407  }
408 
409  if (!allCookies.isEmpty())
410  {
411  if (!useDOMFormat)
412  cookieStr = QL1S("Cookie: ");
413 
414  if (protVersion > 0)
415  cookieStr = cookieStr + QL1S("$Version=") + QString::number(protVersion) + QL1S("; ");
416 
417  Q_FOREACH(const KHttpCookie& cookie, allCookies)
418  cookieStr = cookieStr + cookie.cookieStr(useDOMFormat) + QL1S("; ");
419 
420  cookieStr.truncate(cookieStr.length() - 2); // Remove the trailing ';'
421  }
422 
423  return cookieStr;
424 }
425 
426 //
427 // This function parses a string like 'my_name="my_value";' and returns
428 // 'my_name' in Name and 'my_value' in Value.
429 //
430 // A pointer to the end of the parsed part is returned.
431 // This pointer points either to:
432 // '\0' - The end of the string has reached.
433 // ';' - Another my_name="my_value" pair follows
434 // ',' - Another cookie follows
435 // '\n' - Another header follows
436 static const char * parseNameValue(const char *header,
437  QString &Name,
438  QString &Value,
439  bool keepQuotes=false,
440  bool rfcQuotes=false)
441 {
442  const char *s = header;
443  // Parse 'my_name' part
444  for(; (*s != '='); s++)
445  {
446  if ((*s=='\0') || (*s==';') || (*s=='\n'))
447  {
448  // No '=' sign -> use string as the value, name is empty
449  // (behavior found in Mozilla and IE)
450  Name = QL1S("");
451  Value = QL1S(header);
452  Value.truncate( s - header );
453  Value = Value.trimmed();
454  return s;
455  }
456  }
457 
458  Name = QL1S(header);
459  Name.truncate( s - header );
460  Name = Name.trimmed();
461 
462  // *s == '='
463  s++;
464 
465  // Skip any whitespace
466  for(; (*s == ' ') || (*s == '\t'); s++)
467  {
468  if ((*s=='\0') || (*s==';') || (*s=='\n'))
469  {
470  // End of Name
471  Value = "";
472  return s;
473  }
474  }
475 
476  if ((rfcQuotes || !keepQuotes) && (*s == '\"'))
477  {
478  // Parse '"my_value"' part (quoted value)
479  if (keepQuotes)
480  header = s++;
481  else
482  header = ++s; // skip "
483  for(;(*s != '\"');s++)
484  {
485  if ((*s=='\0') || (*s=='\n'))
486  {
487  // End of Name
488  Value = QL1S(header);
489  Value.truncate(s - header);
490  return s;
491  }
492  }
493  Value = QL1S(header);
494  // *s == '\"';
495  if (keepQuotes)
496  Value.truncate( ++s - header );
497  else
498  Value.truncate( s++ - header );
499 
500  // Skip any remaining garbage
501  for(;; s++)
502  {
503  if ((*s=='\0') || (*s==';') || (*s=='\n'))
504  break;
505  }
506  }
507  else
508  {
509  // Parse 'my_value' part (unquoted value)
510  header = s;
511  while ((*s != '\0') && (*s != ';') && (*s != '\n'))
512  s++;
513  // End of Name
514  Value = QL1S(header);
515  Value.truncate( s - header );
516  Value = Value.trimmed();
517  }
518  return s;
519 
520 }
521 
522 void KCookieJar::stripDomain(const QString &_fqdn, QString &_domain)
523 {
524  QStringList domains;
525  extractDomains(_fqdn, domains);
526  if (domains.count() > 3)
527  _domain = domains[3];
528  else if ( domains.count() > 0 )
529  _domain = domains[0];
530  else
531  _domain = QL1S("");
532 }
533 
534 QString KCookieJar::stripDomain(const KHttpCookie& cookie)
535 {
536  QString domain; // We file the cookie under this domain.
537  if (cookie.domain().isEmpty())
538  stripDomain( cookie.host(), domain);
539  else
540  domain = cookie.domain();
541  return domain;
542 }
543 
544 bool KCookieJar::parseUrl(const QString &_url,
545  QString &_fqdn,
546  QString &_path,
547  int *port)
548 {
549  KUrl kurl(_url);
550  if (!kurl.isValid() || kurl.protocol().isEmpty())
551  return false;
552 
553  _fqdn = kurl.host().toLower();
554  // Cookie spoofing protection. Since there is no way a path separator,
555  // a space or the escape encoding character is allowed in the hostname
556  // according to RFC 2396, reject attempts to include such things there!
557  if (_fqdn.contains(QL1C('/')) || _fqdn.contains(QL1C('%')))
558  return false; // deny everything!!
559 
560  // Set the port number from the protocol when one is found...
561  if (port)
562  *port = kurl.port();
563 
564  _path = kurl.path();
565  if (_path.isEmpty())
566  _path = QL1S("/");
567 
568  return true;
569 }
570 
571 // not static because it uses m_twoLevelTLD
572 void KCookieJar::extractDomains(const QString &_fqdn,
573  QStringList &_domains) const
574 {
575  if (_fqdn.isEmpty()) {
576  _domains.append( QL1S("localhost") );
577  return;
578  }
579 
580  // Return numeric IPv6 addresses as is...
581  if (_fqdn[0] == '[')
582  {
583  _domains.append( _fqdn );
584  return;
585  }
586  // Return numeric IPv4 addresses as is...
587  if (_fqdn[0] >= '0' && _fqdn[0] <= '9' && _fqdn.indexOf(QRegExp(IP_ADDRESS_EXPRESSION)) > -1)
588  {
589  _domains.append( _fqdn );
590  return;
591  }
592 
593  // Always add the FQDN at the start of the list for
594  // hostname == cookie-domainname checks!
595  _domains.append(_fqdn);
596  _domains.append(QL1C('.') + _fqdn);
597 
598  QStringList partList = _fqdn.split(QL1C('.'), QString::SkipEmptyParts);
599 
600  if (partList.count())
601  partList.erase(partList.begin()); // Remove hostname
602 
603  while(partList.count())
604  {
605 
606  if (partList.count() == 1)
607  break; // We only have a TLD left.
608 
609  if ((partList.count() == 2) && m_twoLevelTLD.contains(partList[1].toLower()))
610  {
611  // This domain uses two-level TLDs in the form xxxx.yy
612  break;
613  }
614 
615  if ((partList.count() == 2) && (partList[1].length() == 2))
616  {
617  // If this is a TLD, we should stop. (e.g. co.uk)
618  // We assume this is a TLD if it ends with .xx.yy or .x.yy
619  if (partList[0].length() <= 2)
620  break; // This is a TLD.
621 
622  // Catch some TLDs that we miss with the previous check
623  // e.g. com.au, org.uk, mil.co
624  if (m_gTLDs.contains(partList[0].toLower()))
625  break;
626  }
627 
628  QString domain = partList.join(QL1S("."));
629  _domains.append(domain);
630  _domains.append(QL1C('.') + domain);
631  partList.erase(partList.begin()); // Remove part
632  }
633 }
634 
635 //
636 // This function parses cookie_headers and returns a linked list of
637 // KHttpCookie objects for all cookies found in cookie_headers.
638 // If no cookies could be found 0 is returned.
639 //
640 // cookie_headers should be a concatenation of all lines of a HTTP-header
641 // which start with "Set-Cookie". The lines should be separated by '\n's.
642 //
643 KHttpCookieList KCookieJar::makeCookies(const QString &_url,
644  const QByteArray &cookie_headers,
645  long windowId)
646 {
647  QString fqdn, path;
648 
649  if (!parseUrl(_url, fqdn, path))
650  return KHttpCookieList(); // Error parsing _url
651 
652  QString Name, Value;
653  KHttpCookieList cookieList, cookieList2;
654 
655  bool isRFC2965 = false;
656  bool crossDomain = false;
657  const char *cookieStr = cookie_headers.constData();
658 
659  QString defaultPath;
660  const int index = path.lastIndexOf(QL1C('/'));
661  if (index > 0)
662  defaultPath = path.left(index);
663 
664  KDateTime epoch;
665  epoch.setTime_t(0);
666 
667  // Check for cross-domain flag from kio_http
668  if (qstrncmp(cookieStr, "Cross-Domain\n", 13) == 0)
669  {
670  cookieStr += 13;
671  crossDomain = true;
672  }
673 
674  // The hard stuff :)
675  for(;;)
676  {
677  // check for "Set-Cookie"
678  if (qstrnicmp(cookieStr, "Set-Cookie:", 11) == 0)
679  {
680  cookieStr = parseNameValue(cookieStr+11, Name, Value, true);
681 
682  // Host = FQDN
683  // Default domain = ""
684  // Default path according to rfc2109
685 
686 
687  KHttpCookie cookie(fqdn, QL1S(""), defaultPath, Name, Value);
688  if (windowId)
689  cookie.mWindowIds.append(windowId);
690  cookie.mCrossDomain = crossDomain;
691 
692  // Insert cookie in chain
693  cookieList.append(cookie);
694  }
695  else if (qstrnicmp(cookieStr, "Set-Cookie2:", 12) == 0)
696  {
697  // Attempt to follow rfc2965
698  isRFC2965 = true;
699  cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true);
700 
701  // Host = FQDN
702  // Default domain = ""
703  // Default path according to rfc2965
704 
705  KHttpCookie cookie(fqdn, QL1S(""), defaultPath, Name, Value);
706  if (windowId)
707  cookie.mWindowIds.append(windowId);
708  cookie.mCrossDomain = crossDomain;
709 
710  // Insert cookie in chain
711  cookieList2.append(cookie);
712  }
713  else
714  {
715  // This is not the start of a cookie header, skip till next line.
716  while (*cookieStr && *cookieStr != '\n')
717  cookieStr++;
718 
719  if (*cookieStr == '\n')
720  cookieStr++;
721 
722  if (!*cookieStr)
723  break; // End of cookie_headers
724  else
725  continue; // end of this header, continue with next.
726  }
727 
728  while ((*cookieStr == ';') || (*cookieStr == ' '))
729  {
730  cookieStr++;
731 
732  // Name-Value pair follows
733  cookieStr = parseNameValue(cookieStr, Name, Value);
734  KHttpCookie& lastCookie = (isRFC2965 ? cookieList2.last() : cookieList.last());
735 
736  if (Name.compare(QL1S("domain"), Qt::CaseInsensitive) == 0)
737  {
738  QString dom = Value.toLower();
739  // RFC2965 3.2.2: If an explicitly specified value does not
740  // start with a dot, the user agent supplies a leading dot
741  if(dom.length() && dom[0] != '.')
742  dom.prepend(".");
743  // remove a trailing dot
744  if(dom.length() > 2 && dom[dom.length()-1] == '.')
745  dom = dom.left(dom.length()-1);
746 
747  if(dom.count(QL1C('.')) > 1 || dom == ".local")
748  lastCookie.mDomain = dom;
749  }
750  else if (Name.compare(QL1S("max-age"), Qt::CaseInsensitive) == 0)
751  {
752  int max_age = Value.toInt();
753  if (max_age == 0)
754  lastCookie.mExpireDate = 1;
755  else
756  lastCookie.mExpireDate = epoch.secsTo_long(KDateTime::currentUtcDateTime().addSecs(max_age));
757  }
758  else if (Name.compare(QL1S("expires"), Qt::CaseInsensitive) == 0)
759  {
760  const KDateTime dt = parseDate(Value);
761 
762  if (dt.isValid()) {
763  lastCookie.mExpireDate = epoch.secsTo_long(dt);
764  if (lastCookie.mExpireDate == 0)
765  lastCookie.mExpireDate = 1;
766  }
767  }
768  else if (Name.compare(QL1S("path"), Qt::CaseInsensitive) == 0)
769  {
770  if (Value.isEmpty())
771  lastCookie.mPath.clear(); // Catch "" <> QString()
772  else
773  lastCookie.mPath = QUrl::fromPercentEncoding(Value.toLatin1());
774  lastCookie.mExplicitPath = true;
775  }
776  else if (Name.compare(QL1S("version"), Qt::CaseInsensitive) == 0)
777  {
778  lastCookie.mProtocolVersion = Value.toInt();
779  }
780  else if (Name.compare(QL1S("secure"), Qt::CaseInsensitive) == 0 ||
781  (Name.isEmpty() && Value.compare(QL1S("secure"), Qt::CaseInsensitive) == 0))
782  {
783  lastCookie.mSecure = true;
784  }
785  else if (Name.compare(QL1S("httponly"), Qt::CaseInsensitive) == 0 ||
786  (Name.isEmpty() && Value.compare(QL1S("httponly"), Qt::CaseInsensitive) == 0))
787  {
788  lastCookie.mHttpOnly = true;
789  }
790  else if (isRFC2965 && (Name.compare(QL1S("port"), Qt::CaseInsensitive) == 0 ||
791  (Name.isEmpty() && Value.compare(QL1S("port"), Qt::CaseInsensitive) == 0)))
792  {
793  // Based on the port selection rule of RFC 2965 section 3.3.4...
794  if (Name.isEmpty())
795  {
796  // We intentionally append a -1 first in order to distinguish
797  // between only a 'Port' vs a 'Port="80 443"' in the sent cookie.
798  lastCookie.mPorts.append(-1);
799  const bool secureRequest = (_url.startsWith(QL1S("https://"), Qt::CaseInsensitive) ||
800  _url.startsWith(QL1S("webdavs://"), Qt::CaseInsensitive));
801  if (secureRequest)
802  lastCookie.mPorts.append(443);
803  else
804  lastCookie.mPorts.append(80);
805  }
806  else
807  {
808  bool ok;
809  const QStringList portNums = Value.split(QL1C(' '), QString::SkipEmptyParts);
810  Q_FOREACH(const QString& portNum, portNums)
811  {
812  const int port = portNum.toInt(&ok);
813  if (ok)
814  lastCookie.mPorts.append(port);
815  }
816  }
817  }
818  }
819 
820  if (*cookieStr == '\0')
821  break; // End of header
822 
823  // Skip ';' or '\n'
824  cookieStr++;
825  }
826 
827  // RFC2965 cookies come last so that they override netscape cookies.
828  while(!cookieList2.isEmpty()) {
829  KHttpCookie& lastCookie = cookieList2.first();
830  removeDuplicateFromList(&cookieList, lastCookie, true);
831  cookieList.append(lastCookie);
832  cookieList2.removeFirst();
833  }
834 
835  return cookieList;
836 }
837 
844 KHttpCookieList KCookieJar::makeDOMCookies(const QString &_url,
845  const QByteArray &cookie_domstring,
846  long windowId)
847 {
848  // A lot copied from above
849  KHttpCookieList cookieList;
850 
851  const char *cookieStr = cookie_domstring.data();
852  QString fqdn;
853  QString path;
854 
855  if (!parseUrl(_url, fqdn, path))
856  {
857  // Error parsing _url
858  return KHttpCookieList();
859  }
860 
861  QString Name;
862  QString Value;
863  // This time it's easy
864  while(*cookieStr)
865  {
866  cookieStr = parseNameValue(cookieStr, Name, Value);
867 
868  // Host = FQDN
869  // Default domain = ""
870  // Default path = ""
871  KHttpCookie cookie(fqdn, QString(), QString(),
872  Name, Value );
873  if (windowId)
874  cookie.mWindowIds.append(windowId);
875 
876  cookieList.append(cookie);
877 
878  if (*cookieStr != '\0')
879  cookieStr++; // Skip ';' or '\n'
880  }
881 
882  return cookieList;
883 }
884 
885 // KHttpCookieList sorting
887 
888 // We want the longest path first
889 static bool compareCookies(const KHttpCookie& item1, const KHttpCookie& item2)
890 {
891  return item1.path().length() > item2.path().length();
892 }
893 
894 
895 #ifdef MAX_COOKIE_LIMIT
896 static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr)
897 {
898  // Too many cookies: throw one away, try to be somewhat clever
899  KHttpCookiePtr lastCookie = 0;
900  for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
901  {
902  if (compareCookies(cookie, cookiePtr))
903  break;
904  lastCookie = cookie;
905  }
906  if (!lastCookie)
907  lastCookie = cookieList->first();
908  cookieList->removeRef(lastCookie);
909 }
910 #endif
911 
912 //
913 // This function hands a KHttpCookie object over to the cookie jar.
914 //
915 void KCookieJar::addCookie(KHttpCookie &cookie)
916 {
917  QStringList domains;
918  // We always need to do this to make sure that the
919  // that cookies of type hostname == cookie-domainname
920  // are properly removed and/or updated as necessary!
921  extractDomains( cookie.host(), domains );
922 
923  QStringListIterator it (domains);
924  while (it.hasNext())
925  {
926  const QString& key = it.next();
927  KHttpCookieList* list;
928 
929  if (key.isNull())
930  list = m_cookieDomains.value(QL1S(""));
931  else
932  list = m_cookieDomains.value(key);
933 
934  if (list)
935  removeDuplicateFromList(list, cookie, false, true);
936  }
937 
938  const QString domain = stripDomain( cookie );
939  KHttpCookieList* cookieList;
940  if (domain.isNull())
941  cookieList = m_cookieDomains.value(QL1S(""));
942  else
943  cookieList = m_cookieDomains.value(domain);
944 
945  if (!cookieList)
946  {
947  // Make a new cookie list
948  cookieList = new KHttpCookieList();
949 
950  // All cookies whose domain is not already
951  // known to us should be added with KCookieDunno.
952  // KCookieDunno means that we use the global policy.
953  cookieList->setAdvice( KCookieDunno );
954 
955  m_cookieDomains.insert( domain, cookieList);
956 
957  // Update the list of domains
958  m_domainList.append(domain);
959  }
960 
961  // Add the cookie to the cookie list
962  // The cookie list is sorted 'longest path first'
963  if (!cookie.isExpired())
964  {
965 #ifdef MAX_COOKIE_LIMIT
966  if (cookieList->count() >= MAX_COOKIES_PER_HOST)
967  makeRoom(cookieList, cookie); // Delete a cookie
968 #endif
969  cookieList->push_back(cookie);
970  // Use a stable sort so that unit tests are reliable.
971  // In practice it doesn't matter though.
972  qStableSort(cookieList->begin(), cookieList->end(), compareCookies);
973 
974  m_cookiesChanged = true;
975  }
976 }
977 
978 //
979 // This function advices whether a single KHttpCookie object should
980 // be added to the cookie jar.
981 //
982 KCookieAdvice KCookieJar::cookieAdvice(KHttpCookie& cookie)
983 {
984  if (m_rejectCrossDomainCookies && cookie.isCrossDomain())
985  return KCookieReject;
986 
987  QStringList domains;
988  extractDomains(cookie.host(), domains);
989 
990  // If the cookie specifies a domain, check whether it is valid. Otherwise,
991  // accept the cookie anyways but removes the domain="" value to prevent
992  // cross-site cookie injection.
993  if (!cookie.domain().isEmpty()) {
994  if (!domains.contains(cookie.domain()) &&
995  !cookie.domain().endsWith(QL1C('.') + cookie.host()))
996  cookie.fixDomain(QString());
997  }
998 
999  if (m_autoAcceptSessionCookies && (cookie.expireDate() == 0 ||
1000  m_ignoreCookieExpirationDate))
1001  return KCookieAccept;
1002 
1003  KCookieAdvice advice = KCookieDunno;
1004  QStringListIterator it (domains);
1005  while(advice == KCookieDunno && it.hasNext()) {
1006  const QString& domain = it.next();
1007  if (domain.startsWith(QL1C('.')) || cookie.host() == domain) {
1008  KHttpCookieList *cookieList = m_cookieDomains.value(domain);
1009  if (cookieList)
1010  advice = cookieList->getAdvice();
1011  }
1012  }
1013 
1014  if (advice == KCookieDunno)
1015  advice = m_globalAdvice;
1016 
1017  return advice;
1018 }
1019 
1020 //
1021 // This function gets the advice for all cookies originating from
1022 // _domain.
1023 //
1024 KCookieAdvice KCookieJar::getDomainAdvice(const QString &_domain)
1025 {
1026  KHttpCookieList *cookieList = m_cookieDomains.value(_domain);
1027  KCookieAdvice advice;
1028 
1029  if (cookieList)
1030  advice = cookieList->getAdvice();
1031  else
1032  advice = KCookieDunno;
1033 
1034  return advice;
1035 }
1036 
1037 //
1038 // This function sets the advice for all cookies originating from
1039 // _domain.
1040 //
1041 void KCookieJar::setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
1042 {
1043  QString domain(_domain);
1044  KHttpCookieList *cookieList = m_cookieDomains.value(domain);
1045 
1046  if (cookieList) {
1047  if (cookieList->getAdvice() != _advice) {
1048  m_configChanged = true;
1049  // domain is already known
1050  cookieList->setAdvice( _advice);
1051  }
1052 
1053  if ((cookieList->isEmpty()) && (_advice == KCookieDunno)) {
1054  // This deletes cookieList!
1055  delete m_cookieDomains.take(domain);
1056  m_domainList.removeAll(domain);
1057  }
1058  } else {
1059  // domain is not yet known
1060  if (_advice != KCookieDunno) {
1061  // We should create a domain entry
1062  m_configChanged = true;
1063  // Make a new cookie list
1064  cookieList = new KHttpCookieList();
1065  cookieList->setAdvice(_advice);
1066  m_cookieDomains.insert(domain, cookieList);
1067  // Update the list of domains
1068  m_domainList.append( domain);
1069  }
1070  }
1071 }
1072 
1073 //
1074 // This function sets the advice for all cookies originating from
1075 // the same domain as _cookie
1076 //
1077 void KCookieJar::setDomainAdvice(const KHttpCookie& cookie, KCookieAdvice _advice)
1078 {
1079  QString domain;
1080  stripDomain(cookie.host(), domain); // We file the cookie under this domain.
1081  setDomainAdvice(domain, _advice);
1082 }
1083 
1084 //
1085 // This function sets the global advice for cookies
1086 //
1087 void KCookieJar::setGlobalAdvice(KCookieAdvice _advice)
1088 {
1089  if (m_globalAdvice != _advice)
1090  m_configChanged = true;
1091  m_globalAdvice = _advice;
1092 }
1093 
1094 //
1095 // Get a list of all domains known to the cookie jar.
1096 //
1097 const QStringList& KCookieJar::getDomainList()
1098 {
1099  return m_domainList;
1100 }
1101 
1102 //
1103 // Get a list of all cookies in the cookie jar originating from _domain.
1104 //
1105 KHttpCookieList *KCookieJar::getCookieList(const QString & _domain,
1106  const QString & _fqdn )
1107 {
1108  QString domain;
1109 
1110  if (_domain.isEmpty())
1111  stripDomain(_fqdn, domain);
1112  else
1113  domain = _domain;
1114 
1115  return m_cookieDomains.value(domain);
1116 }
1117 
1118 //
1119 // Eat a cookie out of the jar.
1120 // cookieIterator should be one of the cookies returned by getCookieList()
1121 //
1122 void KCookieJar::eatCookie(KHttpCookieList::iterator cookieIterator)
1123 {
1124  const KHttpCookie& cookie = *cookieIterator;
1125  const QString domain = stripDomain(cookie); // We file the cookie under this domain.
1126  KHttpCookieList *cookieList = m_cookieDomains.value(domain);
1127 
1128  if (cookieList) {
1129  // This deletes cookie!
1130  cookieList->erase(cookieIterator);
1131 
1132  if ((cookieList->isEmpty()) &&
1133  (cookieList->getAdvice() == KCookieDunno))
1134  {
1135  // This deletes cookieList!
1136  delete m_cookieDomains.take(domain);
1137  m_domainList.removeAll(domain);
1138  }
1139  }
1140 }
1141 
1142 void KCookieJar::eatCookiesForDomain(const QString &domain)
1143 {
1144  KHttpCookieList *cookieList = m_cookieDomains.value(domain);
1145  if (!cookieList || cookieList->isEmpty()) return;
1146 
1147  cookieList->clear();
1148  if (cookieList->getAdvice() == KCookieDunno)
1149  {
1150  // This deletes cookieList!
1151  delete m_cookieDomains.take(domain);
1152  m_domainList.removeAll(domain);
1153  }
1154  m_cookiesChanged = true;
1155 }
1156 
1157 void KCookieJar::eatSessionCookies( long windowId )
1158 {
1159  if (!windowId)
1160  return;
1161 
1162  Q_FOREACH(const QString& domain, m_domainList)
1163  eatSessionCookies( domain, windowId, false );
1164 }
1165 
1166 void KCookieJar::eatAllCookies()
1167 {
1168  Q_FOREACH(const QString& domain, m_domainList)
1169  eatCookiesForDomain(domain); // This might remove domain from m_domainList!
1170 }
1171 
1172 void KCookieJar::eatSessionCookies( const QString& fqdn, long windowId,
1173  bool isFQDN )
1174 {
1175  KHttpCookieList* cookieList;
1176  if ( !isFQDN )
1177  cookieList = m_cookieDomains.value(fqdn);
1178  else {
1179  QString domain;
1180  stripDomain( fqdn, domain );
1181  cookieList = m_cookieDomains.value(domain);
1182  }
1183 
1184  if (cookieList) {
1185  QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
1186  while (cookieIterator.hasNext()) {
1187  KHttpCookie& cookie = cookieIterator.next();
1188  if ((cookie.expireDate() != 0) && !m_ignoreCookieExpirationDate) {
1189  continue;
1190  }
1191 
1192  QList<long> &ids = cookie.windowIds();
1193 
1194 #ifndef NDEBUG
1195  if (ids.contains(windowId)) {
1196  if (ids.count() > 1)
1197  kDebug(7104) << "removing window id" << windowId << "from session cookie";
1198  else
1199  kDebug(7104) << "deleting session cookie";
1200  }
1201 #endif
1202  if (!ids.removeAll(windowId) || !ids.isEmpty()) {
1203  continue;
1204  }
1205  cookieIterator.remove();
1206  }
1207  }
1208 }
1209 
1210 static QString hostWithPort(const KHttpCookie* cookie)
1211 {
1212  const QList<int>& ports = cookie->ports();
1213 
1214  if (ports.isEmpty())
1215  return cookie->host();
1216 
1217  QStringList portList;
1218  Q_FOREACH(int port, ports)
1219  portList << QString::number(port);
1220 
1221  return (cookie->host() + QL1C(':') + portList.join(QL1S(",")));
1222 }
1223 
1224 //
1225 // Saves all cookies to the file '_filename'.
1226 // On succes 'true' is returned.
1227 // On failure 'false' is returned.
1228 bool KCookieJar::saveCookies(const QString &_filename)
1229 {
1230  KSaveFile cookieFile(_filename);
1231 
1232  if (!cookieFile.open())
1233  return false;
1234  cookieFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
1235 
1236  QTextStream ts(&cookieFile);
1237 
1238  ts << "# KDE Cookie File v2\n#\n";
1239 
1240  QString s;
1241  s.sprintf("%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n",
1242  "# Host", "Domain", "Path", "Exp.date", "Prot",
1243  "Name", "Sec", "Value");
1244  ts << s.toLatin1().constData();
1245 
1246  QStringListIterator it(m_domainList);
1247  while (it.hasNext())
1248  {
1249  const QString& domain = it.next();
1250  bool domainPrinted = false;
1251 
1252  KHttpCookieList *cookieList = m_cookieDomains.value(domain);
1253  if (!cookieList)
1254  continue;
1255 
1256  QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
1257  while (cookieIterator.hasNext()) {
1258  const KHttpCookie& cookie = cookieIterator.next();
1259  if (cookie.isExpired()) {
1260  // Delete expired cookies
1261  cookieIterator.remove();
1262  continue;
1263  }
1264  if (cookie.expireDate() != 0 && !m_ignoreCookieExpirationDate) {
1265  // Only save cookies that are not "session-only cookies"
1266  if (!domainPrinted) {
1267  domainPrinted = true;
1268  ts << '[' << domain.toLocal8Bit().data() << "]\n";
1269  }
1270  // Store persistent cookies
1271  const QString path = QL1S("\"") + cookie.path() + QL1C('"');
1272  const QString domain = QL1S("\"") + cookie.domain() + QL1C('"');
1273  const QString host = hostWithPort(&cookie);
1274 
1275  // TODO: replace with direct QTextStream output ?
1276  s.sprintf("%-20s %-20s %-12s %10lld %3d %-20s %-4i %s\n",
1277  host.toLatin1().constData(), domain.toLatin1().constData(),
1278  path.toLatin1().constData(), cookie.expireDate(),
1279  cookie.protocolVersion(),
1280  cookie.name().isEmpty() ? cookie.value().toLatin1().constData() : cookie.name().toLatin1().constData(),
1281  (cookie.isSecure() ? 1 : 0) + (cookie.isHttpOnly() ? 2 : 0) +
1282  (cookie.hasExplicitPath() ? 4 : 0) + (cookie.name().isEmpty() ? 8 : 0),
1283  cookie.value().toLatin1().constData());
1284  ts << s.toLatin1().constData();
1285  }
1286  }
1287  }
1288 
1289  return cookieFile.finalize();
1290 }
1291 
1292 static const char *parseField(char* &buffer, bool keepQuotes=false)
1293 {
1294  char *result;
1295  if (!keepQuotes && (*buffer == '\"'))
1296  {
1297  // Find terminating "
1298  buffer++;
1299  result = buffer;
1300  while((*buffer != '\"') && (*buffer))
1301  buffer++;
1302  }
1303  else
1304  {
1305  // Find first white space
1306  result = buffer;
1307  while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer))
1308  buffer++;
1309  }
1310 
1311  if (!*buffer)
1312  return result; //
1313  *buffer++ = '\0';
1314 
1315  // Skip white-space
1316  while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n'))
1317  buffer++;
1318 
1319  return result;
1320 }
1321 
1322 
1323 static QString extractHostAndPorts(const QString& str, QList<int>* ports = 0)
1324 {
1325  if (str.isEmpty())
1326  return str;
1327 
1328  const int index = str.indexOf(QL1C(':'));
1329  if (index == -1)
1330  return str;
1331 
1332  const QString host = str.left(index);
1333  if (ports) {
1334  bool ok;
1335  QStringList portList = str.mid(index+1).split(QL1C(','));
1336  Q_FOREACH(const QString& portStr, portList) {
1337  const int portNum = portStr.toInt(&ok);
1338  if (ok)
1339  ports->append(portNum);
1340  }
1341  }
1342 
1343  return host;
1344 }
1345 
1346 //
1347 // Reloads all cookies from the file '_filename'.
1348 // On succes 'true' is returned.
1349 // On failure 'false' is returned.
1350 bool KCookieJar::loadCookies(const QString &_filename)
1351 {
1352  QFile cookieFile (_filename);
1353 
1354  if (!cookieFile.open(QIODevice::ReadOnly))
1355  return false;
1356 
1357  int version = 1;
1358  bool success = false;
1359  char *buffer = new char[READ_BUFFER_SIZE];
1360  qint64 len = cookieFile.readLine(buffer, READ_BUFFER_SIZE-1);
1361 
1362  if (len != -1)
1363  {
1364  if (qstrcmp(buffer, "# KDE Cookie File\n") == 0)
1365  {
1366  success = true;
1367  }
1368  else if(qstrcmp(buffer, "# KDE Cookie File v") > 0)
1369  {
1370  bool ok = false;
1371  const int verNum = QByteArray(buffer+19, len-19).trimmed().toInt(&ok);
1372  if (ok)
1373  {
1374  version = verNum;
1375  success = true;
1376  }
1377  }
1378  }
1379 
1380  if (success)
1381  {
1382  const qint64 currentTime = epoch();
1383  QList<int> ports;
1384 
1385  while(cookieFile.readLine(buffer, READ_BUFFER_SIZE-1) != -1)
1386  {
1387  char *line = buffer;
1388  // Skip lines which begin with '#' or '['
1389  if ((line[0] == '#') || (line[0] == '['))
1390  continue;
1391 
1392  const QString host = extractHostAndPorts(QL1S(parseField(line)), &ports);
1393  const QString domain = QL1S( parseField(line) );
1394  if (host.isEmpty() && domain.isEmpty())
1395  continue;
1396  const QString path = QL1S( parseField(line) );
1397  const QString expStr = QL1S( parseField(line) );
1398  if (expStr.isEmpty()) continue;
1399  const qint64 expDate = expStr.toLongLong();
1400  const QString verStr = QL1S( parseField(line) );
1401  if (verStr.isEmpty()) continue;
1402  int protVer = verStr.toInt();
1403  QString name = QL1S( parseField(line) );
1404  bool keepQuotes = false;
1405  bool secure = false;
1406  bool httpOnly = false;
1407  bool explicitPath = false;
1408  const char *value = 0;
1409  if ((version == 2) || (protVer >= 200))
1410  {
1411  if (protVer >= 200)
1412  protVer -= 200;
1413  int i = atoi( parseField(line) );
1414  secure = i & 1;
1415  httpOnly = i & 2;
1416  explicitPath = i & 4;
1417  if (i & 8)
1418  name = "";
1419  line[strlen(line)-1] = '\0'; // Strip LF.
1420  value = line;
1421  }
1422  else
1423  {
1424  if (protVer >= 100)
1425  {
1426  protVer -= 100;
1427  keepQuotes = true;
1428  }
1429  value = parseField(line, keepQuotes);
1430  secure = QByteArray(parseField(line)).toShort();
1431  }
1432 
1433  // Expired or parse error
1434  if (!value || expDate == 0 || expDate < currentTime)
1435  continue;
1436 
1437  KHttpCookie cookie(host, domain, path, name, value, expDate,
1438  protVer, secure, httpOnly, explicitPath);
1439  if (ports.count())
1440  cookie.mPorts = ports;
1441  addCookie(cookie);
1442  }
1443  }
1444 
1445  delete [] buffer;
1446  m_cookiesChanged = false;
1447  return success;
1448 }
1449 
1450 //
1451 // Save the cookie configuration
1452 //
1453 
1454 void KCookieJar::saveConfig(KConfig *_config)
1455 {
1456  if (!m_configChanged)
1457  return;
1458 
1459  KConfigGroup dlgGroup(_config, "Cookie Dialog");
1460  dlgGroup.writeEntry("PreferredPolicy", static_cast<int>(m_preferredPolicy));
1461  dlgGroup.writeEntry("ShowCookieDetails", m_showCookieDetails );
1462  KConfigGroup policyGroup(_config,"Cookie Policy");
1463  policyGroup.writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice));
1464 
1465  QStringList domainSettings;
1466  QStringListIterator it (m_domainList);
1467  while (it.hasNext())
1468  {
1469  const QString& domain = it.next();
1470  KCookieAdvice advice = getDomainAdvice( domain);
1471  if (advice != KCookieDunno)
1472  {
1473  const QString value = domain + QL1C(':') + adviceToStr(advice);
1474  domainSettings.append(value);
1475  }
1476  }
1477  policyGroup.writeEntry("CookieDomainAdvice", domainSettings);
1478  _config->sync();
1479  m_configChanged = false;
1480 }
1481 
1482 
1483 //
1484 // Load the cookie configuration
1485 //
1486 
1487 void KCookieJar::loadConfig(KConfig *_config, bool reparse )
1488 {
1489  if ( reparse )
1490  _config->reparseConfiguration();
1491 
1492  KConfigGroup dlgGroup(_config, "Cookie Dialog");
1493  m_showCookieDetails = dlgGroup.readEntry( "ShowCookieDetails" , false );
1494  m_preferredPolicy = static_cast<KCookieDefaultPolicy>(dlgGroup.readEntry("PreferredPolicy", 0));
1495 
1496  KConfigGroup policyGroup(_config,"Cookie Policy");
1497  const QStringList domainSettings = policyGroup.readEntry("CookieDomainAdvice", QStringList());
1498  // Warning: those default values are duplicated in the kcm (kio/kcookiespolicies.cpp)
1499  m_rejectCrossDomainCookies = policyGroup.readEntry("RejectCrossDomainCookies", true);
1500  m_autoAcceptSessionCookies = policyGroup.readEntry("AcceptSessionCookies", true);
1501  m_ignoreCookieExpirationDate = policyGroup.readEntry("IgnoreExpirationDate", false);
1502  m_globalAdvice = strToAdvice(policyGroup.readEntry("CookieGlobalAdvice", QString(QL1S("Accept"))));
1503 
1504  // Reset current domain settings first.
1505  Q_FOREACH( const QString &domain, m_domainList )
1506  setDomainAdvice(domain, KCookieDunno);
1507 
1508  // Now apply the domain settings read from config file...
1509  for (QStringList::ConstIterator it = domainSettings.constBegin(), itEnd = domainSettings.constEnd();
1510  it != itEnd; ++it)
1511  {
1512  const QString& value = *it;
1513  const int sepPos = value.lastIndexOf(QL1C(':'));
1514  if (sepPos <= 0)
1515  continue;
1516 
1517  const QString domain(value.left(sepPos));
1518  KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) );
1519  setDomainAdvice(domain, advice);
1520  }
1521 }
1522 
1523 QDebug operator<<(QDebug dbg, const KHttpCookie& cookie)
1524 {
1525  dbg.nospace() << cookie.cookieStr(false);
1526  return dbg.space();
1527 }
1528 
1529 QDebug operator<<(QDebug dbg, const KHttpCookieList& list)
1530 {
1531  Q_FOREACH(const KHttpCookie& cookie, list)
1532  dbg << cookie;
1533  return dbg;
1534 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Dec 7 2012 16:13:30 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIOSlave

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

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal