47 #include <QtCore/QString>
48 #include <QtCore/QFile>
49 #include <QtCore/QDir>
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)
109 default:
return QL1S(
"Dunno");
118 QString advice = _str.toLower();
120 if (advice ==
QL1S(
"accept"))
122 else if (advice ==
QL1S(
"reject"))
124 else if (advice ==
QL1S(
"ask"))
142 int _protocolVersion,
145 bool _explicitPath) :
148 mPath(_path.isEmpty() ?
QString() : _path),
151 mExpireDate(_expireDate),
152 mProtocolVersion(_protocolVersion),
154 mHttpOnly(_httpOnly),
155 mExplicitPath(_explicitPath)
164 if (currentDate == -1)
165 currentDate =
epoch();
178 if (
mName.isEmpty() )
190 result +=
QL1S(
"; $Port");
193 Q_FOREACH(
int port,
mPorts)
194 portNums += QString::number(port) +
QL1C(
' ');
195 result +=
QL1S(
"; $Port=\"") + portNums.trimmed() +
QL1C(
'"');
205 const QString &path,
int port)
const
213 else if (!domains.contains(
mDomain))
220 if ( !domains.contains( domain ) )
238 if( path.startsWith(
mPath) &&
240 (path.length() ==
mPath.length() ) ||
284 if (domain1.isEmpty())
285 domain1 = cookiePtr.
host();
287 QMutableListIterator<KHttpCookie> cookieIterator(*list);
288 while (cookieIterator.hasNext()) {
291 if (domain2.isEmpty())
292 domain2 = cookie.
host();
294 if (cookiePtr.
name() == cookie.
name() &&
295 (nameMatchOnly || (domain1 == domain2 && cookiePtr.
path() == cookie.
path())))
297 if (updateWindowId) {
298 Q_FOREACH(
long windowId, cookie.
windowIds()) {
299 if (windowId && (!cookiePtr.
windowIds().contains(windowId))) {
304 cookieIterator.remove();
323 if (!
parseUrl(_url, fqdn, path, &port))
326 const bool secureRequest = (_url.startsWith(
QL1S(
"https://"), Qt::CaseInsensitive) ||
327 _url.startsWith(
QL1S(
"webdavs://"), Qt::CaseInsensitive));
329 port = (secureRequest ? 443 : 80);
334 for (QStringList::ConstIterator it = domains.constBegin(), itEnd = domains.constEnd();;++it)
339 cookieList = pendingCookies;
358 QMutableListIterator<KHttpCookie> cookieIt (*cookieList);
359 while (cookieIt.hasNext())
370 if (!cookie.
match(fqdn, domains, path, port))
373 if( cookie.
isSecure() && !secureRequest )
390 if (windowId && (cookie.
windowIds().indexOf(windowId) == -1))
396 allCookies.append(cookie);
409 if (!allCookies.isEmpty())
412 cookieStr =
QL1S(
"Cookie: ");
415 cookieStr = cookieStr +
QL1S(
"$Version=") + QString::number(protVersion) +
QL1S(
"; ");
418 cookieStr = cookieStr + cookie.
cookieStr(useDOMFormat) +
QL1S(
"; ");
420 cookieStr.truncate(cookieStr.length() - 2);
439 bool keepQuotes=
false,
440 bool rfcQuotes=
false)
442 const char *s = header;
444 for(; (*s !=
'='); s++)
446 if ((*s==
'\0') || (*s==
';') || (*s==
'\n'))
451 Value =
QL1S(header);
452 Value.truncate( s - header );
453 Value = Value.trimmed();
459 Name.truncate( s - header );
460 Name = Name.trimmed();
466 for(; (*s ==
' ') || (*s ==
'\t'); s++)
468 if ((*s==
'\0') || (*s==
';') || (*s==
'\n'))
476 if ((rfcQuotes || !keepQuotes) && (*s ==
'\"'))
483 for(;(*s !=
'\"');s++)
485 if ((*s==
'\0') || (*s==
'\n'))
488 Value =
QL1S(header);
489 Value.truncate(s - header);
493 Value =
QL1S(header);
496 Value.truncate( ++s - header );
498 Value.truncate( s++ - header );
503 if ((*s==
'\0') || (*s==
';') || (*s==
'\n'))
511 while ((*s !=
'\0') && (*s !=
';') && (*s !=
'\n'))
514 Value =
QL1S(header);
515 Value.truncate( s - header );
516 Value = Value.trimmed();
526 if (domains.count() > 3)
527 _domain = domains[3];
528 else if ( domains.count() > 0 )
529 _domain = domains[0];
537 if (cookie.
domain().isEmpty())
550 if (!kurl.isValid() || kurl.
protocol().isEmpty())
553 _fqdn = kurl.host().toLower();
557 if (_fqdn.contains(
QL1C(
'/')) || _fqdn.contains(
QL1C(
'%')))
575 if (_fqdn.isEmpty()) {
576 _domains.append(
QL1S(
"localhost") );
583 _domains.append( _fqdn );
589 _domains.append( _fqdn );
595 _domains.append(_fqdn);
596 _domains.append(
QL1C(
'.') + _fqdn);
598 QStringList partList = _fqdn.split(
QL1C(
'.'), QString::SkipEmptyParts);
600 if (partList.count())
601 partList.erase(partList.begin());
603 while(partList.count())
606 if (partList.count() == 1)
609 if ((partList.count() == 2) &&
m_twoLevelTLD.contains(partList[1].toLower()))
615 if ((partList.count() == 2) && (partList[1].length() == 2))
619 if (partList[0].length() <= 2)
624 if (
m_gTLDs.contains(partList[0].toLower()))
629 _domains.append(domain);
630 _domains.append(
QL1C(
'.') + domain);
631 partList.erase(partList.begin());
644 const QByteArray &cookie_headers,
655 bool isRFC2965 =
false;
656 bool crossDomain =
false;
657 const char *cookieStr = cookie_headers.constData();
660 const int index = path.lastIndexOf(
QL1C(
'/'));
662 defaultPath = path.left(index);
668 if (qstrncmp(cookieStr,
"Cross-Domain\n", 13) == 0)
678 if (qstrnicmp(cookieStr,
"Set-Cookie:", 11) == 0)
693 cookieList.append(cookie);
695 else if (qstrnicmp(cookieStr,
"Set-Cookie2:", 12) == 0)
699 cookieStr =
parseNameValue(cookieStr+12, Name, Value,
true,
true);
711 cookieList2.append(cookie);
716 while (*cookieStr && *cookieStr !=
'\n')
719 if (*cookieStr ==
'\n')
728 while ((*cookieStr ==
';') || (*cookieStr ==
' '))
734 KHttpCookie& lastCookie = (isRFC2965 ? cookieList2.last() : cookieList.last());
736 if (Name.compare(
QL1S(
"domain"), Qt::CaseInsensitive) == 0)
741 if(dom.length() && dom[0] !=
'.')
744 if(dom.length() > 2 && dom[dom.length()-1] ==
'.')
745 dom = dom.left(dom.length()-1);
747 if(dom.count(
QL1C(
'.')) > 1 || dom ==
".local")
750 else if (Name.compare(
QL1S(
"max-age"), Qt::CaseInsensitive) == 0)
752 int max_age = Value.toInt();
758 else if (Name.compare(
QL1S(
"expires"), Qt::CaseInsensitive) == 0)
768 else if (Name.compare(
QL1S(
"path"), Qt::CaseInsensitive) == 0)
771 lastCookie.
mPath.clear();
773 lastCookie.
mPath = QUrl::fromPercentEncoding(Value.toLatin1());
776 else if (Name.compare(
QL1S(
"version"), Qt::CaseInsensitive) == 0)
780 else if (Name.compare(
QL1S(
"secure"), Qt::CaseInsensitive) == 0 ||
781 (Name.isEmpty() && Value.compare(
QL1S(
"secure"), Qt::CaseInsensitive) == 0))
785 else if (Name.compare(
QL1S(
"httponly"), Qt::CaseInsensitive) == 0 ||
786 (Name.isEmpty() && Value.compare(
QL1S(
"httponly"), Qt::CaseInsensitive) == 0))
790 else if (isRFC2965 && (Name.compare(
QL1S(
"port"), Qt::CaseInsensitive) == 0 ||
791 (Name.isEmpty() && Value.compare(
QL1S(
"port"), Qt::CaseInsensitive) == 0)))
798 lastCookie.
mPorts.append(-1);
799 const bool secureRequest = (_url.startsWith(
QL1S(
"https://"), Qt::CaseInsensitive) ||
800 _url.startsWith(
QL1S(
"webdavs://"), Qt::CaseInsensitive));
802 lastCookie.
mPorts.append(443);
804 lastCookie.
mPorts.append(80);
809 const QStringList portNums = Value.split(
QL1C(
' '), QString::SkipEmptyParts);
810 Q_FOREACH(
const QString& portNum, portNums)
812 const int port = portNum.toInt(&ok);
814 lastCookie.
mPorts.append(port);
820 if (*cookieStr ==
'\0')
828 while(!cookieList2.isEmpty()) {
831 cookieList.append(lastCookie);
832 cookieList2.removeFirst();
845 const QByteArray &cookie_domstring,
851 const char *cookieStr = cookie_domstring.data();
876 cookieList.append(cookie);
878 if (*cookieStr !=
'\0')
891 return item1.
path().length() > item2.
path().length();
895 #ifdef MAX_COOKIE_LIMIT
900 for(
KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next())
907 lastCookie = cookieList->first();
908 cookieList->removeRef(lastCookie);
923 QStringListIterator it (domains);
926 const QString& key = it.next();
965 #ifdef MAX_COOKIE_LIMIT
967 makeRoom(cookieList, cookie);
969 cookieList->push_back(cookie);
972 qStableSort(cookieList->begin(), cookieList->end(),
compareCookies);
993 if (!cookie.
domain().isEmpty()) {
994 if (!domains.contains(cookie.
domain()) &&
1004 QStringListIterator it (domains);
1006 const QString& domain = it.next();
1007 if (domain.startsWith(
QL1C(
'.')) || cookie.
host() == domain) {
1047 if (cookieList->
getAdvice() != _advice) {
1053 if ((cookieList->isEmpty()) && (_advice ==
KCookieDunno)) {
1110 if (_domain.isEmpty())
1130 cookieList->erase(cookieIterator);
1132 if ((cookieList->isEmpty()) &&
1145 if (!cookieList || cookieList->isEmpty())
return;
1147 cookieList->clear();
1185 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
1186 while (cookieIterator.hasNext()) {
1195 if (ids.contains(windowId)) {
1196 if (ids.count() > 1)
1197 kDebug(7104) <<
"removing window id" << windowId <<
"from session cookie";
1199 kDebug(7104) <<
"deleting session cookie";
1202 if (!ids.removeAll(windowId) || !ids.isEmpty()) {
1205 cookieIterator.remove();
1214 if (ports.isEmpty())
1215 return cookie->
host();
1218 Q_FOREACH(
int port, ports)
1219 portList << QString::number(port);
1221 return (cookie->
host() +
QL1C(
':') + portList.join(
QL1S(
",")));
1232 if (!cookieFile.
open())
1234 cookieFile.setPermissions(QFile::ReadUser|QFile::WriteUser);
1236 QTextStream ts(&cookieFile);
1238 ts <<
"# KDE Cookie File v2\n#\n";
1241 s.sprintf(
"%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n",
1242 "# Host",
"Domain",
"Path",
"Exp.date",
"Prot",
1243 "Name",
"Sec",
"Value");
1244 ts << s.toLatin1().constData();
1247 while (it.hasNext())
1249 const QString& domain = it.next();
1250 bool domainPrinted =
false;
1256 QMutableListIterator<KHttpCookie> cookieIterator(*cookieList);
1257 while (cookieIterator.hasNext()) {
1258 const KHttpCookie& cookie = cookieIterator.next();
1261 cookieIterator.remove();
1266 if (!domainPrinted) {
1267 domainPrinted =
true;
1268 ts <<
'[' << domain.toLocal8Bit().data() <<
"]\n";
1276 s.sprintf(
"%-20s %-20s %-12s %10lld %3d %-20s %-4i %s\n",
1277 host.toLatin1().constData(), domain.toLatin1().constData(),
1278 path.toLatin1().constData(), cookie.
expireDate(),
1280 cookie.
name().isEmpty() ? cookie.
value().toLatin1().constData() : cookie.
name().toLatin1().constData(),
1283 cookie.
value().toLatin1().constData());
1284 ts << s.toLatin1().constData();
1292 static const char *
parseField(
char* &buffer,
bool keepQuotes=
false)
1295 if (!keepQuotes && (*buffer ==
'\"'))
1300 while((*buffer !=
'\"') && (*buffer))
1307 while((*buffer !=
' ') && (*buffer !=
'\t') && (*buffer !=
'\n') && (*buffer))
1316 while((*buffer ==
' ') || (*buffer ==
'\t') || (*buffer ==
'\n'))
1328 const int index = str.indexOf(
QL1C(
':'));
1332 const QString host = str.left(index);
1336 Q_FOREACH(
const QString& portStr, portList) {
1337 const int portNum = portStr.toInt(&ok);
1339 ports->append(portNum);
1352 QFile cookieFile (_filename);
1354 if (!cookieFile.open(QIODevice::ReadOnly))
1358 bool success =
false;
1364 if (qstrcmp(buffer,
"# KDE Cookie File\n") == 0)
1368 else if(qstrcmp(buffer,
"# KDE Cookie File v") > 0)
1371 const int verNum = QByteArray(buffer+19, len-19).trimmed().toInt(&ok);
1387 char *line = buffer;
1389 if ((line[0] ==
'#') || (line[0] ==
'['))
1394 if (host.isEmpty() && domain.isEmpty())
1398 if (expStr.isEmpty())
continue;
1399 const qint64 expDate = expStr.toLongLong();
1401 if (verStr.isEmpty())
continue;
1402 int protVer = verStr.toInt();
1404 bool keepQuotes =
false;
1405 bool secure =
false;
1406 bool httpOnly =
false;
1407 bool explicitPath =
false;
1408 const char *value = 0;
1409 if ((version == 2) || (protVer >= 200))
1416 explicitPath = i & 4;
1419 line[strlen(line)-1] =
'\0';
1430 secure = QByteArray(
parseField(line)).toShort();
1434 if (!value || expDate == 0 || expDate < currentTime)
1437 KHttpCookie cookie(host, domain, path, name, value, expDate,
1438 protVer, secure, httpOnly, explicitPath);
1467 while (it.hasNext())
1469 const QString& domain = it.next();
1474 domainSettings.append(value);
1477 policyGroup.
writeEntry(
"CookieDomainAdvice", domainSettings);
1509 for (QStringList::ConstIterator it = domainSettings.constBegin(), itEnd = domainSettings.constEnd();
1513 const int sepPos = value.lastIndexOf(
QL1C(
':'));
1517 const QString domain(value.left(sepPos));
1525 dbg.nospace() << cookie.
cookieStr(
false);