diff --git a/webenginepart/src/CMakeLists.txt b/webenginepart/src/CMakeLists.txt --- a/webenginepart/src/CMakeLists.txt +++ b/webenginepart/src/CMakeLists.txt @@ -17,6 +17,7 @@ webengineparterrorschemehandler.cpp webengineparthtmlembedder.cpp webenginepartkiohandler.cpp + webenginepartcookiejar.cpp settings/webenginesettings.cpp settings/webengine_filter.cpp ui/searchbar.cpp diff --git a/webenginepart/src/settings/webenginesettings.h b/webenginepart/src/settings/webenginesettings.h --- a/webenginepart/src/settings/webenginesettings.h +++ b/webenginepart/src/settings/webenginesettings.h @@ -111,6 +111,9 @@ // CookieJar... bool isCookieJarEnabled() const; + + // Cross domain cookies + bool acceptCrossDomainCookies() const; // Password storage... bool isNonPasswordStorableSite(const QString &host) const; diff --git a/webenginepart/src/settings/webenginesettings.cpp b/webenginepart/src/settings/webenginesettings.cpp --- a/webenginepart/src/settings/webenginesettings.cpp +++ b/webenginepart/src/settings/webenginesettings.cpp @@ -103,6 +103,7 @@ bool m_accessKeysEnabled : 1; bool m_zoomTextOnly : 1; bool m_useCookieJar : 1; + bool m_acceptCrossDomainCookies : 1; bool m_bAutoRefreshPage: 1; bool m_bEnableFavicon:1; bool m_disableInternalPluginHandling:1; @@ -1175,6 +1176,12 @@ return d->m_useCookieJar; } +bool WebEngineSettings::acceptCrossDomainCookies() const +{ + return d->m_acceptCrossDomainCookies; +} + + // Password storage... static KConfigGroup nonPasswordStorableSitesCg(KSharedConfig::Ptr& configPtr) { @@ -1257,6 +1264,7 @@ KSharedConfig::Ptr cookieCfgPtr = KSharedConfig::openConfig(QStringLiteral("kcookiejarrc"), KConfig::NoGlobals); KConfigGroup cookieCfg ( cookieCfgPtr, "Cookie Policy"); d->m_useCookieJar = cookieCfg.readEntry("Cookies", false); + d->m_acceptCrossDomainCookies = !cookieCfg.readEntry("RejectCrossDomainCookies", true); } void WebEngineSettings::initNSPluginSettings() diff --git a/webenginepart/src/webenginepage.cpp b/webenginepart/src/webenginepage.cpp --- a/webenginepart/src/webenginepage.cpp +++ b/webenginepart/src/webenginepage.cpp @@ -185,7 +185,7 @@ bool WebEnginePage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame) { - qDebug() << url << "type=" << type; +// qDebug() << url << "type=" << type; QUrl reqUrl(url); // Handle "mailto:" url here... diff --git a/webenginepart/src/webenginepart.cpp b/webenginepart/src/webenginepart.cpp --- a/webenginepart/src/webenginepart.cpp +++ b/webenginepart/src/webenginepart.cpp @@ -37,6 +37,7 @@ #include "webhistoryinterface.h" #include "webenginewallet.h" #include "webengineparterrorschemehandler.h" +#include "webenginepartcookiejar.h" #include "ui/searchbar.h" #include "ui/passwordbar.h" @@ -93,6 +94,7 @@ prof->installUrlSchemeHandler("error", new WebEnginePartErrorSchemeHandler(prof)); prof->installUrlSchemeHandler("help", new WebEnginePartKIOHandler(prof)); } + static WebEnginePartCookieJar s_cookieJar(prof, prof); KAboutData about = KAboutData(QStringLiteral("webenginepart"), i18nc("Program Name", "WebEnginePart"), /*version*/ QStringLiteral("1.3.0"), diff --git a/webenginepart/src/webenginepartcookiejar.h b/webenginepart/src/webenginepartcookiejar.h new file mode 100644 --- /dev/null +++ b/webenginepart/src/webenginepartcookiejar.h @@ -0,0 +1,321 @@ +/* + * 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. + * + */ + +#ifndef WEBENGINEPARTCOOKIEJAR_H +#define WEBENGINEPARTCOOKIEJAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QWidget; +class QWebEngineProfile; + +/** + * @brief Class which takes care of synchronizing Chromium cookies from `QWebEngineCookieStore` with KIO + */ +class WebEnginePartCookieJar : public QObject +{ + Q_OBJECT + +public: + + /** + * @brief Constructor + * + * @param [in,out] prof the profile containig the store to synchronize with + * @param view the view associated with the store. Its only purpose is to obtain the `WinID` for the DBus call to `addCookies` + * @param parent the parent object + * @note The `PersistentCookiePolicy` of the given profile will be set to `NoPersistentCookies` so that, on application startup, + * only cookies from KIO will be inside the store + */ + WebEnginePartCookieJar(QWebEngineProfile* prof, QObject* parent = Q_NULLPTR); + + /** + * @brief Destructor + */ + ~WebEnginePartCookieJar(); + +private slots: + + /** + * @brief Adds a cookie to KIO + * + * This slot is called in response to `QWebEngineCookieStore::cookieAdded` signal. + * + * @param cookie cookie the cookie to add + * + * @internal KIO requires an URL when adding a cookie; unfortunately, the `cookieAdded` signal doesn't provide one. To solve this problem, an URL is created + * by using the scheme of #m_lastRequestOrigin and the cookie's domain. Looking At the source code for `KCookieJar`, an URL built this way should work. + * In case the cookie's domain is empty (which I believe shouldn't happen), #m_lastRequestOrigin is used. + * + * This function also adds the cookie and its corresponding URL to #m_cookiesUrl + */ + void addCookie(const QNetworkCookie &cookie); + + /** + * @brief Removes the given cookie from KIO + * + * This slot is called in response to `QWebEngineCookieStore::cookieRemoved` signal. + * + * @param cookie the cookie to remove + * + * @internal As for addCookie() there's a problem here, because `QWebEngineCookieStore::cookieRemoved` doesn't provide a fqdn for the cookie. This value is obtained + * from #m_cookiesUrl. + */ + void removeCookie(const QNetworkCookie &cookie); + + /** + * @brief Removes all session cookies from `KCookieJar` + * + * This function doesn't remove cookies from the `QWebEngineCookieStore`, because it's meant to be called + * when the application is closing, so those cookies will be destroied automatically (because they're only stored + * in memory) + * + */ + void deleteSessionCookies(); + +private: + + /** + * @brief Determine the window ID to pass to `KCookieServer::addCookies` + * + * There's no sure way to find the window which received a cookie, so this function chooses the active window + * if there's one (according to `QApplication::activeWindow`) or the first widget in `QApplication::topLevelWidgets` + * for which `QWidget::isWindow` is `true` and which doesn't have a parent. + * + * @return the ID of the window determined as described above or 0 if no such a window can be found + */ + static qlonglong findWinID(); + + using CookieList = QList; + + /** + * @brief An identifier for a cookie + * + * The identifier is made by the cookie's name, domain and path + */ + struct CookieIdentifier{ + + /** + * @brief Default constructor + */ + CookieIdentifier(){} + + /** + * @brief Constructor + * + * @param cookie the cookie to create the identifier for + */ + CookieIdentifier(const QNetworkCookie &cookie); + + /** + * @brief Constructor + * + * @param n the cookie's name + * @param d the cookie's domain + * @param p the cookie's path + */ + CookieIdentifier(const QString &n, const QString &d, const QString &p); + + /** + * Comparison operator + * + * Two cookies are equal if all their fields are equal + * @param other the identifier to compare this identifier to + * @return `true` if the two identifiers' name, domain and path are equal and `false` if at least one of them is different + */ + bool operator== (const CookieIdentifier &other) const {return name == other.name && domain == other.domain && path == other.path;} + + /** + * @brief The name of the cookie + * + */ + QString name; + /** + * @brief The domain of the cookie + * + */ + QString domain; + + /** + * @brief The path of the cookie + * + */ + QString path; + + }; + + friend QDebug operator<<(QDebug, const CookieIdentifier &); + + using CookieIdentifierList = QList; + + /** + * @brief Checks whether a cookie with the given identifier is in the KCookieJar + * + * @note If the _id_'s domain doesn't start with a dot, a dot is prepended to it. This is because + * `KCookieJar` always wants a dot in front of the domain. + * + * @param id the identifiere of the cookie + * @param url the origin of the cookie + * @return `true` if a cookie with the given identifier is in the KCookieJar and `false` otherwise + */ + bool cookieInKCookieJar(const CookieIdentifier &id, const QUrl &url); + + /** + * @brief The advice from `KCookieJar` for a URL + * + * @param url The URL to get the advice for + * @return The advice for _url_. It can be one of `"Accept"`, `"AcceptForSession"`, `"Reject"`, `"Ask"`, `"Dunno"` or an empty + * string if an error happens while contacting the `KCookieServer` + */ + QString askAdvice(const QUrl &url); + + /** + * @brief Inserts all cookies contained in `KCookieJar` to the store + * + * @note this function should only be called by the constructor + * @note this function is asynchronous because it calls `QWebEngineCookieStore::setCookie` + */ + void loadKIOCookies(); + + /** + * @brief Finds all cookies stored in `KCookieJar` + * @return a list of the cookies in `KCookieJar` + */ + CookieList findKIOCookies(); + + /** + * @brief Enum describing the possible fields to pas to `KCookieServer::findCookies` using DBus. + * + * The values are the same as those of `CookieDetails` in `kio/src/kioslaves/http/kcookiejar/kcookieserver.cpp` + */ + enum class CookieDetails {domain=0, path=1, name=2, host=3, value=4, expirationDate=5, protocolVersion=6, secure=7}; + + /** + * @brief Parses the value returned by `KCookieServer::findCookies` for a single cookie + * + * This function assumes that all possible data for the cookie is availlable (that is, that the list returned by + * `KCookieServer::findCookies` contains an entry for each value in #CookieDetails) + * + * @param data: the data returned by `KCookieServer::findCookies`. It can contain data for more than one cookie, but only one will be parsed + * @param start: the position in the list where the data for the cookie starts. + * @return The cookie described by the data and its host + */ + static QNetworkCookie parseKIOCookie(const QStringList &data, int start); + + /** + * @brief Function used to filter cookies + * + * In theory, this function should use the configuration chosen by the user in the Cookies KCM. However, this can't be done for several reasons: + * - this function doesn't have the cookies details availlable and they're needed for the "Ask" policy + * - this function doesn't know the URL of the cookie (even if `QWebEngineCookieStore::FilterRequest::origin` could be used as a substitute + * - if the policy is "Ask" and the question was asked here, it would be asked again when adding the cookie to `KCookieJar`. + * Because of these reasons, the only setting from the KCM which is applied here is whether to accept and reject cross domain cookies. Other settings + * from the KCM will be enforced by the addCookies(). + * + * @param req the request to filter + * @return ``false` for third party cookies if the user chose to block them in the KCM and `true` otherwise + * @internal Besides filtering cookie requests, this function also stores the `origin` member of request in the #m_lastRequestOrigin. + * @endinternal + * @sa addCookie() + */ + bool filterCookie(const QWebEngineCookieStore::FilterRequest &req); + + /** + * @brief Adds a dot in front of a domain if it's not already there + * + * @param dom the domain + * @return `dom` if it already starts with a dot and `dom` preceeded by a dot otherwise + * + * @internal + * This function is needed because KCookieJar prepends a dot to all domains not starting with one (according + * to `KCookieJar::makeCookies` in `kcookiejar.cpp`) + */ + static inline QString prependDotToDomain(const QString &dom) {return dom.startsWith(".") ? dom : "." + dom;} + + QUrl constructUrlForCookie(const QNetworkCookie &cookie) const; + + /** + * @brief The `QWebEngineCookieStore` to synchronize KIO with + */ + QWebEngineCookieStore* m_cookieStore; + + /** + * @brief The DBus interface used to connect to KCookieServer + */ + QDBusInterface m_cookieServer; + + /** + * @brief The fields to pass to `KCookieStore::findCookies` via DBus + */ + static const QVariant s_findCookieFields; + + /** + * @brief Overload of `qHash` for a #CookieIdentifier + * + * @param id: the other identifier + * @param seed: the seed + * @return The hash value of the identifier + */ + friend uint qHash(const CookieIdentifier &id, uint seed){return qHash(QStringList{id.name, id.domain, id.path}, seed);}; + + /** + * @brief A list of cookies which were added to to the `QWebEngineCookieStore` but were rejected by KCookieJar and must + * be removed from the store + * + * When cookieRemoved() is called with one of those cookies, the cookie is removed from this list and no attempt is made to remove + * the cookie from `KCookieJar` (because it's not there) + */ + QVector m_pendingRejectedCookies; + + /** + * @brief The IDs of all the windows which have session cookies + */ + QSet m_windowsWithSessionCookies; + + /** + * @brief A list of cookies loaded from KCookieServer when this instance is created + */ + CookieList m_cookiesLoadedFromKCookieServer; + +}; + +/** +* @brief Overload of operator `<<` to allow a WebEnginePartCookieJar::CookieIdentifier to be written to a `QDebug` +* +* @param deb: the debug object +* @param id: the identifier to write +* @return the debug object +*/ +QDebug operator<<(QDebug deb, const WebEnginePartCookieJar::CookieIdentifier &id); + +#endif // WEBENGINEPARTCOOKIEJAR_H diff --git a/webenginepart/src/webenginepartcookiejar.cpp b/webenginepart/src/webenginepartcookiejar.cpp new file mode 100644 --- /dev/null +++ b/webenginepart/src/webenginepartcookiejar.cpp @@ -0,0 +1,324 @@ +/* + * 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.h" +#include "settings/webenginesettings.h" + +#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()){ + qDebug() << "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() +{ +} + +bool WebEnginePartCookieJar::filterCookie(const QWebEngineCookieStore::FilterRequest& req) +{ + return WebEngineSettings::self()->acceptCrossDomainCookies() || !req.thirdParty; +} + +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 { + qDebug() << "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::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; + } + + 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) + QDateTime dt = cookie.expirationDate(); + dt.setTimeZone(QTimeZone("GMT")); + cookie.setExpirationDate(dt); +#endif + } + QUrl url = constructUrlForCookie(cookie); + if (url.isEmpty()) { + return; + } + QByteArray header("Set-Cookie: "); + header += cookie.toRawForm(); + header += "\n"; + qlonglong winId = findWinID(); + if (!cookie.expirationDate().isValid()) { + m_windowsWithSessionCookies.insert(winId); + } +// qDebug() << 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()) { + qDebug() << 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 { + qDebug() << rep.error().message(); + return QString(); + } +} + +bool WebEnginePartCookieJar::cookieInKCookieJar(const WebEnginePartCookieJar::CookieIdentifier& _id, const QUrl& url) +{ + if (!m_cookieServer.isValid()) { + return false; + } + CookieIdentifier id(_id.name, prependDotToDomain(_id.domain), _id.path); + 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()) { + qDebug() << 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) +{ + CookieIdentifier id(cookie); + + int pos = m_pendingRejectedCookies.indexOf(id); + //Ignore pending cookies + if (pos >= 0) { + m_pendingRejectedCookies.takeAt(pos); + return; + } + + if (!m_cookieServer.isValid()) { + return; + } + + QUrl url = constructUrlForCookie(cookie); + if(url.isEmpty()){ + qDebug() << "Can't remove cookie" << cookie.name() << "because its URL isn't known"; + return; + } + + //Add leading dot to domain, if necessary + id.domain = prependDotToDomain(id.domain); + + m_cookieServer.call(QDBus::NoBlock, "deleteCookie", cookie.domain(), url.host().toLower(), cookie.path(), cookie.name()); + if (m_cookieServer.lastError().isValid()) { + qDebug() << m_cookieServer.lastError(); + } +} + +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; + 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()){ + qDebug() << 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()) { + qDebug() << 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.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()); + return c; +} + +QDebug operator<<(QDebug deb, const WebEnginePartCookieJar::CookieIdentifier& id) +{ + QDebugStateSaver saver(deb); + deb << "(" << id.name << "," << id.domain << "," << id.path << ")"; + return deb; +} diff --git a/webenginepart/src/webenginepartdownloadmanager.cpp b/webenginepart/src/webenginepartdownloadmanager.cpp --- a/webenginepart/src/webenginepartdownloadmanager.cpp +++ b/webenginepart/src/webenginepartdownloadmanager.cpp @@ -77,7 +77,7 @@ void WebEnginePartDownloadManager::recordNavigationRequest(WebEnginePage *page, const QUrl& url) { - qDebug() << url; +// qDebug() << url; m_requests.insert(url, page); } diff --git a/webenginepart/src/webenginepartfactory.cpp b/webenginepart/src/webenginepartfactory.cpp --- a/webenginepart/src/webenginepartfactory.cpp +++ b/webenginepart/src/webenginepartfactory.cpp @@ -24,7 +24,6 @@ #include - WebEngineFactory::~WebEngineFactory() { // kDebug() << this;