diff --git a/webenginepart/autotests/webenginepartcookiejar_test.h b/webenginepart/autotests/webenginepartcookiejar_test.h --- a/webenginepart/autotests/webenginepartcookiejar_test.h +++ b/webenginepart/autotests/webenginepartcookiejar_test.h @@ -37,35 +37,42 @@ class TestWebEnginePartCookieJar : public QObject { Q_OBJECT - + private: - + struct CookieData { QString name; QString value; QString domain; QString path; QString host; QDateTime expiration; bool secure; - + QNetworkCookie cookie() const; }; - + private Q_SLOTS: void init(); void initTestCase(); void cleanup(); + void testConstructUrlForCookieNoOrigin_data(); + void testConstructUrlForCookieNoOrigin(); + void testConstructUrlForCookieOrigin(); void testCookieAddedToStoreAreAddedToKCookieServer_data(); void testCookieAddedToStoreAreAddedToKCookieServer(); + void testCookieAddedToStoreAreAddedToKCookieServerUsingFilterCookie_data(); + void testCookieAddedToStoreAreAddedToKCookieServerUsingFilterCookie(); void testCookieRemovedFromStoreAreRemovedFromKCookieServer_data(); void testCookieRemovedFromStoreAreRemovedFromKCookieServer(); void testPersistentCookiesAreAddedToStoreOnCreation(); void testSessionCookiesAreNotAddedToStoreOnCreation(); - + private: - + + static QUrl constructUrl(const QString &scheme, const QString& host, const QString& path); + /** * @brief Adds a cookie to KCookieServer * @@ -80,7 +87,7 @@ QDBusError addCookieToKCookieServer(const QNetworkCookie &_cookie, const QString &host); void deleteCookies(const QList &cookies); QList findTestCookies(); - + QString m_cookieName; QWebEngineCookieStore *m_store; WebEnginePartCookieJar *m_jar; diff --git a/webenginepart/autotests/webenginepartcookiejar_test.cpp b/webenginepart/autotests/webenginepartcookiejar_test.cpp --- a/webenginepart/autotests/webenginepartcookiejar_test.cpp +++ b/webenginepart/autotests/webenginepartcookiejar_test.cpp @@ -33,7 +33,7 @@ #include #include - + //Cookie expiration dates returned by KCookieServer always have msecs set to 0 static QDateTime currentDateTime(){return QDateTime::fromSecsSinceEpoch(QDateTime::currentMSecsSinceEpoch()/1000);} @@ -52,6 +52,16 @@ } } +QUrl TestWebEnginePartCookieJar::constructUrl(const QString& scheme, const QString& host, const QString& path) +{ + QUrl url; + url.setScheme(scheme); + url.setHost(host); + url.setPath(path); + return url; +} + + QTEST_MAIN(TestWebEnginePartCookieJar); void TestWebEnginePartCookieJar::initTestCase() @@ -93,6 +103,59 @@ return cookie; } +//This test assumes that cookies are in the format used by QWebEngineCookieStore, that is: +//* the domain is never empty +//* if the Set-Cookie header didn't include a domain entry, domain() returns a string not starting with a dot +//* if the Set-Cookie header included a domain entry, QNetworkCookie::domain() returns a string starting with a dot +//* the domain() never returns an empty string +void TestWebEnginePartCookieJar::testConstructUrlForCookieNoOrigin_data() +{ + QTest::addColumn("cookie"); + QTest::addColumn("exp_url"); + + const QStringList labels{ + "cookie with domain and path", + "cookie with domain and no path", + "cookie with domain and / as path", + "cookie with path and no domain", + "cookie with neither domain nor path", + }; + + const QList input{ + {m_cookieName + "-domain-path", "test-value", ".yyy.xxx.com", "/abc/def/", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-domain-no-path", "test-value", ".yyy.xxx.com", "", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-slash-as-path", "test-value", ".yyy.xxx.com", "", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-no-domain", "test-value", "", "/abc/def/", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-no-domain-no-path", "test-value", "", "", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + }; + + for (int i = 0; i < input.length(); ++i) { + CookieData d = input.at(i); + QNetworkCookie c = d.cookie(); + QUrl url = constructUrl(d.secure ? "https" : "http", d.host, d.path); + c.normalize(url); + //We can't simply use url because QNetworkCookie::normalize transforms an empty path in a /. This way, we ensure the paths are coherent with each other + QTest::newRow(labels.at(i).toLatin1()) << c << constructUrl(url.scheme(), url.host(), c.path()); + } + +} + +void TestWebEnginePartCookieJar::testConstructUrlForCookieNoOrigin() +{ + QFETCH(const QNetworkCookie, cookie); + QFETCH(const QUrl, exp_url); + QUrl url = m_jar->constructUrlForCookie(cookie); + QCOMPARE(url, exp_url); +} + +void TestWebEnginePartCookieJar::testConstructUrlForCookieOrigin() +{ + QUrl url("https://www.xyz.abc.com/a/b"); + QNetworkCookie cookie = CookieData{m_cookieName + "-origin", "test-value", ".xyz.abc.com", "/a/b", url.host(), QDateTime::currentDateTime().addYears(1), true}.cookie(); + QUrl constructedUrl = m_jar->constructUrlForCookie(cookie, url); + QCOMPARE(constructedUrl, url); +} + void TestWebEnginePartCookieJar::testCookieAddedToStoreAreAddedToKCookieServer_data() { QTest::addColumn("cookie"); @@ -103,27 +166,108 @@ 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/", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-session", "test-value", ".yyy.xxx.com", "/abc/def/", "yyy.xxx.com", QDateTime(), true}, + {m_cookieName + "-no-path", "test-value", ".yyy.xxx.com", "", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-slash-as-path", "test-value", ".yyy.xxx.com", "", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-no-domain", "test-value", "", "/abc/def/", "yyy.xxx.com", QDateTime::currentDateTime().addYears(1), true}, + {m_cookieName + "-no-secure", "test-value", ".yyy.xxx.com", "/abc/def/", "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); + 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); +} +void TestWebEnginePartCookieJar::testCookieAddedToStoreAreAddedToKCookieServerUsingFilterCookie_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); @@ -135,7 +279,7 @@ } } -void TestWebEnginePartCookieJar::testCookieAddedToStoreAreAddedToKCookieServer() +void TestWebEnginePartCookieJar::testCookieAddedToStoreAreAddedToKCookieServerUsingFilterCookie() { QFETCH(const QNetworkCookie, cookie); QFETCH(const QString, name); @@ -145,26 +289,28 @@ 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}; - + + QWebEngineCookieStore::FilterRequest req; + req.firstPartyUrl = QUrl("http://www.kde.org"); + req.origin.setScheme(secure ? "https" : "http"); + req.origin.setHost(host); + m_jar->filterCookie(req); 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(); @@ -177,7 +323,6 @@ const bool sec = resFields.at(7).toInt(); QCOMPARE(sec, secure); } - QList TestWebEnginePartCookieJar::findTestCookies() { QList cookies; @@ -233,27 +378,27 @@ 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" }; - + 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}, }; - + QList expected(input); - + for (int i = 0; i < input.count(); ++i) { const CookieData &ex = expected.at(i); const CookieData &in = input.at(i); @@ -271,11 +416,11 @@ 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; @@ -321,14 +466,17 @@ {baseCookieName + "-no-secure", "test-value", ".yyy.xxx.com", "/abc/def/", "zzz.yyy.xxx.com", currentDateTime().addYears(1), false} }; QList expected; + using CookieIdHash = QHash; + CookieIdHash expCookiesUrl; 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); } + expCookiesUrl.insert(WebEnginePartCookieJar::CookieIdentifier(c), constructUrl(c.isSecure() ? "https" : "http", d.host, c.path())); expected << c; } m_jar = new WebEnginePartCookieJar(m_profile, this); @@ -338,17 +486,27 @@ 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); - + + //We can't compare m_jar->m_cookiesUrl with cookiesUrl because the former may contain cookies which have nothing to do with the test + //so we iterate on all cookies in the jar and store in another hash the ones we're interested in + CookieIdHash actualCookiesUrl = m_jar->m_cookiesUrl; + CookieIdHash testCookiesUrl; + for(CookieIdHash::const_iterator it = actualCookiesUrl.constBegin(); it != actualCookiesUrl.constEnd(); ++it) { + if (it.key().name.startsWith(m_cookieName)) { + testCookiesUrl.insert(it.key(), it.value()); + } + } QCOMPARE(cookiesInsertedIntoJar, expected); + QCOMPARE(testCookiesUrl, expCookiesUrl); } void TestWebEnginePartCookieJar::testSessionCookiesAreNotAddedToStoreOnCreation() diff --git a/webenginepart/src/webenginepartcookiejar.h b/webenginepart/src/webenginepartcookiejar.h --- a/webenginepart/src/webenginepartcookiejar.h +++ b/webenginepart/src/webenginepartcookiejar.h @@ -125,7 +125,7 @@ */ static qlonglong findWinID(); - using CookieList = QList; + using CookieHostList = QList>; /** * @brief An identifier for a cookie @@ -220,7 +220,7 @@ * @brief Finds all cookies stored in `KCookieJar` * @return a list of the cookies in `KCookieJar` */ - CookieList findKIOCookies(); + CookieHostList findKIOCookies(); /** * @brief Enum describing the possible fields to pas to `KCookieServer::findCookies` using DBus. @@ -239,7 +239,7 @@ * @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); + static QPair parseKIOCookie(const QStringList &data, int start); #if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) /** @@ -281,9 +281,10 @@ * if it's not empty. If the domain is empty or it's only a dot, an empty URL is returned * * @param cookie the cookie to create the URL for + * @param origin the URL of the origin of the cookie (for example, the one given by filterCookie) * @return the URL for the cookie or an empty URL if the cookie's domain is empty or it's only a dot */ - QUrl constructUrlForCookie(const QNetworkCookie &cookie) const; + static QUrl constructUrlForCookie(const QNetworkCookie &cookie, const QUrl &origin=QUrl()); /** * @brief The `QWebEngineCookieStore` to synchronize KIO with @@ -326,7 +327,11 @@ /** * @brief A list of cookies loaded from KCookieServer when this instance is created */ - CookieList m_cookiesLoadedFromKCookieServer; + QList m_cookiesLoadedFromKCookieServer; + + QHash m_cookiesUrl; + + QUrl m_lastCookieOrigin; #ifdef BUILD_TESTING QList m_testCookies; @@ -343,5 +348,4 @@ * @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 --- a/webenginepart/src/webenginepartcookiejar.cpp +++ b/webenginepart/src/webenginepartcookiejar.cpp @@ -84,6 +84,7 @@ #if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) bool WebEnginePartCookieJar::filterCookie(const QWebEngineCookieStore::FilterRequest& req) { + m_lastCookieOrigin = req.origin; return WebEngineSettings::self()->acceptCrossDomainCookies() || !req.thirdParty; } #endif //QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5,11,0) @@ -98,16 +99,29 @@ } } -QUrl WebEnginePartCookieJar::constructUrlForCookie(const QNetworkCookie& cookie) const +QUrl WebEnginePartCookieJar::constructUrlForCookie(const QNetworkCookie& cookie, const QUrl &origin) { + auto createUrl = [](const QString& scheme, const QString& host, const QString &path){ + QUrl url; + url.setScheme(scheme); + url.setHost(host); + url.setPath(path); + return url; + }; 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()); + if (origin.isValid()) { + url = createUrl(origin.scheme(), origin.host(), origin.path()); } else { - qCDebug(WEBENGINEPART_LOG) << "EMPTY COOKIE DOMAIN for" << cookie.name(); + //We use the domain to guess the origin host. If the domain doesn't start with a dot, there + //wasn't a "domain" entry in the Set-Cookie header and the domain is equal to the host; + //if the domain starts with a dot, there was a "domain" entry in the Set-Cookie header. In this case + //we can't know the real origin host: the best guess is the domain itself (with the leading dot removed) + QString domain = cookie.domain().startsWith(".") ? cookie.domain().mid(1) : cookie.domain(); + if (!domain.isEmpty()) { + url = createUrl(cookie.isSecure() ? "https" : "http", domain, cookie.path()); + } else { + qCDebug(WEBENGINEPART_LOG) << "EMPTY COOKIE DOMAIN for" << cookie.name(); + } } return url; } @@ -168,10 +182,12 @@ cookie.setExpirationDate(dt); #endif } - QUrl url = constructUrlForCookie(cookie); + QUrl url = constructUrlForCookie(cookie, m_lastCookieOrigin); if (url.isEmpty()) { return; } + m_lastCookieOrigin.clear(); + m_cookiesUrl.insert(id, url); //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); @@ -262,12 +278,18 @@ } QNetworkCookie cookie(_cookie); - QUrl url = constructUrlForCookie(cookie); + CookieIdentifier id(_cookie); + + QUrl url = m_cookiesUrl.value(id); + if (url.isEmpty()) { + url = constructUrlForCookie(cookie); + } if(url.isEmpty()){ qCDebug(WEBENGINEPART_LOG) << "Can't remove cookie" << cookie.name() << "because its URL isn't known"; return; } removeCookieDomain(cookie); + m_cookiesUrl.remove(id); QDBusPendingCall pcall = m_cookieServer.asyncCall("deleteCookie", cookie.domain(), url.host(), cookie.path(), QString(cookie.name())); QDBusPendingCallWatcher *w = new QDBusPendingCallWatcher(pcall, this); @@ -285,9 +307,10 @@ void WebEnginePartCookieJar::loadKIOCookies() { - CookieList cookies = findKIOCookies(); - foreach(const QNetworkCookie& cookie, cookies){ + CookieHostList cookies = findKIOCookies(); + for(const QPair pair: cookies) { QDateTime currentTime = QDateTime::currentDateTime(); + QNetworkCookie cookie = pair.first; //Don't attempt to add expired cookies if (cookie.expirationDate().isValid() && cookie.expirationDate() < currentTime) { continue; @@ -297,12 +320,13 @@ m_testCookies << cookie; #endif m_cookieStore->setCookie(cookie); + m_cookiesUrl.insert(CookieIdentifier(cookie), pair.second); } } -WebEnginePartCookieJar::CookieList WebEnginePartCookieJar::findKIOCookies() +WebEnginePartCookieJar::CookieHostList WebEnginePartCookieJar::findKIOCookies() { - CookieList res; + CookieHostList res; if (!m_cookieServer.isValid()) { return res; } @@ -327,7 +351,7 @@ return res; } -QNetworkCookie WebEnginePartCookieJar::parseKIOCookie(const QStringList& data, int start) +QPair WebEnginePartCookieJar::parseKIOCookie(const QStringList& data, int start) { QNetworkCookie c; auto extractField = [data, start](CookieDetails field){return data.at(start + static_cast(field));}; @@ -337,14 +361,15 @@ c.setPath(extractField(CookieDetails::path).toUtf8()); c.setSecure(extractField(CookieDetails::secure).toInt()); //1 for true, 0 for false c.setValue(extractField(CookieDetails::value).toUtf8()); + QString host = extractField(CookieDetails::host); + QUrl url; + url.setScheme(c.isSecure() ? "https" : "http"); + url.setHost(host); + url.setPath(c.path()); 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; + return qMakePair(c, url); } QDebug operator<<(QDebug deb, const WebEnginePartCookieJar::CookieIdentifier& id)