File indexing completed on 2024-05-12 05:46:42

0001 /*
0002     This file is part of KDE
0003 
0004     Copyright (C) 2004 Waldo Bastian (bastian@kde.org)
0005     Copyright 2008 David Faure <faure@kde.org>
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Library General Public License
0009     as published by the Free Software Foundation; either
0010     version 2, or (at your option) version 3.
0011 
0012     This software is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     General Public License for more details.
0016 
0017     You should have received a copy of the GNU General Public License
0018     along with this library; see the file COPYING. If not, write to
0019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020     Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include <QDate>
0024 #include <QString>
0025 
0026 #include <QtTest>
0027 #include <qplatformdefs.h>
0028 #include <qstandardpaths.h>
0029 
0030 #include "../../src/ioslaves/http/kcookiejar/kcookiejar.cpp"
0031 
0032 static KCookieJar *jar;
0033 static QString *lastYear;
0034 static QString *nextYear;
0035 static KConfig *config = nullptr;
0036 static int windowId = 1234; // random number to be used as windowId for test cookies
0037 
0038 static void FAIL(const QString &msg)
0039 {
0040     qWarning("%s", msg.toLocal8Bit().data());
0041     exit(1);
0042 }
0043 
0044 static void popArg(QString &command, QString &line)
0045 {
0046     int i = line.indexOf(' ');
0047     if (i != -1) {
0048         command = line.left(i);
0049         line = line.mid(i + 1);
0050     } else {
0051         command = line;
0052         line.clear();
0053     }
0054 }
0055 
0056 static void clearConfig()
0057 {
0058     delete config;
0059     QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + "kcookiejar-testconfig";
0060     QFile::remove(file);
0061     config = new KConfig(file);
0062     KConfigGroup cg(config, "Cookie Policy");
0063     cg.writeEntry("RejectCrossDomainCookies", false);
0064     cg.writeEntry("AcceptSessionCookies", false);
0065     cg.writeEntry("CookieGlobalAdvice", "Ask");
0066     jar->loadConfig(config, false);
0067 }
0068 
0069 static void clearCookies(bool sessionOnly = false)
0070 {
0071     if (sessionOnly) {
0072         jar->eatSessionCookies(windowId);
0073     } else {
0074         jar->eatAllCookies();
0075     }
0076 }
0077 
0078 static void saveCookies()
0079 {
0080     QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + "kcookiejar-testcookies";
0081     QFile::remove(file);
0082     jar->saveCookies(file);
0083 
0084     // Add an empty domain to the cookies file, just for testing robustness
0085     QFile f(file);
0086     f.open(QIODevice::Append);
0087     f.write("[]\n   \"\"   \"/\"    1584320400  0 h  4  x\n");
0088     f.close();
0089 
0090     delete jar;
0091     jar = new KCookieJar();
0092     clearConfig();
0093     jar->loadCookies(file);
0094 }
0095 
0096 static void endSession()
0097 {
0098     jar->eatSessionCookies(windowId);
0099 }
0100 
0101 static void processCookie(QString &line)
0102 {
0103     QString policy;
0104     popArg(policy, line);
0105     KCookieAdvice expectedAdvice = KCookieJar::strToAdvice(policy);
0106     if (expectedAdvice == KCookieDunno) {
0107         FAIL(QStringLiteral("Unknown accept policy '%1'").arg(policy));
0108     }
0109 
0110     QString urlStr;
0111     popArg(urlStr, line);
0112     QUrl url(urlStr);
0113     if (!url.isValid()) {
0114         FAIL(QStringLiteral("Invalid URL '%1'").arg(urlStr));
0115     }
0116     if (url.isEmpty()) {
0117         FAIL(QStringLiteral("Missing URL"));
0118     }
0119 
0120     line.replace(QLatin1String("%LASTYEAR%"), *lastYear);
0121     line.replace(QLatin1String("%NEXTYEAR%"), *nextYear);
0122 
0123     KHttpCookieList list = jar->makeCookies(urlStr, line.toUtf8(), windowId);
0124 
0125     if (list.isEmpty()) {
0126         FAIL(QStringLiteral("Failed to make cookies from: '%1'").arg(line));
0127     }
0128 
0129     for (KHttpCookieList::iterator cookieIterator = list.begin();
0130             cookieIterator != list.end(); ++cookieIterator) {
0131         KHttpCookie &cookie = *cookieIterator;
0132         const KCookieAdvice cookieAdvice = jar->cookieAdvice(cookie);
0133         if (cookieAdvice != expectedAdvice)
0134             FAIL(urlStr + QStringLiteral("\n'%2'\nGot advice '%3' expected '%4'")
0135                  .arg(line, KCookieJar::adviceToStr(cookieAdvice), KCookieJar::adviceToStr(expectedAdvice))
0136                 );
0137         jar->addCookie(cookie);
0138     }
0139 }
0140 
0141 static void processCheck(QString &line)
0142 {
0143     QString urlStr;
0144     popArg(urlStr, line);
0145     QUrl url(urlStr);
0146     if (!url.isValid()) {
0147         FAIL(QStringLiteral("Invalid URL '%1'").arg(urlStr));
0148     }
0149     if (url.isEmpty()) {
0150         FAIL(QStringLiteral("Missing URL"));
0151     }
0152 
0153     QString expectedCookies = line;
0154 
0155     QString cookies = jar->findCookies(urlStr, false, windowId, nullptr).trimmed();
0156     if (cookies != expectedCookies)
0157         FAIL(urlStr + QStringLiteral("\nGot '%1' expected '%2'")
0158              .arg(cookies, expectedCookies));
0159 }
0160 
0161 static void processClear(QString &line)
0162 {
0163     if (line == QLatin1String("CONFIG")) {
0164         clearConfig();
0165     } else if (line == QLatin1String("COOKIES")) {
0166         clearCookies();
0167     } else if (line == QLatin1String("SESSIONCOOKIES")) {
0168         clearCookies(true);
0169     } else {
0170         FAIL(QStringLiteral("Unknown command 'CLEAR %1'").arg(line));
0171     }
0172 }
0173 
0174 static void processConfig(QString &line)
0175 {
0176     QString key;
0177     popArg(key, line);
0178 
0179     if (key.isEmpty()) {
0180         FAIL(QStringLiteral("Missing Key"));
0181     }
0182 
0183     KConfigGroup cg(config, "Cookie Policy");
0184     cg.writeEntry(key, line);
0185     jar->loadConfig(config, false);
0186 }
0187 
0188 static void processLine(QString line)
0189 {
0190     if (line.isEmpty()) {
0191         return;
0192     }
0193 
0194     if (line[0] == '#') {
0195         if (line[1] == '#') {
0196             qDebug("%s", line.toLatin1().constData());
0197         }
0198         return;
0199     }
0200 
0201     QString command;
0202     popArg(command, line);
0203     if (command.isEmpty()) {
0204         return;
0205     }
0206 
0207     if (command == QLatin1String("COOKIE")) {
0208         processCookie(line);
0209     } else if (command == QLatin1String("CHECK")) {
0210         processCheck(line);
0211     } else if (command == QLatin1String("CLEAR")) {
0212         processClear(line);
0213     } else if (command == QLatin1String("CONFIG")) {
0214         processConfig(line);
0215     } else if (command == QLatin1String("SAVE")) {
0216         saveCookies();
0217     } else if (command == QLatin1String("ENDSESSION")) {
0218         endSession();
0219     } else {
0220         FAIL(QStringLiteral("Unknown command '%1'").arg(command));
0221     }
0222 }
0223 
0224 static void runRegression(const QString &filename)
0225 {
0226     FILE *file = QT_FOPEN(QFile::encodeName(filename).constData(), "r");
0227     if (!file) {
0228         FAIL(QStringLiteral("Can't open '%1'").arg(filename));
0229     }
0230 
0231     char buf[4096];
0232     while (fgets(buf, sizeof(buf), file)) {
0233         int l = strlen(buf);
0234         if (l) {
0235             l--;
0236             buf[l] = 0;
0237         }
0238         processLine(QString::fromUtf8(buf));
0239     }
0240     fclose(file);
0241     qDebug("%s OK", filename.toLocal8Bit().data());
0242 }
0243 
0244 class KCookieJarTest : public QObject
0245 {
0246     Q_OBJECT
0247 private Q_SLOTS:
0248     void initTestCase()
0249     {
0250         QStandardPaths::setTestModeEnabled(true);
0251         jar = new KCookieJar;
0252         QDateTime dt = QDateTime::currentDateTime();
0253         lastYear = new QString(dt.addYears(-1).toString(Qt::RFC2822Date));
0254         nextYear = new QString(dt.addYears(1).toString(Qt::RFC2822Date));
0255     }
0256     void testCookieFile_data()
0257     {
0258         QTest::addColumn<QString>("fileName");
0259         QTest::newRow("cookie.test") << QFINDTESTDATA("cookie.test");
0260         QTest::newRow("cookie_rfc.test") << QFINDTESTDATA("cookie_rfc.test");
0261         QTest::newRow("cookie_saving.test") << QFINDTESTDATA("cookie_saving.test");
0262         QTest::newRow("cookie_settings.test") << QFINDTESTDATA("cookie_settings.test");
0263         QTest::newRow("cookie_session.test") << QFINDTESTDATA("cookie_session.test");
0264     }
0265     void testCookieFile()
0266     {
0267         QFETCH(QString, fileName);
0268         clearConfig();
0269         runRegression(fileName);
0270     }
0271 
0272     void testParseUrl_data()
0273     {
0274         QTest::addColumn<QString>("url");
0275         QTest::addColumn<bool>("expectedResult");
0276         QTest::addColumn<QString>("expectedFqdn");
0277         QTest::addColumn<QString>("expectedPath");
0278         QTest::newRow("empty") << "" << false << "" << "";
0279         QTest::newRow("url with no path") << "http://bugs.kde.org" << true << "bugs.kde.org" << "/";
0280         QTest::newRow("url with path") << "http://bugs.kde.org/foo" << true << "bugs.kde.org" << "/foo";
0281         QTest::newRow("just a host") << "bugs.kde.org" << false << "" << "";
0282     }
0283     void testParseUrl()
0284     {
0285         QFETCH(QString, url);
0286         QFETCH(bool, expectedResult);
0287         QFETCH(QString, expectedFqdn);
0288         QFETCH(QString, expectedPath);
0289         QString fqdn;
0290         QString path;
0291         bool result = KCookieJar::parseUrl(url, fqdn, path);
0292         QCOMPARE(result, expectedResult);
0293         QCOMPARE(fqdn, expectedFqdn);
0294         QCOMPARE(path, expectedPath);
0295     }
0296 
0297     void testExtractDomains_data()
0298     {
0299         QTest::addColumn<QString>("fqdn");
0300         QTest::addColumn<QStringList>("expectedDomains");
0301         QTest::newRow("empty") << "" << (QStringList() << QStringLiteral("localhost"));
0302         QTest::newRow("ipv4") << "1.2.3.4" << (QStringList() << QStringLiteral("1.2.3.4"));
0303         QTest::newRow("ipv6") << "[fe80::213:d3ff:fef4:8c92]" << (QStringList() << QStringLiteral("[fe80::213:d3ff:fef4:8c92]"));
0304         QTest::newRow("bugs.kde.org") << "bugs.kde.org" << (QStringList() << QStringLiteral("bugs.kde.org") << QStringLiteral(".bugs.kde.org") << QStringLiteral("kde.org") << QStringLiteral(".kde.org"));
0305 
0306     }
0307     void testExtractDomains()
0308     {
0309         QFETCH(QString, fqdn);
0310         QFETCH(QStringList, expectedDomains);
0311         KCookieJar jar;
0312         QStringList lst;
0313         jar.extractDomains(fqdn, lst);
0314         QCOMPARE(lst, expectedDomains);
0315     }
0316 };
0317 
0318 QTEST_MAIN(KCookieJarTest)
0319 
0320 #include "kcookiejartest.moc"