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

KIOSlave

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

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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