File indexing completed on 2024-05-05 12:17:41

0001 /*
0002     This file is part of KDE
0003 
0004     SPDX-FileCopyrightText: 2004 Waldo Bastian <bastian@kde.org>
0005     SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only
0008 */
0009 
0010 #include <QDate>
0011 #include <QString>
0012 
0013 #include <QStandardPaths>
0014 #include <QTest>
0015 #include <qplatformdefs.h>
0016 
0017 #include "../../src/kioworkers/http/kcookiejar/kcookiejar.cpp"
0018 
0019 static KCookieJar *jar;
0020 static QString *lastYear;
0021 static QString *nextYear;
0022 static KConfig *config = nullptr;
0023 static int windowId = 1234; // random number to be used as windowId for test cookies
0024 
0025 static void popArg(QString &command, QString &line)
0026 {
0027     int i = line.indexOf(' ');
0028     if (i != -1) {
0029         command = line.left(i);
0030         line = line.mid(i + 1);
0031     } else {
0032         command = line;
0033         line.clear();
0034     }
0035 }
0036 
0037 static void clearConfig()
0038 {
0039     delete config;
0040     QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + "kcookiejar-testconfig";
0041     QFile::remove(file);
0042     config = new KConfig(file);
0043     KConfigGroup cg(config, "Cookie Policy");
0044     cg.writeEntry("RejectCrossDomainCookies", false);
0045     cg.writeEntry("AcceptSessionCookies", false);
0046     cg.writeEntry("CookieGlobalAdvice", "Ask");
0047     jar->loadConfig(config, false);
0048 }
0049 
0050 static void clearCookies(bool sessionOnly = false)
0051 {
0052     if (sessionOnly) {
0053         jar->eatSessionCookies(windowId);
0054     } else {
0055         jar->eatAllCookies();
0056     }
0057 }
0058 
0059 static void saveCookies()
0060 {
0061     QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + "kcookiejar-testcookies";
0062     QFile::remove(file);
0063     jar->saveCookies(file);
0064 
0065     // Add an empty domain to the cookies file, just for testing robustness
0066     QFile f(file);
0067     f.open(QIODevice::Append);
0068     f.write("[]\n   \"\"   \"/\"    1584320400  0 h  4  x\n");
0069     f.close();
0070 
0071     delete jar;
0072     jar = new KCookieJar();
0073     clearConfig();
0074     jar->loadCookies(file);
0075 }
0076 
0077 static void endSession()
0078 {
0079     jar->eatSessionCookies(windowId);
0080 }
0081 
0082 static void processCookie(QString &line)
0083 {
0084     QString policy;
0085     popArg(policy, line);
0086     KCookieAdvice expectedAdvice = KCookieJar::strToAdvice(policy);
0087     if (expectedAdvice == KCookieDunno) {
0088         QFAIL(qPrintable(QStringLiteral("Unknown accept policy '%1'").arg(policy)));
0089     }
0090 
0091     QString urlStr;
0092     popArg(urlStr, line);
0093     QUrl url(urlStr);
0094     if (!url.isValid()) {
0095         QFAIL(qPrintable(QStringLiteral("Invalid URL '%1'").arg(urlStr)));
0096     }
0097     if (url.isEmpty()) {
0098         QFAIL(qPrintable(QStringLiteral("Missing URL")));
0099     }
0100 
0101     line.replace(QLatin1String("%LASTYEAR%"), *lastYear);
0102     line.replace(QLatin1String("%NEXTYEAR%"), *nextYear);
0103 
0104     KHttpCookieList list = jar->makeCookies(urlStr, line.toUtf8(), windowId);
0105 
0106     if (list.isEmpty()) {
0107         QFAIL(qPrintable(QStringLiteral("Failed to make cookies from: '%1'").arg(line)));
0108     }
0109 
0110     for (KHttpCookieList::iterator cookieIterator = list.begin(); cookieIterator != list.end(); ++cookieIterator) {
0111         KHttpCookie &cookie = *cookieIterator;
0112         const KCookieAdvice cookieAdvice = jar->cookieAdvice(cookie);
0113         if (cookieAdvice != expectedAdvice) {
0114             QFAIL(qPrintable(urlStr
0115                              + QStringLiteral("\n'%2'\nGot advice '%3' expected '%4'")
0116                                    .arg(line, KCookieJar::adviceToStr(cookieAdvice), KCookieJar::adviceToStr(expectedAdvice))));
0117         }
0118         jar->addCookie(cookie);
0119     }
0120 }
0121 
0122 static void processCheck(QString &line)
0123 {
0124     QString urlStr;
0125     popArg(urlStr, line);
0126     QUrl url(urlStr);
0127     if (!url.isValid()) {
0128         QFAIL(qPrintable(QStringLiteral("Invalid URL '%1'").arg(urlStr)));
0129     }
0130     if (url.isEmpty()) {
0131         QFAIL(qPrintable(QStringLiteral("Missing URL")));
0132     }
0133 
0134     QString expectedCookies = line;
0135 
0136     QString cookies = jar->findCookies(urlStr, false, windowId, nullptr).trimmed();
0137     if (cookies != expectedCookies) {
0138         QFAIL(qPrintable(urlStr + QStringLiteral("\nGot '%1' expected '%2'").arg(cookies, expectedCookies)));
0139     }
0140 }
0141 
0142 static void processClear(QString &line)
0143 {
0144     if (line == QLatin1String("CONFIG")) {
0145         clearConfig();
0146     } else if (line == QLatin1String("COOKIES")) {
0147         clearCookies();
0148     } else if (line == QLatin1String("SESSIONCOOKIES")) {
0149         clearCookies(true);
0150     } else {
0151         QFAIL(qPrintable(QStringLiteral("Unknown command 'CLEAR %1'").arg(line)));
0152     }
0153 }
0154 
0155 static void processConfig(QString &line)
0156 {
0157     QString key;
0158     popArg(key, line);
0159 
0160     if (key.isEmpty()) {
0161         QFAIL(qPrintable(QStringLiteral("Missing Key")));
0162     }
0163 
0164     KConfigGroup cg(config, "Cookie Policy");
0165     cg.writeEntry(key, line);
0166     jar->loadConfig(config, false);
0167 }
0168 
0169 static void processLine(QString line)
0170 {
0171     if (line.isEmpty()) {
0172         return;
0173     }
0174 
0175     if (line[0] == '#') {
0176         if (line[1] == '#') {
0177             qDebug().noquote() << line;
0178         }
0179         return;
0180     }
0181 
0182     QString command;
0183     popArg(command, line);
0184     if (command.isEmpty()) {
0185         return;
0186     }
0187 
0188     if (command == QLatin1String("COOKIE")) {
0189         processCookie(line);
0190     } else if (command == QLatin1String("CHECK")) {
0191         processCheck(line);
0192     } else if (command == QLatin1String("CLEAR")) {
0193         processClear(line);
0194     } else if (command == QLatin1String("CONFIG")) {
0195         processConfig(line);
0196     } else if (command == QLatin1String("SAVE")) {
0197         saveCookies();
0198     } else if (command == QLatin1String("ENDSESSION")) {
0199         endSession();
0200     } else {
0201         QFAIL(qPrintable(QStringLiteral("Unknown command '%1'").arg(command)));
0202     }
0203 }
0204 
0205 class KCookieJarTest : public QObject
0206 {
0207     Q_OBJECT
0208 private Q_SLOTS:
0209     void initTestCase()
0210     {
0211         QStandardPaths::setTestModeEnabled(true);
0212         jar = new KCookieJar;
0213         QDateTime dt = QDateTime::currentDateTime();
0214         lastYear = new QString(dt.addYears(-1).toString(Qt::RFC2822Date));
0215         nextYear = new QString(dt.addYears(1).toString(Qt::RFC2822Date));
0216     }
0217     void testCookieFile_data()
0218     {
0219         QTest::addColumn<QString>("fileName");
0220         QTest::newRow("cookie.test") << QFINDTESTDATA("cookie.test");
0221         QTest::newRow("cookie_rfc.test") << QFINDTESTDATA("cookie_rfc.test");
0222         QTest::newRow("cookie_saving.test") << QFINDTESTDATA("cookie_saving.test");
0223         QTest::newRow("cookie_settings.test") << QFINDTESTDATA("cookie_settings.test");
0224         QTest::newRow("cookie_session.test") << QFINDTESTDATA("cookie_session.test");
0225     }
0226     void testCookieFile()
0227     {
0228         QFETCH(QString, fileName);
0229         clearConfig();
0230 
0231         QFile file(fileName);
0232         QVERIFY2(file.open(QIODevice::ReadOnly), qPrintable(fileName));
0233         while (!file.atEnd()) {
0234             const QByteArray buf = file.readLine().chopped(1);
0235             processLine(QString::fromUtf8(buf));
0236         }
0237     }
0238 
0239     void testParseUrl_data()
0240     {
0241         QTest::addColumn<QString>("url");
0242         QTest::addColumn<bool>("expectedResult");
0243         QTest::addColumn<QString>("expectedFqdn");
0244         QTest::addColumn<QString>("expectedPath");
0245         QTest::newRow("empty") << "" << false << ""
0246                                << "";
0247         QTest::newRow("url with no path") << "http://bugs.kde.org" << true << "bugs.kde.org"
0248                                           << "/";
0249         QTest::newRow("url with path") << "http://bugs.kde.org/foo" << true << "bugs.kde.org"
0250                                        << "/foo";
0251         QTest::newRow("just a host") << "bugs.kde.org" << false << ""
0252                                      << "";
0253     }
0254     void testParseUrl()
0255     {
0256         QFETCH(QString, url);
0257         QFETCH(bool, expectedResult);
0258         QFETCH(QString, expectedFqdn);
0259         QFETCH(QString, expectedPath);
0260         QString fqdn;
0261         QString path;
0262         bool result = KCookieJar::parseUrl(url, fqdn, path);
0263         QCOMPARE(result, expectedResult);
0264         QCOMPARE(fqdn, expectedFqdn);
0265         QCOMPARE(path, expectedPath);
0266     }
0267 
0268     void testExtractDomains_data()
0269     {
0270         QTest::addColumn<QString>("fqdn");
0271         QTest::addColumn<QStringList>("expectedDomains");
0272         QTest::newRow("empty") << "" << (QStringList() << QStringLiteral("localhost"));
0273         QTest::newRow("ipv4") << "1.2.3.4" << (QStringList() << QStringLiteral("1.2.3.4"));
0274         QTest::newRow("ipv6") << "[fe80::213:d3ff:fef4:8c92]" << (QStringList() << QStringLiteral("[fe80::213:d3ff:fef4:8c92]"));
0275         QTest::newRow("bugs.kde.org") << "bugs.kde.org"
0276                                       << (QStringList() << QStringLiteral("bugs.kde.org") << QStringLiteral(".bugs.kde.org") << QStringLiteral("kde.org")
0277                                                         << QStringLiteral(".kde.org"));
0278     }
0279     void testExtractDomains()
0280     {
0281         QFETCH(QString, fqdn);
0282         QFETCH(QStringList, expectedDomains);
0283         KCookieJar jar;
0284         QStringList lst;
0285         jar.extractDomains(fqdn, lst);
0286         QCOMPARE(lst, expectedDomains);
0287     }
0288 };
0289 
0290 QTEST_MAIN(KCookieJarTest)
0291 
0292 #include "kcookiejartest.moc"