47#include <QtCore/QString>
48#include <QtCore/QFile>
50#include <QtCore/QRegExp>
51#include <QtCore/QTextStream>
59#undef MAX_COOKIE_LIMIT
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]?)"
68#define QL1S(x) QLatin1String(x)
69#define QL1C(x) QLatin1Char(x)
74 const int index = value.indexOf(
QL1C(
' '));
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)) {
86 return value.mid(pos);
104 static const char* date_formats[] = {
105 "%:B%t%d%t%H:%M:%S%t%Y%t%Z",
106 "%:B%t%d%t%Y%t%H:%M:%S%t%Z",
110 for (
int i = 0; date_formats[i]; ++i) {
123 return (dt.toMSecsSinceEpoch()/1000);
128 return toEpochSecs(QDateTime::currentDateTimeUtc());
139 default:
return QL1S(
"Dunno");
148 QString advice = _str.toLower();
150 if (advice ==
QL1S(
"accept"))
152 else if (advice ==
QL1S(
"acceptforsession"))
154 else if (advice ==
QL1S(
"reject"))
156 else if (advice ==
QL1S(
"ask"))
169 const QString &_domain,
170 const QString &_path,
171 const QString &_name,
172 const QString &_value,
174 int _protocolVersion,
177 bool _explicitPath) :
180 mPath(_path.isEmpty() ? QString() : _path),
183 mExpireDate(_expireDate),
184 mProtocolVersion(_protocolVersion),
187 mHttpOnly(_httpOnly),
188 mExplicitPath(_explicitPath),
198 if (currentDate == -1)
199 currentDate =
epoch();
212 if (
mName.isEmpty() )
224 result +=
QL1S(
"; $Port");
227 Q_FOREACH(
int port,
mPorts)
228 portNums += QString::number(port) +
QL1C(
' ');
229 result +=
QL1S(
"; $Port=\"") + portNums.trimmed() +
QL1C(
'"');
239 const QString &path,
int port)
const
247 else if (!domains.contains(
mDomain))
254 if ( !domains.contains(
domain ) )
317 QString domain1 = cookiePtr.
domain();
318 if (domain1.isEmpty())
319 domain1 = cookiePtr.
host();
321 QMutableListIterator<KHttpCookie> cookieIterator(*
list);
322 while (cookieIterator.hasNext()) {
324 QString domain2 = cookie.
domain();
325 if (domain2.isEmpty())
326 domain2 = cookie.
host();
328 if (cookiePtr.
name() == cookie.
name() &&
329 (nameMatchOnly || (domain1 == domain2 && cookiePtr.
path() == cookie.
path())))
331 if (updateWindowId) {
332 Q_FOREACH(
long windowId, cookie.
windowIds()) {
333 if (windowId && (!cookiePtr.
windowIds().contains(windowId))) {
338 cookieIterator.remove();
352 QString cookieStr, fqdn, path;
356 if (!
parseUrl(_url, fqdn, path, &port))
359 const bool secureRequest = (_url.startsWith(
QL1S(
"https://"), Qt::CaseInsensitive) ||
360 _url.startsWith(
QL1S(
"webdavs://"), Qt::CaseInsensitive));
362 port = (secureRequest ? 443 : 80);
367 for (QStringList::ConstIterator it = domains.constBegin(), itEnd = domains.constEnd();;++it)
372 cookieList = pendingCookies;
388 QMutableListIterator<KHttpCookie> cookieIt (*cookieList);
389 while (cookieIt.hasNext())
395 if (!cookie.
match(fqdn, domains, path, port))
398 if( cookie.
isSecure() && !secureRequest )
415 if (windowId && (cookie.
windowIds().indexOf(windowId) == -1))
421 allCookies.append(cookie);
434 if (!allCookies.isEmpty())
437 cookieStr =
QL1S(
"Cookie: ");
440 cookieStr = cookieStr +
QL1S(
"$Version=") + QString::number(protVersion) +
QL1S(
"; ");
443 cookieStr = cookieStr + cookie.
cookieStr(useDOMFormat) +
QL1S(
"; ");
445 cookieStr.truncate(cookieStr.length() - 2);
464 bool keepQuotes=
false,
465 bool rfcQuotes=
false)
469 for(; (*s !=
'='); s++)
471 if ((*s==
'\0') || (*s==
';') || (*s==
'\n'))
477 Value.truncate( s -
header );
478 Value = Value.trimmed();
484 Name.truncate( s -
header );
485 Name = Name.trimmed();
491 for(; (*s ==
' ') || (*s ==
'\t'); s++)
493 if ((*s==
'\0') || (*s==
';') || (*s==
'\n'))
501 if ((rfcQuotes || !keepQuotes) && (*s ==
'\"'))
508 for(;(*s !=
'\"');s++)
510 if ((*s==
'\0') || (*s==
'\n'))
514 Value.truncate(s -
header);
521 Value.truncate( ++s -
header );
523 Value.truncate( s++ -
header );
528 if ((*s==
'\0') || (*s==
';') || (*s==
'\n'))
536 while ((*s !=
'\0') && (*s !=
';') && (*s !=
'\n'))
540 Value.truncate( s -
header );
541 Value = Value.trimmed();
551 if (domains.count() > 3)
552 _domain = domains[3];
553 else if ( domains.count() > 0 )
554 _domain = domains[0];
562 if (cookie.
domain().isEmpty())
572 if (!kurl.isValid() || kurl.
protocol().isEmpty())
575 _fqdn = kurl.host().toLower();
579 if (_fqdn.contains(
QL1C(
'/')) || _fqdn.contains(
QL1C(
'%')))
595 QStringList &_domains)
const
597 if (_fqdn.isEmpty()) {
598 _domains.append(
QL1S(
"localhost") );
605 _domains.append( _fqdn );
611 _domains.append( _fqdn );
617 _domains.append(_fqdn);
618 _domains.append(
QL1C(
'.') + _fqdn);
620 QStringList partList = _fqdn.split(
QL1C(
'.'), QString::SkipEmptyParts);
622 if (partList.count())
623 partList.erase(partList.begin());
625 while(partList.count())
628 if (partList.count() == 1)
631 if ((partList.count() == 2) &&
m_twoLevelTLD.contains(partList[1].toLower()))
637 if ((partList.count() == 2) && (partList[1].length() == 2))
641 if (partList[0].length() <= 2)
646 if (
m_gTLDs.contains(partList[0].toLower()))
650 QString domain = partList.join(
QL1S(
"."));
651 _domains.append(domain);
652 _domains.append(
QL1C(
'.') + domain);
653 partList.erase(partList.begin());
666 const QByteArray &cookie_headers,
677 bool isRFC2965 =
false;
678 bool crossDomain =
false;
679 const char *cookieStr = cookie_headers.constData();
682 const int index = path.lastIndexOf(
QL1C(
'/'));
684 defaultPath = path.left(index);
687 if (qstrncmp(cookieStr,
"Cross-Domain\n", 13) == 0)
697 if (qstrnicmp(cookieStr,
"Set-Cookie:", 11) == 0)
712 cookieList.append(cookie);
714 else if (qstrnicmp(cookieStr,
"Set-Cookie2:", 12) == 0)
718 cookieStr =
parseNameValue(cookieStr+12, Name, Value,
true,
true);
730 cookieList2.append(cookie);
735 while (*cookieStr && *cookieStr !=
'\n')
738 if (*cookieStr ==
'\n')
747 while ((*cookieStr ==
';') || (*cookieStr ==
' '))
753 KHttpCookie& lastCookie = (isRFC2965 ? cookieList2.last() : cookieList.last());
755 if (Name.compare(
QL1S(
"domain"), Qt::CaseInsensitive) == 0)
757 QString dom = Value.toLower();
760 if(dom.length() && dom[0] !=
'.')
763 if(dom.length() > 2 && dom[dom.length()-1] ==
'.')
764 dom = dom.left(dom.length()-1);
766 if(dom.count(
QL1C(
'.')) > 1 || dom ==
".local")
769 else if (Name.compare(
QL1S(
"max-age"), Qt::CaseInsensitive) == 0)
771 int max_age = Value.toInt();
777 else if (Name.compare(
QL1S(
"expires"), Qt::CaseInsensitive) == 0)
787 else if (Name.compare(
QL1S(
"path"), Qt::CaseInsensitive) == 0)
790 lastCookie.
mPath.clear();
792 lastCookie.
mPath = QUrl::fromPercentEncoding(Value.toLatin1());
795 else if (Name.compare(
QL1S(
"version"), Qt::CaseInsensitive) == 0)
799 else if (Name.compare(
QL1S(
"secure"), Qt::CaseInsensitive) == 0 ||
800 (Name.isEmpty() && Value.compare(
QL1S(
"secure"), Qt::CaseInsensitive) == 0))
804 else if (Name.compare(
QL1S(
"httponly"), Qt::CaseInsensitive) == 0 ||
805 (Name.isEmpty() && Value.compare(
QL1S(
"httponly"), Qt::CaseInsensitive) == 0))
809 else if (isRFC2965 && (Name.compare(
QL1S(
"port"), Qt::CaseInsensitive) == 0 ||
810 (Name.isEmpty() && Value.compare(
QL1S(
"port"), Qt::CaseInsensitive) == 0)))
817 lastCookie.
mPorts.append(-1);
818 const bool secureRequest = (_url.startsWith(
QL1S(
"https://"), Qt::CaseInsensitive) ||
819 _url.startsWith(
QL1S(
"webdavs://"), Qt::CaseInsensitive));
821 lastCookie.
mPorts.append(443);
823 lastCookie.
mPorts.append(80);
828 const QStringList portNums = Value.split(
QL1C(
' '), QString::SkipEmptyParts);
829 Q_FOREACH(
const QString& portNum, portNums)
831 const int port = portNum.toInt(&
ok);
833 lastCookie.
mPorts.append(port);
839 if (*cookieStr ==
'\0')
847 while(!cookieList2.isEmpty()) {
850 cookieList.append(lastCookie);
851 cookieList2.removeFirst();
864 const QByteArray &cookie_domstring,
870 const char *cookieStr = cookie_domstring.data();
895 cookieList.append(cookie);
897 if (*cookieStr !=
'\0')
910 return item1.
path().length() > item2.
path().length();
914#ifdef MAX_COOKIE_LIMIT
919 for(
KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
926 lastCookie = cookieList->first();
927 cookieList->removeRef(lastCookie);
945 if (!cookie.
domain().isEmpty()) {
946 if (!domains.contains(cookie.
domain()) &&
951 QStringListIterator it (domains);
954 const QString& key = it.next();
993#ifdef MAX_COOKIE_LIMIT
995 makeRoom(cookieList, cookie);
997 cookieList->push_back(cookie);
1000 qStableSort(cookieList->begin(), cookieList->end(),
compareCookies);
1021 QStringList domains;
1025 QStringListIterator it (domains);
1027 const QString& domain = it.next();
1028 if (domain.startsWith(
QL1C(
'.')) || cookie.
host() == domain) {
1082 QString domain(_domain);
1086 if (cookieList->
getAdvice() != _advice) {
1092 if ((cookieList->isEmpty()) && (_advice ==
KCookieDunno)) {
1145 const QString & _fqdn )
1149 if (_domain.isEmpty())
1169 cookieList->erase(cookieIterator);
1171 if ((cookieList->isEmpty()) &&
1184 if (!cookieList || cookieList->isEmpty())
return;
1186 cookieList->clear();
1224 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
1225 while (cookieIterator.hasNext()) {
1234 if (ids.contains(windowId)) {
1235 if (ids.count() > 1)
1236 kDebug(7104) <<
"removing window id" << windowId <<
"from session cookie";
1238 kDebug(7104) <<
"deleting session cookie";
1241 if (!ids.removeAll(windowId) || !ids.isEmpty()) {
1244 cookieIterator.remove();
1253 if (ports.isEmpty())
1254 return cookie->
host();
1256 QStringList portList;
1257 Q_FOREACH(
int port, ports)
1258 portList << QString::number(port);
1260 return (cookie->
host() +
QL1C(
':') + portList.join(
QL1S(
",")));
1271 if (!cookieFile.
open())
1273 cookieFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
1275 QTextStream ts(&cookieFile);
1277 ts <<
"# KDE Cookie File v2\n#\n";
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();
1286 while (it.hasNext())
1288 const QString& domain = it.next();
1289 bool domainPrinted =
false;
1295 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
1296 while (cookieIterator.hasNext()) {
1297 const KHttpCookie& cookie = cookieIterator.next();
1301 cookieIterator.remove();
1306 if (!domainPrinted) {
1307 domainPrinted =
true;
1308 ts <<
'[' << domain.toLocal8Bit().data() <<
"]\n";
1311 const QString path =
QL1S(
"\"") + cookie.
path() +
QL1C(
'"');
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(),
1320 cookie.
name().isEmpty() ? cookie.
value().toLatin1().constData() : cookie.
name().toLatin1().constData(),
1323 cookie.
value().toLatin1().constData());
1324 ts << s.toLatin1().constData();
1332static const char *
parseField(
char* &buffer,
bool keepQuotes=
false)
1335 if (!keepQuotes && (*buffer ==
'\"'))
1340 while((*buffer !=
'\"') && (*buffer))
1347 while((*buffer !=
' ') && (*buffer !=
'\t') && (*buffer !=
'\n') && (*buffer))
1356 while((*buffer ==
' ') || (*buffer ==
'\t') || (*buffer ==
'\n'))
1368 const int index = str.indexOf(
QL1C(
':'));
1372 const QString host = str.left(index);
1375 QStringList portList = str.mid(index+1).split(
QL1C(
','));
1376 Q_FOREACH(
const QString& portStr, portList) {
1377 const int portNum = portStr.toInt(&
ok);
1379 ports->append(portNum);
1392 QFile cookieFile (_filename);
1394 if (!cookieFile.open(QIODevice::ReadOnly))
1398 bool success =
false;
1404 if (qstrcmp(buffer,
"# KDE Cookie File\n") == 0)
1408 else if(qstrcmp(buffer,
"# KDE Cookie File v") > 0)
1411 const int verNum = QByteArray(buffer+19, len-19).trimmed().toInt(&
ok);
1422 const qint64 currentTime =
epoch();
1427 char *line = buffer;
1429 if ((line[0] ==
'#') || (line[0] ==
'['))
1434 if (host.isEmpty() && domain.isEmpty())
1438 if (expStr.isEmpty())
continue;
1439 const qint64 expDate = expStr.toLongLong();
1441 if (verStr.isEmpty())
continue;
1442 int protVer = verStr.toInt();
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))
1456 explicitPath = i & 4;
1459 line[strlen(line)-1] =
'\0';
1470 secure = QByteArray(
parseField(line)).toShort();
1474 if (!value || expDate == 0 || expDate < currentTime)
1478 protVer, secure, httpOnly, explicitPath);
1505 QStringList domainSettings;
1507 while (it.hasNext())
1509 const QString& domain = it.next();
1514 domainSettings.append(value);
1517 policyGroup.
writeEntry(
"CookieDomainAdvice", domainSettings);
1537 const QStringList domainSettings = policyGroup.
readEntry(
"CookieDomainAdvice", QStringList());
1548 for (QStringList::ConstIterator it = domainSettings.constBegin(), itEnd = domainSettings.constEnd();
1551 const QString& value = *it;
1552 const int sepPos = value.lastIndexOf(
QL1C(
':'));
1556 const QString domain(value.left(sepPos));
1564 dbg.nospace() << cookie.
cookieStr(
false);
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=0) const
void reparseConfiguration()
void eatSessionCookies(long windowId)
Removes all end of session cookies set by the session windId.
KHttpCookieList * getCookieList(const QString &_domain, const QString &_fqdn)
Get a list of all cookies in the cookie jar originating from _domain.
KCookieAdvice m_globalAdvice
KCookieAdvice getDomainAdvice(const QString &_domain) const
This function gets the advice for all cookies originating from _domain.
static KCookieAdvice strToAdvice(const QString &_str)
void extractDomains(const QString &_fqdn, QStringList &_domainList) const
Returns a list of domains in _domainList relevant for this host.
static QString adviceToStr(KCookieAdvice _advice)
void saveConfig(KConfig *_config)
Save the cookie configuration.
bool saveCookies(const QString &_filename)
Store all the cookies in a safe(?) place.
KCookieAdvice cookieAdvice(const KHttpCookie &cookie) const
This function advices whether a single KHttpCookie object should be added to the cookie jar.
~KCookieJar()
Destructs the cookie jar.
void eatCookie(KHttpCookieList::iterator cookieIterator)
Remove & delete a cookie from the jar.
const QStringList & getDomainList()
Get a list of all domains known to the cookie jar.
QHash< QString, KHttpCookieList * > m_cookieDomains
QSet< QString > m_twoLevelTLD
bool m_rejectCrossDomainCookies
void stripDomain(const QString &_fqdn, QString &_domain) const
KCookieJar()
Constructs a new cookie jar.
void addCookie(KHttpCookie &cookie)
This function hands a KHttpCookie object over to the cookie jar.
KCookieDefaultPolicy m_preferredPolicy
void setDomainAdvice(const QString &_domain, KCookieAdvice _advice)
This function sets the advice for all cookies originating from _domain.
void eatCookiesForDomain(const QString &domain)
Remove & delete all cookies for domain.
QString findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies=0)
Looks for cookies in the cookie jar which are appropriate for _url.
void eatAllCookies()
Remove & delete all cookies.
bool m_autoAcceptSessionCookies
bool cookieIsPersistent(const KHttpCookie &cookie) const
This function tells whether a single KHttpCookie object should be considered persistent.
void loadConfig(KConfig *_config, bool reparse=false)
Load the cookie configuration.
bool loadCookies(const QString &_filename)
Load all the cookies from file and add them to the cookie jar.
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...
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...
void setGlobalAdvice(KCookieAdvice _advice)
This function sets the global advice for cookies.
static bool parseUrl(const QString &_url, QString &_fqdn, QString &_path, int *port=0)
Parses _url and returns the FQDN (_fqdn) and path (_path).
QDateTime dateTime() const
static KDateTime fromString(const QString &string, const QString &format, const KTimeZones *zones=0, bool offsetIfAmbiguous=true)
KCookieAdvice getAdvice() const
void setAdvice(KCookieAdvice _advice)
bool isCrossDomain() const
int protocolVersion() const
bool match(const QString &fqdn, const QStringList &domainList, const QString &path, int port=-1) const
QString cookieStr(bool useDOMFormat) const
KCookieAdvice getUserSelectedAdvice() const
const QList< int > & ports() const
bool isExpired(qint64 currentDate=-1) const
If currentDate is -1, the default, then the current timestamp in UTC is used for comparison against t...
void fixDomain(const QString &domain)
bool hasExplicitPath() const
qint64 expireDate() const
QList< long > & windowIds()
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)
virtual bool open(OpenMode flags=QIODevice::ReadWrite)
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
static const char version[]
static const char * parseField(char *&buffer, bool keepQuotes=false)
#define MAX_COOKIES_PER_HOST
#define IP_ADDRESS_EXPRESSION
static QString extractHostAndPorts(const QString &str, QList< int > *ports=0)
static qint64 toEpochSecs(const QDateTime &dt)
static QDateTime parseDate(const QString &_value)
static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie &cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false)
static const char * parseNameValue(const char *header, QString &Name, QString &Value, bool keepQuotes=false, bool rfcQuotes=false)
QDebug operator<<(QDebug dbg, const KHttpCookie &cookie)
static QString hostWithPort(const KHttpCookie *cookie)
static QString removeWeekday(const QString &value)
static bool compareCookies(const KHttpCookie &item1, const KHttpCookie &item2)
@ KCookieAcceptForSession
QStringList list(const QString &fileClass)
const char * name(StandardAction id)