• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 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
72static 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
92static 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
121static qint64 toEpochSecs(const QDateTime& dt)
122{
123 return (dt.toMSecsSinceEpoch()/1000); // convert to seconds...
124}
125
126static qint64 epoch()
127{
128 return toEpochSecs(QDateTime::currentDateTimeUtc());
129}
130
131QString 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
143KCookieAdvice 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//
168KHttpCookie::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//
196bool 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//
207QString 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.
238bool 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//
291KCookieJar::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//
308KCookieJar::~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
315static 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//
350QString 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
461static 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
547void 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
559QString 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
569bool 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
594void 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//
665KHttpCookieList 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
863KHttpCookieList 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
908static 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
915static 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//
934void 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//
1010KCookieAdvice 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//
1046bool 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//
1063KCookieAdvice 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//
1080void 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//
1116void 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//
1126void 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//
1136const 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//
1144KHttpCookieList *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//
1161void 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
1181void 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
1196void 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
1205void KCookieJar::eatAllCookies()
1206{
1207 Q_FOREACH(const QString& domain, m_domainList)
1208 eatCookiesForDomain(domain); // This might remove domain from m_domainList!
1209}
1210
1211void 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
1249static 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.
1267bool 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
1332static 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
1363static 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.
1390bool 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
1494void 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
1527void 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
1562QDebug operator<<(QDebug dbg, const KHttpCookie& cookie)
1563{
1564 dbg.nospace() << cookie.cookieStr(false);
1565 return dbg.space();
1566}
1567
1568QDebug operator<<(QDebug dbg, const KHttpCookieList& list)
1569{
1570 Q_FOREACH(const KHttpCookie& cookie, list)
1571 dbg << cookie;
1572 return dbg;
1573}
KConfigGroup
KConfigGroup::writeEntry
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
KConfigGroup::readEntry
QString readEntry(const char *key, const char *aDefault=0) const
KConfig
KConfig::reparseConfiguration
void reparseConfiguration()
KConfig::sync
void sync()
KConfig::NoGlobals
NoGlobals
KCookieJar::eatSessionCookies
void eatSessionCookies(long windowId)
Removes all end of session cookies set by the session windId.
Definition: kcookiejar.cpp:1196
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
KCookieJar::m_globalAdvice
KCookieAdvice m_globalAdvice
Definition: kcookiejar.h:384
KCookieJar::getDomainAdvice
KCookieAdvice getDomainAdvice(const QString &_domain) const
This function gets the advice for all cookies originating from _domain.
Definition: kcookiejar.cpp:1063
KCookieJar::m_gTLDs
QSet< QString > m_gTLDs
Definition: kcookiejar.h:387
KCookieJar::strToAdvice
static KCookieAdvice strToAdvice(const QString &_str)
Definition: kcookiejar.cpp:143
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
KCookieJar::adviceToStr
static QString adviceToStr(KCookieAdvice _advice)
Definition: kcookiejar.cpp:131
KCookieJar::saveConfig
void saveConfig(KConfig *_config)
Save the cookie configuration.
Definition: kcookiejar.cpp:1494
KCookieJar::saveCookies
bool saveCookies(const QString &_filename)
Store all the cookies in a safe(?) place.
Definition: kcookiejar.cpp:1267
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
KCookieJar::~KCookieJar
~KCookieJar()
Destructs the cookie jar.
Definition: kcookiejar.cpp:308
KCookieJar::eatCookie
void eatCookie(KHttpCookieList::iterator cookieIterator)
Remove & delete a cookie from the jar.
Definition: kcookiejar.cpp:1161
KCookieJar::getDomainList
const QStringList & getDomainList()
Get a list of all domains known to the cookie jar.
Definition: kcookiejar.cpp:1136
KCookieJar::m_cookieDomains
QHash< QString, KHttpCookieList * > m_cookieDomains
Definition: kcookiejar.h:385
KCookieJar::m_twoLevelTLD
QSet< QString > m_twoLevelTLD
Definition: kcookiejar.h:386
KCookieJar::m_domainList
QStringList m_domainList
Definition: kcookiejar.h:383
KCookieJar::m_rejectCrossDomainCookies
bool m_rejectCrossDomainCookies
Definition: kcookiejar.h:392
KCookieJar::stripDomain
void stripDomain(const QString &_fqdn, QString &_domain) const
Definition: kcookiejar.cpp:547
KCookieJar::KCookieJar
KCookieJar()
Constructs a new cookie jar.
Definition: kcookiejar.cpp:291
KCookieJar::addCookie
void addCookie(KHttpCookie &cookie)
This function hands a KHttpCookie object over to the cookie jar.
Definition: kcookiejar.cpp:934
KCookieJar::m_preferredPolicy
KCookieDefaultPolicy m_preferredPolicy
Definition: kcookiejar.h:395
KCookieJar::setDomainAdvice
void setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
This function sets the advice for all cookies originating from _domain.
Definition: kcookiejar.cpp:1080
KCookieJar::m_cookiesChanged
bool m_cookiesChanged
Definition: kcookiejar.h:390
KCookieJar::eatCookiesForDomain
void eatCookiesForDomain(const QString &domain)
Remove & delete all cookies for domain.
Definition: kcookiejar.cpp:1181
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::eatAllCookies
void eatAllCookies()
Remove & delete all cookies.
Definition: kcookiejar.cpp:1205
KCookieJar::m_autoAcceptSessionCookies
bool m_autoAcceptSessionCookies
Definition: kcookiejar.h:393
KCookieJar::cookieIsPersistent
bool cookieIsPersistent(const KHttpCookie &cookie) const
This function tells whether a single KHttpCookie object should be considered persistent.
Definition: kcookiejar.cpp:1046
KCookieJar::loadConfig
void loadConfig(KConfig *_config, bool reparse=false)
Load the cookie configuration.
Definition: kcookiejar.cpp:1527
KCookieJar::m_showCookieDetails
bool m_showCookieDetails
Definition: kcookiejar.h:391
KCookieJar::loadCookies
bool loadCookies(const QString &_filename)
Load all the cookies from file and add them to the cookie jar.
Definition: kcookiejar.cpp:1390
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
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::setGlobalAdvice
void setGlobalAdvice(KCookieAdvice _advice)
This function sets the global advice for cookies.
Definition: kcookiejar.cpp:1126
KCookieJar::m_configChanged
bool m_configChanged
Definition: kcookiejar.h:389
KCookieJar::KCookieDefaultPolicy
KCookieDefaultPolicy
Definition: kcookiejar.h:356
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
KDateTime
KDateTime::dateTime
QDateTime dateTime() const
KDateTime::fromString
static KDateTime fromString(const QString &string, const QString &format, const KTimeZones *zones=0, bool offsetIfAmbiguous=true)
KDateTime::toUtc
KDateTime toUtc() const
KDateTime::isValid
bool isValid() const
KDateTime::RFCDate
RFCDate
KHttpCookieList
Definition: kcookiejar.h:114
KHttpCookieList::getAdvice
KCookieAdvice getAdvice() const
Definition: kcookiejar.h:120
KHttpCookieList::setAdvice
void setAdvice(KCookieAdvice _advice)
Definition: kcookiejar.h:121
KHttpCookie
Definition: kcookiejar.h:50
KHttpCookie::domain
QString domain() const
Definition: kcookiejar.h:85
KHttpCookie::isCrossDomain
bool isCrossDomain() const
Definition: kcookiejar.h:102
KHttpCookie::protocolVersion
int protocolVersion() const
Definition: kcookiejar.h:95
KHttpCookie::mValue
QString mValue
Definition: kcookiejar.h:60
KHttpCookie::mProtocolVersion
int mProtocolVersion
Definition: kcookiejar.h:62
KHttpCookie::mHttpOnly
bool mHttpOnly
Definition: kcookiejar.h:65
KHttpCookie::match
bool match(const QString &fqdn, const QStringList &domainList, const QString &path, int port=-1) const
Definition: kcookiejar.cpp:238
KHttpCookie::value
QString value() const
Definition: kcookiejar.h:89
KHttpCookie::cookieStr
QString cookieStr(bool useDOMFormat) const
Definition: kcookiejar.cpp:207
KHttpCookie::getUserSelectedAdvice
KCookieAdvice getUserSelectedAdvice() const
Definition: kcookiejar.h:107
KHttpCookie::mSecure
bool mSecure
Definition: kcookiejar.h:63
KHttpCookie::ports
const QList< int > & ports() const
Definition: kcookiejar.h:92
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
KHttpCookie::host
QString host() const
Definition: kcookiejar.h:86
KHttpCookie::fixDomain
void fixDomain(const QString &domain)
Definition: kcookiejar.h:93
KHttpCookie::mDomain
QString mDomain
Definition: kcookiejar.h:57
KHttpCookie::mCrossDomain
bool mCrossDomain
Definition: kcookiejar.h:64
KHttpCookie::mExplicitPath
bool mExplicitPath
Definition: kcookiejar.h:66
KHttpCookie::isSecure
bool isSecure() const
Definition: kcookiejar.h:96
KHttpCookie::mPorts
QList< int > mPorts
Definition: kcookiejar.h:68
KHttpCookie::mName
QString mName
Definition: kcookiejar.h:59
KHttpCookie::mExpireDate
qint64 mExpireDate
Definition: kcookiejar.h:61
KHttpCookie::mPath
QString mPath
Definition: kcookiejar.h:58
KHttpCookie::hasExplicitPath
bool hasExplicitPath() const
Definition: kcookiejar.h:104
KHttpCookie::mHost
QString mHost
Definition: kcookiejar.h:56
KHttpCookie::path
QString path() const
Definition: kcookiejar.h:87
KHttpCookie::isHttpOnly
bool isHttpOnly() const
Definition: kcookiejar.h:103
KHttpCookie::mWindowIds
QList< long > mWindowIds
Definition: kcookiejar.h:67
KHttpCookie::expireDate
qint64 expireDate() const
Definition: kcookiejar.h:94
KHttpCookie::name
QString name() const
Definition: kcookiejar.h:88
KHttpCookie::windowIds
QList< long > & windowIds()
Definition: kcookiejar.h:90
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
KSaveFile
KSaveFile::finalize
bool finalize()
KSaveFile::open
virtual bool open(OpenMode flags=QIODevice::ReadWrite)
KUrl
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::protocol
QString protocol() const
QList
QSet
header
const char header[]
kDebug
#define kDebug
version
static const char version[]
Definition: http_cache_cleaner.cpp:65
kconfig.h
kconfiggroup.h
READ_BUFFER_SIZE
#define READ_BUFFER_SIZE
Definition: kcookiejar.cpp:62
QL1S
#define QL1S(x)
Definition: kcookiejar.cpp:68
parseField
static const char * parseField(char *&buffer, bool keepQuotes=false)
Definition: kcookiejar.cpp:1332
MAX_COOKIES_PER_HOST
#define MAX_COOKIES_PER_HOST
Definition: kcookiejar.cpp:61
epoch
static qint64 epoch()
Definition: kcookiejar.cpp:126
QL1C
#define QL1C(x)
Definition: kcookiejar.cpp:69
IP_ADDRESS_EXPRESSION
#define IP_ADDRESS_EXPRESSION
Definition: kcookiejar.cpp:63
extractHostAndPorts
static QString extractHostAndPorts(const QString &str, QList< int > *ports=0)
Definition: kcookiejar.cpp:1363
toEpochSecs
static qint64 toEpochSecs(const QDateTime &dt)
Definition: kcookiejar.cpp:121
parseDate
static QDateTime parseDate(const QString &_value)
Definition: kcookiejar.cpp:92
removeDuplicateFromList
static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie &cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false)
Definition: kcookiejar.cpp:315
parseNameValue
static const char * parseNameValue(const char *header, QString &Name, QString &Value, bool keepQuotes=false, bool rfcQuotes=false)
Definition: kcookiejar.cpp:461
operator<<
QDebug operator<<(QDebug dbg, const KHttpCookie &cookie)
Definition: kcookiejar.cpp:1562
hostWithPort
static QString hostWithPort(const KHttpCookie *cookie)
Definition: kcookiejar.cpp:1249
removeWeekday
static QString removeWeekday(const QString &value)
Definition: kcookiejar.cpp:72
compareCookies
static bool compareCookies(const KHttpCookie &item1, const KHttpCookie &item2)
Definition: kcookiejar.cpp:908
kcookiejar.h
KCookieAdvice
KCookieAdvice
Definition: kcookiejar.h:41
KCookieAcceptForSession
@ KCookieAcceptForSession
Definition: kcookiejar.h:44
KCookieAsk
@ KCookieAsk
Definition: kcookiejar.h:46
KCookieAccept
@ KCookieAccept
Definition: kcookiejar.h:43
KCookieReject
@ KCookieReject
Definition: kcookiejar.h:45
KCookieDunno
@ KCookieDunno
Definition: kcookiejar.h:42
kdatetime.h
kdebug.h
ksavefile.h
ksystemtimezone.h
kurl.h
group
group
list
QStringList list(const QString &fileClass)
name
const char * name(StandardAction id)
ok
KGuiItem ok()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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.14.38 API Reference

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