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

Skip menu "kdelibs-4.9.4 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