diff --git a/webenginepart/autotests/webenginepartcookiejar_test.cpp b/webenginepart/autotests/webenginepartcookiejar_test.cpp index 97f674f18..c40d9c250 100644 --- a/webenginepart/autotests/webenginepartcookiejar_test.cpp +++ b/webenginepart/autotests/webenginepartcookiejar_test.cpp @@ -1,358 +1,369 @@ /* * This file is part of the KDE project * Copyright (C) 2018 Stefano Crocco * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "webenginepartcookiejar_test.h" #include #include #include #include #include #include #include #include //Cookie expiration dates returned by KCookieServer always have msecs set to 0 static QDateTime currentDateTime(){return QDateTime::fromSecsSinceEpoch(QDateTime::currentMSecsSinceEpoch()/1000);} namespace QTest { template <> char *toString(const QNetworkCookie &cookie){ QByteArray ba = "QNetworkCookie{"; ba += "\nname: " + cookie.name(); ba += "\ndomain: " + (cookie.domain().isEmpty() ? "" : cookie.domain()); ba += "\npath: " + (cookie.path().isEmpty() ? "" : cookie.path()); ba += "\nvalue: " + cookie.value(); ba += "\nexpiration: " + (cookie.expirationDate().isValid() ? QString::number(cookie.expirationDate().toMSecsSinceEpoch()) : ""); ba += "\nsecure: " + QString::number(cookie.isSecure()); ba += "\nhttp: only" + QString::number(cookie.isHttpOnly()); return qstrdup(ba.data()); } } QTEST_MAIN(TestWebEnginePartCookieJar); void TestWebEnginePartCookieJar::initTestCase() { m_cookieName = "webenginepartcookiejartest"; } void TestWebEnginePartCookieJar::init() { m_server = new QDBusInterface("org.kde.kcookiejar5", "/modules/kcookiejar", "org.kde.KCookieServer"); m_profile = new QWebEngineProfile(this); m_store = m_profile->cookieStore(); m_jar = new WebEnginePartCookieJar(m_profile, this); } void TestWebEnginePartCookieJar::cleanup() { if (m_server->isValid()) { deleteCookies(findTestCookies()); } delete m_server; m_server = nullptr; delete m_jar; m_jar = nullptr; m_store = nullptr; delete m_profile; m_profile = nullptr; } QNetworkCookie TestWebEnginePartCookieJar::CookieData::cookie() const { QNetworkCookie cookie; cookie.setName(name.toUtf8()); cookie.setValue(value.toUtf8()); cookie.setPath(path); cookie.setDomain(domain); cookie.setSecure(secure); cookie.setExpirationDate(expiration); return cookie; } void TestWebEnginePartCookieJar::testCookieAddedToStoreAreAddedToKCookieServer_data() { QTest::addColumn("cookie"); QTest::addColumn("name"); QTest::addColumn("value"); QTest::addColumn("domain"); QTest::addColumn("path"); QTest::addColumn("host"); QTest::addColumn("expiration"); QTest::addColumn("secure"); const QStringList labels{ "persistent cookie with domain and path", "session cookie with domain and path", "persistent cookie with domain and no path", + "persistent cookie with domain and / as path", "persistent cookie with path and no domain", "persistent cookie without secure", }; const QList input{ {m_cookieName + "-persistent", "test-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, {m_cookieName + "-session", "test-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime(), true}, {m_cookieName + "-no-path", "test-value", ".yyy.xxx.com", "", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-slash-as-path", "test-value", ".yyy.xxx.com", "", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, {m_cookieName + "-no-domain", "test-value", "", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, {m_cookieName + "-no-secure", "test-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), false} }; QList expected(input); for (int i = 0; i < input.count(); ++i) { const CookieData &ex = expected.at(i); const CookieData &in = input.at(i); QNetworkCookie c = in.cookie(); if (in.domain.isEmpty()) { c.normalize(QUrl("https://" + in.host)); } QTest::newRow(labels.at(i).toLatin1()) << c << ex.name << ex.value << ex.domain << ex.path << ex.host << ex.expiration << ex.secure; } } void TestWebEnginePartCookieJar::testCookieAddedToStoreAreAddedToKCookieServer() { QFETCH(const QNetworkCookie, cookie); QFETCH(const QString, name); QFETCH(const QString, value); QFETCH(const QString, domain); QFETCH(const QString, path); QFETCH(const QString, host); QFETCH(const QDateTime, expiration); QFETCH(const bool, secure); QVERIFY2(m_server->isValid(), qPrintable(m_server->lastError().message())); // domain=0, path=1, name=2, host=3, value=4, expirationDate=5, protocolVersion=6, secure=7; const QList fields{0,1,2,3,4,5,6,7}; emit m_store->cookieAdded(cookie); const QDBusReply res = m_server->call(QDBus::Block, "findCookies", QVariant::fromValue(fields), domain, host, cookie.path(), QString(cookie.name())); QVERIFY2(!m_server->lastError().isValid(), m_server->lastError().message().toLatin1()); QStringList resFields = res.value(); QVERIFY(!resFields.isEmpty()); QCOMPARE(fields.count(), resFields.count()); QCOMPARE(resFields.at(0), domain); QCOMPARE(resFields.at(1), path); QCOMPARE(resFields.at(2), name); if (!domain.isEmpty()){ QEXPECT_FAIL("", "The value returned by KCookieServer strips the leftmost part of the fqdn. Why?", Continue); } QCOMPARE(resFields.at(3), host); QCOMPARE(resFields.at(4), value); const int secsSinceEpoch = resFields.at(5).toInt(); //KCookieServer gives a session cookie an expiration time equal to epoch, while QNetworkCookie uses an invalid QDateTime if (!expiration.isValid()) { QCOMPARE(secsSinceEpoch, 0); } else { QCOMPARE(secsSinceEpoch, expiration.toSecsSinceEpoch()); } const bool sec = resFields.at(7).toInt(); QCOMPARE(sec, secure); } QList TestWebEnginePartCookieJar::findTestCookies() { QList cookies; if (!m_server->isValid()) { return cookies; } QDBusReply rep = m_server->call(QDBus::Block, "findDomains"); if (!rep.isValid()) { qDebug() << rep.error().message(); return cookies; } QStringList domains = rep.value(); //domain, path, name, host const QList fields{0,1,2,3}; foreach (const QString &d, domains){ rep = m_server->call(QDBus::Block, "findCookies", QVariant::fromValue(fields), d, "", "", ""); if (!rep.isValid()) { qDebug() << rep.error().message(); return cookies; } QStringList res = rep.value(); for (int i = 0; i < res.count(); i+= fields.count()) { if (res.at(i+2).startsWith(m_cookieName)) { CookieData d; d.name = res.at(i+2); d.domain = res.at(i); d.path = res.at(i+1); d.host = res.at(i+3); cookies.append(d); } } } return cookies; } void TestWebEnginePartCookieJar::deleteCookies(const QList &cookies) { if (!m_server->isValid()) { return; } for (const CookieData &c: cookies) { QDBusMessage deleteRep = m_server->call(QDBus::Block, "deleteCookie", c.domain, c.host, c.path, c.name); if (m_server->lastError().isValid()) { qDebug() << m_server->lastError().message(); } } } void TestWebEnginePartCookieJar::testCookieRemovedFromStoreAreRemovedFromKCookieServer_data() { QTest::addColumn("cookie"); QTest::addColumn("name"); QTest::addColumn("domain"); + QTest::addColumn("path"); QTest::addColumn("host"); const QStringList labels{ "remove persistent cookie with domain and path", "remove session cookie with domain and path", "remove persistent cookie with domain and no path", + "remove persistent cookie with domain and / as path", "remove persistent cookie with path and no domain", - "remove persistent cookie without secure", + "remove persistent cookie without secure" }; const QList input{ {m_cookieName + "-persistent-remove", "test-remove-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, {m_cookieName + "-session-remove", "test-remove-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime(), true}, {m_cookieName + "-no-path-remove", "test-remove-value", ".yyy.xxx.com", "", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-slash-as-path-remove", "test-remove-value", ".yyy.xxx.com", "/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, {m_cookieName + "-no-domain-remove", "test-remove-value", "", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, - {m_cookieName + "-no-secure-remove", "test-remove-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), false} + {m_cookieName + "-no-secure-remove", "test-remove-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", QDateTime::currentDateTime().addYears(1), false}, }; QList expected(input); for (int i = 0; i < input.count(); ++i) { const CookieData &ex = expected.at(i); const CookieData &in = input.at(i); QNetworkCookie c = in.cookie(); if (in.domain.isEmpty()) { c.normalize(QUrl("https://" + in.host)); } - QTest::newRow(labels.at(i).toLatin1()) << c << ex.name << ex.domain << ex.host; + QTest::newRow(labels.at(i).toLatin1()) << c << ex.name << ex.domain << ex.path << ex.host; }} void TestWebEnginePartCookieJar::testCookieRemovedFromStoreAreRemovedFromKCookieServer() { QFETCH(const QNetworkCookie, cookie); QFETCH(const QString, name); QFETCH(const QString, domain); + QFETCH(const QString, path); QFETCH(const QString, host); //Add cookie to KCookieServer QDBusError e = addCookieToKCookieServer(cookie, host); QVERIFY2(!e.isValid(), qPrintable(m_server->lastError().message())); + auto findCookies=[this, &domain, &host, &path, &name](){ + QDBusReply reply = m_server->call(QDBus::Block, "findCookies", QVariant::fromValue(QList{2}), domain, host, path, name); + return reply; + }; + //Ensure cookie has been added to KCookieServer - QDBusReply reply = m_server->call(QDBus::Block, "findCookies", QVariant::fromValue(QList{2}), domain, host, "", ""); + QDBusReply reply = findCookies(); QVERIFY2(reply.isValid(), qPrintable(reply.error().message())); - QStringList cookies = reply.value(); - QVERIFY2(cookies.contains(name), "Cookie wasn't added to server"); - + QVERIFY2(reply.value().contains(name), "Cookie wasn't added to server"); + //Emit QWebEngineCookieStore::cookieRemoved signal and check that cookie has indeed been removed emit m_store->cookieRemoved(cookie); - reply = m_server->call(QDBus::Block, "findCookies", QVariant::fromValue(QList{2}), domain, "", "", ""); + + //Check that cookie is no longer in KCookieServer + reply = findCookies(); QVERIFY2(reply.isValid(), qPrintable(reply.error().message())); - cookies = reply.value(); - QVERIFY2(!cookies.contains(name), "Cookie wasn't removed from server"); + QVERIFY2(!reply.value().contains(name), "Cookie wasn't removed from server"); } QDBusError TestWebEnginePartCookieJar::addCookieToKCookieServer(const QNetworkCookie& _cookie, const QString& host) { QNetworkCookie cookie(_cookie); QUrl url; url.setHost(host); url.setScheme(cookie.isSecure() ? "https" : "http"); if (!cookie.domain().startsWith('.')) { cookie.setDomain(QString()); } const QByteArray setCookie = "Set-Cookie: " + cookie.toRawForm(); m_server->call(QDBus::Block, "addCookies", url.toString(), setCookie, static_cast(0)); return m_server->lastError(); } void TestWebEnginePartCookieJar::testPersistentCookiesAreAddedToStoreOnCreation() { delete m_jar; QDateTime exp = QDateTime::currentDateTime().addYears(1); QString baseCookieName = m_cookieName + "-startup"; QList data { {baseCookieName + "-persistent", "test-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", currentDateTime().addYears(1), true}, {baseCookieName + "-no-path", "test-value", ".yyy.xxx.com", "", "zzz.yyy.xxx.com", currentDateTime().addYears(1), true}, {baseCookieName + "-no-domain", "test-value", "", "/abc/def/", "zzz.yyy.xxx.com", currentDateTime().addYears(1), true}, {baseCookieName + "-no-secure", "test-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", currentDateTime().addYears(1), false} }; QList expected; for(const CookieData &d: data){ QNetworkCookie c = d.cookie(); QDBusError e = addCookieToKCookieServer(c, d.host); QVERIFY2(!e.isValid(), qPrintable(e.message())); //In case of an empty domain, WebEnginePartCookieJar will use QNetworkCookie::normalize on the cookie if (c.domain().isEmpty()) { c.setDomain(d.host); } expected << c; } m_jar = new WebEnginePartCookieJar(m_profile, this); QList cookiesInsertedIntoJar; for(const QNetworkCookie &c: qAsConst(m_jar->m_testCookies)){ if(QString(c.name()).startsWith(baseCookieName)) { cookiesInsertedIntoJar << c; } } //Ensure that cookies in the two lists are in the same order before comparing them //(the order in cookiesInsertedIntoJar depends on the order KCookieServer::findCookies //returns them) auto sortLambda = [](const QNetworkCookie &c1, const QNetworkCookie &c2){ return c1.name() < c2.name(); }; std::sort(cookiesInsertedIntoJar.begin(), cookiesInsertedIntoJar.end(), sortLambda); std::sort(expected.begin(), expected.end(), sortLambda); QCOMPARE(cookiesInsertedIntoJar, expected); } void TestWebEnginePartCookieJar::testSessionCookiesAreNotAddedToStoreOnCreation() { delete m_jar; CookieData data{m_cookieName + "-startup-session", "test-value", ".yyy.xxx.com", "/abc/def", "zzz.yyy.xxx.com", QDateTime(), true}; QDBusError e = addCookieToKCookieServer(data.cookie(), data.host); QVERIFY2(!e.isValid(), qPrintable(e.message())); m_jar = new WebEnginePartCookieJar(m_profile, this); QList cookiesInsertedIntoJar; for(const QNetworkCookie &c: qAsConst(m_jar->m_testCookies)) { if (c.name() == data.name) { cookiesInsertedIntoJar << c; } } QVERIFY2(cookiesInsertedIntoJar.isEmpty(), "Session cookies inserted into cookie store"); } diff --git a/webenginepart/src/webenginepartcookiejar.cpp b/webenginepart/src/webenginepartcookiejar.cpp index 381c4afaa..9f53ca8bd 100644 --- a/webenginepart/src/webenginepartcookiejar.cpp +++ b/webenginepart/src/webenginepartcookiejar.cpp @@ -1,355 +1,355 @@ /* * This file is part of the KDE project. * * Copyright (C) 2018 Stefano Crocco * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "webenginepartcookiejar.h" #include "settings/webenginesettings.h" #include #include #include #include #include #include #include #include #include #include #include #include const QVariant WebEnginePartCookieJar::s_findCookieFields = QVariant::fromValue(QList{ static_cast(CookieDetails::domain), static_cast(CookieDetails::path), static_cast(CookieDetails::name), static_cast(CookieDetails::host), static_cast(CookieDetails::value), static_cast(CookieDetails::expirationDate), static_cast(CookieDetails::protocolVersion), static_cast(CookieDetails::secure) } ); WebEnginePartCookieJar::CookieIdentifier::CookieIdentifier(const QNetworkCookie& cookie): name(cookie.name()), domain(cookie.domain()), path(cookie.path()) { } WebEnginePartCookieJar::CookieIdentifier::CookieIdentifier(const QString& n, const QString& d, const QString& p): name(n), domain(d), path(p) { } WebEnginePartCookieJar::WebEnginePartCookieJar(QWebEngineProfile *prof, QObject *parent): QObject(parent), m_cookieStore(prof->cookieStore()), m_cookieServer("org.kde.kcookiejar5", "/modules/kcookiejar", "org.kde.KCookieServer") { prof->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); connect(qApp, &QApplication::lastWindowClosed, this, &WebEnginePartCookieJar::deleteSessionCookies); connect(m_cookieStore, &QWebEngineCookieStore::cookieAdded, this, &WebEnginePartCookieJar::addCookie); connect(m_cookieStore, &QWebEngineCookieStore::cookieRemoved, this, &WebEnginePartCookieJar::removeCookie); if(!m_cookieServer.isValid()){ qCDebug(WEBENGINEPART_LOG) << "Couldn't connect to KCookieServer"; } loadKIOCookies(); //QWebEngineCookieStore::setCookieFilter only exists from Qt 5.11.0 #if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) auto filter = [this](const QWebEngineCookieStore::FilterRequest &req){return filterCookie(req);}; m_cookieStore->setCookieFilter(filter); #endif //QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) } WebEnginePartCookieJar::~WebEnginePartCookieJar() { } #if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) bool WebEnginePartCookieJar::filterCookie(const QWebEngineCookieStore::FilterRequest& req) { return WebEngineSettings::self()->acceptCrossDomainCookies() || !req.thirdParty; } #endif //QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) void WebEnginePartCookieJar::deleteSessionCookies() { if (!m_cookieServer.isValid()) { return; } foreach(qlonglong id, m_windowsWithSessionCookies) { m_cookieServer.call(QDBus::NoBlock, "deleteSessionCookies", id); } } QUrl WebEnginePartCookieJar::constructUrlForCookie(const QNetworkCookie& cookie) const { QUrl url; QString domain = cookie.domain().startsWith(".") ? cookie.domain().mid(1) : cookie.domain(); if (!domain.isEmpty()) { url.setScheme("http"); url.setHost(domain); url.setPath(cookie.path()); } else { qCDebug(WEBENGINEPART_LOG) << "EMPTY COOKIE DOMAIN for" << cookie.name(); } return url; } qlonglong WebEnginePartCookieJar::findWinID() { QWidget *mainWindow = qApp->activeWindow(); if (mainWindow && !(mainWindow->windowFlags() & Qt::Dialog)) { return mainWindow->winId(); } else { QWidgetList windows = qApp->topLevelWidgets(); foreach(QWidget *w, windows){ if (w->isWindow() && !(w->windowFlags() & Qt::Dialog)) { return w->winId(); } } } return 0; } void WebEnginePartCookieJar::removeCookieDomain(QNetworkCookie& cookie) { if (!cookie.domain().startsWith('.')) { cookie.setDomain(QString()); } } void WebEnginePartCookieJar::addCookie(const QNetworkCookie& _cookie) { //If the added cookie is in m_cookiesLoadedFromKCookieServer, it means //we're loading the cookie from KCookieServer (from the call to loadKIOCookies //in the constructor (QWebEngineCookieStore::setCookie is asynchronous, though, //so we're not in the constructor anymore)), so don't attempt to add //the cookie back to KCookieServer; instead, remove it from the list. if (m_cookiesLoadedFromKCookieServer.removeOne(_cookie)) { return; } #ifdef BUILD_TESTING m_testCookies.clear(); #endif QNetworkCookie cookie(_cookie); CookieIdentifier id(cookie); if (!m_cookieServer.isValid()) { return; } if (cookie.expirationDate().isValid()) { //There's a bug in KCookieJar which causes the expiration date to be interpreted as local time //instead of GMT as it should. The bug is fixed in KIO 5.50 #if KIO_VERSION < QT_VERSION_CHECK(5,50,0) QTimeZone local = QTimeZone::systemTimeZone(); int offset = local.offsetFromUtc(QDateTime::currentDateTime()); QDateTime dt = cookie.expirationDate(); dt.setTime(dt.time().addSecs(offset)); cookie.setExpirationDate(dt); #endif } QUrl url = constructUrlForCookie(cookie); if (url.isEmpty()) { return; } //NOTE: the removal of the domain (when not starting with a dot) must be done *after* creating //the URL, as constructUrlForCookie needs the domain removeCookieDomain(cookie); QByteArray header("Set-Cookie: "); header += cookie.toRawForm(); header += "\n"; qlonglong winId = findWinID(); if (!cookie.expirationDate().isValid()) { m_windowsWithSessionCookies.insert(winId); } // qCDebug(WEBENGINEPART_LOG) << url; QString advice = askAdvice(url); if (advice == "Reject"){ m_pendingRejectedCookies << CookieIdentifier(_cookie); m_cookieStore->deleteCookie(_cookie); } else if (advice == "AcceptForSession" && !cookie.isSessionCookie()) { cookie.setExpirationDate(QDateTime()); addCookie(cookie); } else { int oldTimeout = m_cookieServer.timeout(); if (advice == "Ask") { //Give the user time (10 minutes = 600 000ms) to analyze the cookie m_cookieServer.setTimeout(10*60*1000); } m_cookieServer.call(QDBus::Block, "addCookies", url.toString(), header, winId); m_cookieServer.setTimeout(oldTimeout); if (m_cookieServer.lastError().isValid()) { qCDebug(WEBENGINEPART_LOG) << m_cookieServer.lastError(); return; } if (!advice.startsWith("Accept") && !cookieInKCookieJar(id, url)) { m_pendingRejectedCookies << id; m_cookieStore->deleteCookie(_cookie); } } } QString WebEnginePartCookieJar::askAdvice(const QUrl& url) { if (!m_cookieServer.isValid()) { return QString(); } QDBusReply rep = m_cookieServer.call(QDBus::Block, "getDomainAdvice", url.toString()); if (rep.isValid()) { return rep.value(); } else { qCDebug(WEBENGINEPART_LOG) << rep.error().message(); return QString(); } } bool WebEnginePartCookieJar::cookieInKCookieJar(const WebEnginePartCookieJar::CookieIdentifier& id, const QUrl& url) { if (!m_cookieServer.isValid()) { return false; } QList fields = { static_cast(CookieDetails::name), static_cast(CookieDetails::domain), static_cast(CookieDetails::path) }; QDBusReply rep = m_cookieServer.call(QDBus::Block, "findCookies", QVariant::fromValue(fields), id.domain, url.toString(QUrl::FullyEncoded), id.path, id.name); if (!rep.isValid()) { qCDebug(WEBENGINEPART_LOG) << rep.error().message(); return false; } QStringList cookies = rep.value(); for(int i = 0; i < cookies.length()-2; i+=3){ if (CookieIdentifier(cookies.at(i), cookies.at(i+1), cookies.at(i+2)) == id) { return true; } } return false; } void WebEnginePartCookieJar::removeCookie(const QNetworkCookie& _cookie) { int pos = m_pendingRejectedCookies.indexOf(CookieIdentifier(_cookie)); //Ignore pending cookies if (pos >= 0) { m_pendingRejectedCookies.takeAt(pos); return; } if (!m_cookieServer.isValid()) { return; } QNetworkCookie cookie(_cookie); QUrl url = constructUrlForCookie(cookie); if(url.isEmpty()){ qCDebug(WEBENGINEPART_LOG) << "Can't remove cookie" << cookie.name() << "because its URL isn't known"; return; } removeCookieDomain(cookie); - QDBusPendingCall pcall = m_cookieServer.asyncCall("deleteCookie", cookie.domain(), url.toString(), cookie.path(), QString(cookie.name())); + QDBusPendingCall pcall = m_cookieServer.asyncCall("deleteCookie", cookie.domain(), url.host(), cookie.path(), QString(cookie.name())); QDBusPendingCallWatcher *w = new QDBusPendingCallWatcher(pcall, this); connect(w, &QDBusPendingCallWatcher::finished, this, &WebEnginePartCookieJar::cookieRemovalFailed); } void WebEnginePartCookieJar::cookieRemovalFailed(QDBusPendingCallWatcher *watcher) { QDBusPendingReply<> r = *watcher; if (r.isError()){ qCDebug(WEBENGINEPART_LOG) << "DBus error:" << r.error().message(); } watcher->deleteLater(); } void WebEnginePartCookieJar::loadKIOCookies() { CookieList cookies = findKIOCookies(); foreach(const QNetworkCookie& cookie, cookies){ QDateTime currentTime = QDateTime::currentDateTime(); //Don't attempt to add expired cookies if (cookie.expirationDate().isValid() && cookie.expirationDate() < currentTime) { continue; } m_cookiesLoadedFromKCookieServer << cookie; #ifdef BUILD_TESTING m_testCookies << cookie; #endif m_cookieStore->setCookie(cookie); } } WebEnginePartCookieJar::CookieList WebEnginePartCookieJar::findKIOCookies() { CookieList res; if (!m_cookieServer.isValid()) { return res; } QDBusReply rep = m_cookieServer.call(QDBus::Block, "findDomains"); if(!rep.isValid()){ qCDebug(WEBENGINEPART_LOG) << rep.error().message(); return res; } QStringList domains = rep.value(); uint fieldsCount = 8; foreach( const QString &d, domains){ QDBusReply rep = m_cookieServer.call(QDBus::Block, "findCookies", s_findCookieFields, d, "", "", ""); if (!rep.isValid()) { qCDebug(WEBENGINEPART_LOG) << rep.error().message(); return res; } QStringList data = rep.value(); for(int i = 0; i < data.count(); i+=fieldsCount){ res << parseKIOCookie(data, i); } } return res; } QNetworkCookie WebEnginePartCookieJar::parseKIOCookie(const QStringList& data, int start) { QNetworkCookie c; auto extractField = [data, start](CookieDetails field){return data.at(start + static_cast(field));}; - c.setDomain(data.at(start+static_cast(CookieDetails::domain)).toUtf8()); + c.setDomain(extractField(CookieDetails::domain).toUtf8()); c.setExpirationDate(QDateTime::fromSecsSinceEpoch(extractField(CookieDetails::expirationDate).toInt())); c.setName(extractField(CookieDetails::name).toUtf8()); c.setPath(extractField(CookieDetails::path).toUtf8()); c.setSecure(extractField(CookieDetails::secure).toInt()); //1 for true, 0 for false c.setValue(extractField(CookieDetails::value).toUtf8()); if (c.domain().isEmpty()) { QString host = extractField(CookieDetails::host); QUrl url; url.setScheme(c.isSecure() ? "https" : "http"); url.setHost(host); c.normalize(url); } return c; } QDebug operator<<(QDebug deb, const WebEnginePartCookieJar::CookieIdentifier& id) { QDebugStateSaver saver(deb); deb << "(" << id.name << "," << id.domain << "," << id.path << ")"; return deb; }