[Merge] lp:~mardy/webbrowser-app/cookie-domain into lp:webbrowser-app
Alberto Mardegan
alberto.mardegan at canonical.com
Mon Sep 29 07:53:52 UTC 2014
Review comments addressed: I'm now handling the case where -1 is immediately returned, and I've added a unit test for that case.
Diff comments:
> === modified file 'src/app/webcontainer/CMakeLists.txt'
> --- src/app/webcontainer/CMakeLists.txt 2014-08-12 17:43:03 +0000
> +++ src/app/webcontainer/CMakeLists.txt 2014-09-18 14:58:26 +0000
> @@ -12,6 +12,7 @@
> chrome-cookie-store.cpp
> cookie-store.cpp
> online-accounts-cookie-store.cpp
> + oxide-cookie-helper.cpp
> local-cookie-store.cpp
> webapp-container.cpp
> webapp-container-helper.cpp
>
> === modified file 'src/app/webcontainer/chrome-cookie-store.cpp'
> --- src/app/webcontainer/chrome-cookie-store.cpp 2014-09-04 13:35:29 +0000
> +++ src/app/webcontainer/chrome-cookie-store.cpp 2014-09-18 14:58:26 +0000
> @@ -17,64 +17,21 @@
> */
>
> #include "chrome-cookie-store.h"
> +#include "oxide-cookie-helper.h"
>
> #include <QDebug>
> #include <QFileInfo>
> #include <QStandardPaths>
> -#include <QMetaMethod>
> -
> -namespace {
> -
> -QList<QNetworkCookie> networkCookiesFromVariantList(const QVariant& cookies) {
> - if (!cookies.canConvert(QMetaType::QVariantList)) {
> - return QList<QNetworkCookie>();
> - }
> -
> - QList<QNetworkCookie> networkCookies;
> - QList<QVariant> cl = cookies.toList();
> - Q_FOREACH(QVariant cookie, cl) {
> - if (!cookie.canConvert(QVariant::Map)) {
> - continue;
> - }
> -
> - QNetworkCookie nc;
> - QVariantMap vm = cookie.toMap();
> - if (!vm.contains("name") || !vm.contains("value")) {
> - continue;
> - }
> -
> - nc.setName(vm.value("name").toByteArray());
> - nc.setValue(vm.value("value").toByteArray());
> - nc.setDomain(vm.value("domain").toString());
> - nc.setPath(vm.value("path").toString());
> - if (vm.contains("httponly") &&
> - vm.value("httponly").canConvert(QVariant::Bool)) {
> - nc.setHttpOnly(vm.value("httponly").toBool());
> - }
> -
> - if (vm.contains("issecure") &&
> - vm.value("issecure").canConvert(QVariant::Bool)) {
> - nc.setSecure(vm.value("issecure").toBool());
> - }
> -
> - if (vm.contains("expirationdate") &&
> - vm.value("expirationdate").canConvert(QVariant::LongLong)) {
> - bool ok = false;
> - qlonglong date = vm.value("expirationdate").toLongLong(&ok);
> - if (ok)
> - nc.setExpirationDate(QDateTime::fromMSecsSinceEpoch(date));
> - }
> -
> - networkCookies.append(nc);
> - }
> - return networkCookies;
> -}
> -
> -}
>
> ChromeCookieStore::ChromeCookieStore(QObject* parent):
> - CookieStore(parent), m_backend(0)
> -{}
> + CookieStore(parent),
> + m_cookieHelper(new OxideCookieHelper(this))
I've set "this" as parent, so it will be deleted.
> +{
> + QObject::connect(m_cookieHelper, SIGNAL(oxideStoreBackendChanged()),
> + this, SIGNAL(oxideStoreBackendChanged()));
> + QObject::connect(m_cookieHelper, SIGNAL(cookiesSet(const QList<QNetworkCookie>&)),
> + this, SLOT(oxideCookiesUpdated(const QList<QNetworkCookie>&)));
> +}
>
> void ChromeCookieStore::setHomepage(const QUrl& homepage) {
> if (homepage == m_homepage)
> @@ -91,32 +48,22 @@
>
> void ChromeCookieStore::setOxideStoreBackend(QObject* backend)
> {
> - if (m_backend == backend)
> - return;
> -
> - m_backend = backend;
> -
> - emit oxideStoreBackendChanged();
> + m_cookieHelper->setOxideStoreBackend(backend);
> }
>
> QObject* ChromeCookieStore::oxideStoreBackend() const
> {
> - return m_backend;
> + return m_cookieHelper->oxideStoreBackend();
> }
>
> void ChromeCookieStore::oxideCookiesReceived(int requestId, const QVariant& cookies)
> {
> Q_UNUSED(requestId);
> - emit gotCookies(networkCookiesFromVariantList(cookies));
> + emit gotCookies(OxideCookieHelper::cookiesFromVariant(cookies));
> }
>
> -void ChromeCookieStore::oxideCookiesUpdated(int requestId,
> - const QVariant& failedCookiesVariant)
> +void ChromeCookieStore::oxideCookiesUpdated(const QList<QNetworkCookie>& failedCookies)
> {
> - Q_UNUSED(requestId);
> -
> - QList<QNetworkCookie> failedCookies =
> - networkCookiesFromVariantList(failedCookiesVariant);
> if (!failedCookies.isEmpty()) {
> qWarning() << "Couldn't set some cookies:" << failedCookies;
> }
> @@ -125,15 +72,16 @@
>
> void ChromeCookieStore::doGetCookies()
> {
> - if ( ! m_backend)
> + QObject* backend = m_cookieHelper->oxideStoreBackend();
> + if ( ! backend)
> return;
>
> - QObject::connect(m_backend,
> + QObject::connect(backend,
> SIGNAL(getCookiesResponse(int, const QVariant&)),
> this,
> SLOT(oxideCookiesReceived(int, const QVariant&)));
>
> - QMetaObject::invokeMethod(m_backend, "getAllCookies", Qt::DirectConnection);
> + QMetaObject::invokeMethod(backend, "getAllCookies", Qt::DirectConnection);
> }
>
> QDateTime ChromeCookieStore::lastUpdateTimeStamp() const
> @@ -144,18 +92,7 @@
>
> void ChromeCookieStore::doSetCookies(const Cookies& cookies)
> {
> - if ( ! m_backend)
> - return;
> -
> - QObject::connect(m_backend, SIGNAL(setCookiesResponse(int, const QVariant&)),
> - this, SLOT(oxideCookiesUpdated(int, const QVariant&)));
> -
> - int requestId = -1;
> - QMetaObject::invokeMethod(m_backend, "setNetworkCookies",
> - Qt::DirectConnection,
> - Q_RETURN_ARG(int, requestId),
> - Q_ARG(const QUrl&, m_homepage),
> - Q_ARG(const QList<QNetworkCookie>&, cookies));
> + m_cookieHelper->setCookies(cookies);
> }
>
> void ChromeCookieStore::setDbPath(const QString &path)
>
> === modified file 'src/app/webcontainer/chrome-cookie-store.h'
> --- src/app/webcontainer/chrome-cookie-store.h 2014-09-03 07:26:30 +0000
> +++ src/app/webcontainer/chrome-cookie-store.h 2014-09-18 14:58:26 +0000
> @@ -24,6 +24,7 @@
> #include <QString>
> #include <QUrl>
>
> +class OxideCookieHelper;
>
> class ChromeCookieStore : public CookieStore
> {
> @@ -58,14 +59,14 @@
>
> private Q_SLOTS:
> void oxideCookiesReceived(int requestId, const QVariant& cookies);
> - void oxideCookiesUpdated(int requestId, const QVariant& failedCookies);
> + void oxideCookiesUpdated(const QList<QNetworkCookie>& failedCookies);
>
> private:
> virtual void doGetCookies() Q_DECL_OVERRIDE;
> virtual void doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
>
> private:
> - QObject* m_backend;
> + OxideCookieHelper* m_cookieHelper;
> QUrl m_homepage;
> QString m_dbPath;
> };
>
> === added file 'src/app/webcontainer/oxide-cookie-helper.cpp'
> --- src/app/webcontainer/oxide-cookie-helper.cpp 1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/oxide-cookie-helper.cpp 2014-09-18 14:58:26 +0000
> @@ -0,0 +1,247 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "oxide-cookie-helper.h"
> +
> +#include <QDateTime>
> +#include <QDebug>
> +#include <QMap>
> +#include <QMetaMethod>
> +#include <QSet>
> +#include <QUrl>
> +
> +typedef QList<QNetworkCookie> Cookies;
> +
> +class OxideCookieHelperPrivate : public QObject
> +{
> + Q_OBJECT
> + Q_DECLARE_PUBLIC(OxideCookieHelper)
> +
> +public:
> + OxideCookieHelperPrivate(OxideCookieHelper* q);
> +
> + void setCookies(const QList<QNetworkCookie>& cookies);
> +
> +private Q_SLOTS:
> + void oxideCookiesUpdated(int requestId, const QVariant& failedCookies);
> +
> +private:
> + QObject* m_backend;
> + QSet<int> m_pendingCalls;
> + QList<QNetworkCookie> m_failedCookies;
> + mutable OxideCookieHelper* q_ptr;
> +};
> +
> +OxideCookieHelperPrivate::OxideCookieHelperPrivate(OxideCookieHelper* q):
> + QObject(q),
> + m_backend(0),
> + q_ptr(q)
> +{
> +}
> +
> +void OxideCookieHelperPrivate::setCookies(const QList<QNetworkCookie>& cookies)
> +{
> + Q_Q(OxideCookieHelper);
> +
> + if (Q_UNLIKELY(!m_backend)) {
> + qCritical() << "No Oxide backend set!";
> + return;
> + }
> +
> + if (Q_UNLIKELY(!m_pendingCalls.isEmpty())) {
> + qCritical() << "A call to setCookies() is already in progress";
> + return;
> + }
> +
> + if (cookies.isEmpty()) {
> + /* We don't simply use Q_EMIT because we want the signal to be emitted
> + * asynchronously */
> + QMetaObject::invokeMethod(q, "cookiesSet", Qt::QueuedConnection,
> + Q_ARG(const QList<QNetworkCookie>&, cookies));
> + return;
> + }
> +
> + /* Since Oxide does not support setting cookies for different domains in a
> + * single call to setCookies(), we group the cookies by their domain, and
> + * perform a separate call to Oxide's setCookies() for each domain.
> + */
> + QMap<QString, Cookies> cookiesPerDomain;
> + Q_FOREACH(const QNetworkCookie &cookie, cookies) {
> + /* This creates an empty list if the domain is new in the map */
> + QList<QNetworkCookie> &domainCookies =
> + cookiesPerDomain[cookie.domain()];
> +
> + domainCookies.append(cookie);
> + }
> +
> + /* Grouping done, perform the calls */
> + QMapIterator<QString, Cookies> it(cookiesPerDomain);
> + while (it.hasNext()) {
> + it.next();
> +
> + QString domain = it.key();
> + if (domain.startsWith('.')) {
> + domain = domain.mid(1);
> + }
> +
> + QUrl url;
> + url.setScheme("http");
> + url.setHost(domain);
> +
> + int requestId = -1;
> + QMetaObject::invokeMethod(m_backend, "setNetworkCookies",
> + Qt::DirectConnection,
> + Q_RETURN_ARG(int, requestId),
> + Q_ARG(const QUrl&, url),
> + Q_ARG(const QList<QNetworkCookie>&, it.value()));
Indeed, will fix.
> + m_pendingCalls.insert(requestId);
> + }
> +}
> +
> +void OxideCookieHelperPrivate::oxideCookiesUpdated(int requestId,
> + const QVariant& failedCookies)
> +{
> + Q_Q(OxideCookieHelper);
> +
> + m_failedCookies.append(OxideCookieHelper::cookiesFromVariant(failedCookies));
> + m_pendingCalls.remove(requestId);
> +
> + if (m_pendingCalls.isEmpty()) {
> + Q_EMIT q->cookiesSet(m_failedCookies);
> + }
> +}
> +
> +OxideCookieHelper::OxideCookieHelper(QObject* parent):
> + QObject(parent),
> + d_ptr(new OxideCookieHelperPrivate(this))
> +{
> +}
> +
> +QList<QNetworkCookie>
> +OxideCookieHelper::cookiesFromVariant(const QVariant& cookies)
> +{
> + if (!cookies.canConvert(QMetaType::QVariantList)) {
> + return QList<QNetworkCookie>();
> + }
> +
> + QList<QNetworkCookie> networkCookies;
> + QList<QVariant> cl = cookies.toList();
> + Q_FOREACH(QVariant cookie, cl) {
> + if (!cookie.canConvert(QVariant::Map)) {
> + continue;
> + }
> +
> + QNetworkCookie nc;
> + QVariantMap vm = cookie.toMap();
> + if (!vm.contains("name") || !vm.contains("value")) {
> + continue;
> + }
> +
> + nc.setName(vm.value("name").toByteArray());
> + nc.setValue(vm.value("value").toByteArray());
> + nc.setDomain(vm.value("domain").toString());
> + nc.setPath(vm.value("path").toString());
> + if (vm.contains("httponly") &&
> + vm.value("httponly").canConvert(QVariant::Bool)) {
> + nc.setHttpOnly(vm.value("httponly").toBool());
> + }
> +
> + if (vm.contains("issecure") &&
> + vm.value("issecure").canConvert(QVariant::Bool)) {
> + nc.setSecure(vm.value("issecure").toBool());
> + }
> +
> + if (vm.contains("expirationdate")) {
> + QVariant value = vm.value("expirationdate");
> + if (value.canConvert(QVariant::DateTime)) {
> + nc.setExpirationDate(value.toDateTime());
> + } else if (value.canConvert(QVariant::LongLong)) {
> + bool ok = false;
> + qlonglong date = value.toLongLong(&ok);
> + if (ok)
> + nc.setExpirationDate(QDateTime::fromMSecsSinceEpoch(date));
> + }
> + }
> +
> + networkCookies.append(nc);
> + }
> + return networkCookies;
> +}
> +
> +QVariant
> +OxideCookieHelper::variantFromCookies(const QList<QNetworkCookie>& cookies)
> +{
> + /* Taken straight from Oxide's networkCookiesToVariant() method defined in
> + * qt/quick/api/oxideqquickwebcontext.cc
> + */
> + QList<QVariant> list;
> + Q_FOREACH(QNetworkCookie cookie, cookies) {
> + QVariantMap c;
> + c.insert("name", QVariant(QString(cookie.name())));
> + c.insert("value", QVariant(QString(cookie.value())));
> + c.insert("domain", QVariant(cookie.domain()));
> + c.insert("path", QVariant(cookie.path()));
> + c.insert("httponly", QVariant(cookie.isHttpOnly()));
> + c.insert("issecure", QVariant(cookie.isSecure()));
> + c.insert("issessioncookie", QVariant(cookie.isSessionCookie()));
> + if (cookie.expirationDate().isValid()) {
> + c.insert("expirationdate", QVariant(cookie.expirationDate()));
> + } else {
> + c.insert("expirationdate", QVariant());
> + }
> +
> + list.append(c);
> + }
> +
> + return QVariant(list);
> +
> +}
> +
> +void OxideCookieHelper::setOxideStoreBackend(QObject* backend)
> +{
> + Q_D(OxideCookieHelper);
> +
> + if (d->m_backend == backend)
> + return;
> +
> + if (d->m_backend) {
> + QObject::disconnect(d->m_backend, 0, this, 0);
> + }
> +
> + d->m_backend = backend;
> + if (backend) {
> + QObject::connect(backend, SIGNAL(setCookiesResponse(int, const QVariant&)),
> + d, SLOT(oxideCookiesUpdated(int, const QVariant&)));
> + }
> +
> + Q_EMIT oxideStoreBackendChanged();
> +}
> +
> +QObject* OxideCookieHelper::oxideStoreBackend() const
> +{
> + Q_D(const OxideCookieHelper);
> + return d->m_backend;
> +}
> +
> +void OxideCookieHelper::setCookies(const QList<QNetworkCookie>& cookies)
> +{
> + Q_D(OxideCookieHelper);
> + d->setCookies(cookies);
> +}
> +
> +#include "oxide-cookie-helper.moc"
>
> === added file 'src/app/webcontainer/oxide-cookie-helper.h'
> --- src/app/webcontainer/oxide-cookie-helper.h 1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/oxide-cookie-helper.h 2014-09-18 14:58:26 +0000
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef OXIDE_COOKIE_HELPER_H
> +#define OXIDE_COOKIE_HELPER_H
> +
> +#include <QList>
> +#include <QNetworkCookie>
> +#include <QObject>
> +#include <QString>
> +
> +class OxideCookieHelperPrivate;
> +class OxideCookieHelper : public QObject
> +{
> + Q_OBJECT
> +
> + Q_PROPERTY(QObject* oxideStoreBackend READ oxideStoreBackend \
> + WRITE setOxideStoreBackend NOTIFY oxideStoreBackendChanged)
> +
> +public:
> + OxideCookieHelper(QObject* parent = 0);
> +
> + // oxideStoreBackend
> + void setOxideStoreBackend(QObject* backend);
> + QObject* oxideStoreBackend() const;
> +
> + static QList<QNetworkCookie> cookiesFromVariant(const QVariant& cookies);
> + static QVariant variantFromCookies(const QList<QNetworkCookie>& cookies);
> +
> +public Q_SLOTS:
> + void setCookies(const QList<QNetworkCookie>& cookies);
> +
> +Q_SIGNALS:
> + void oxideStoreBackendChanged();
> + void cookiesSet(const QList<QNetworkCookie>& failedCookies);
> +
> +private:
> + OxideCookieHelperPrivate* d_ptr;
> + Q_DECLARE_PRIVATE(OxideCookieHelper)
> +};
> +
> +#endif // OXIDE_COOKIE_HELPER_H
>
> === modified file 'tests/unittests/CMakeLists.txt'
> --- tests/unittests/CMakeLists.txt 2014-08-08 15:29:07 +0000
> +++ tests/unittests/CMakeLists.txt 2014-09-18 14:58:26 +0000
> @@ -13,4 +13,5 @@
> add_subdirectory(limit-proxy-model)
> add_subdirectory(container-url-patterns)
> add_subdirectory(cookie-store)
> +add_subdirectory(oxide-cookie-helper)
> add_subdirectory(session-storage)
>
> === modified file 'tests/unittests/cookie-store/CMakeLists.txt'
> --- tests/unittests/cookie-store/CMakeLists.txt 2014-08-05 00:25:20 +0000
> +++ tests/unittests/cookie-store/CMakeLists.txt 2014-09-18 14:58:26 +0000
> @@ -2,6 +2,7 @@
> set(SOURCES
> ${webapp-container_SOURCE_DIR}/chrome-cookie-store.cpp
> ${webapp-container_SOURCE_DIR}/cookie-store.cpp
> + ${webapp-container_SOURCE_DIR}/oxide-cookie-helper.cpp
> tst_CookieStore.cpp
> )
> add_executable(${TEST} ${SOURCES})
>
> === added directory 'tests/unittests/oxide-cookie-helper'
> === added file 'tests/unittests/oxide-cookie-helper/CMakeLists.txt'
> --- tests/unittests/oxide-cookie-helper/CMakeLists.txt 1970-01-01 00:00:00 +0000
> +++ tests/unittests/oxide-cookie-helper/CMakeLists.txt 2014-09-18 14:58:26 +0000
> @@ -0,0 +1,9 @@
> +set(TEST tst_OxideCookieHelperTests)
> +set(SOURCES
> + ${webapp-container_SOURCE_DIR}/oxide-cookie-helper.cpp
> + tst_OxideCookieHelper.cpp
> +)
> +add_executable(${TEST} ${SOURCES})
> +include_directories(${webapp-container_SOURCE_DIR})
> +qt5_use_modules(${TEST} Core Network Test)
> +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
>
> === added file 'tests/unittests/oxide-cookie-helper/tst_OxideCookieHelper.cpp'
> --- tests/unittests/oxide-cookie-helper/tst_OxideCookieHelper.cpp 1970-01-01 00:00:00 +0000
> +++ tests/unittests/oxide-cookie-helper/tst_OxideCookieHelper.cpp 2014-09-18 14:58:26 +0000
> @@ -0,0 +1,298 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +// Qt
> +#include <QtCore/QDir>
> +#include <QtCore/QList>
> +#include <QtCore/QTimer>
> +#include <QtNetwork/QNetworkCookie>
> +#include <QtTest/QSignalSpy>
> +#include <QtTest/QtTest>
> +
> +// local
> +#include "oxide-cookie-helper.h"
> +
> +typedef QList<QNetworkCookie> Cookies;
> +
> +/* Fake Oxide backend implementation */
> +class CookieBackend : public QObject
> +{
> + Q_OBJECT
> +
> +public:
> + CookieBackend(QObject *parent = 0):
> + QObject(parent),
> + m_lastRequestId(0)
> + {}
> +
> + void sendReply(int requestId, const QList<QNetworkCookie>& failedCookies) {
> + QVariant failedCookiesVariant =
> + OxideCookieHelper::variantFromCookies(failedCookies);
> + Q_EMIT setCookiesResponse(requestId, failedCookiesVariant);
> + }
> +
> +public Q_SLOTS:
> + int setNetworkCookies(const QUrl& url, const QList<QNetworkCookie>& cookies) {
> + m_lastRequestId++;
> + Q_EMIT setNetworkCookiesCalled(m_lastRequestId, url, cookies);
> + return m_lastRequestId;
> + }
> +
> + void onTimerTimeout() {
> + QObject *timer = sender();
> + int requestId = timer->property("requestId").toInt();
> + Cookies failedCookies = timer->property("failedCookies").value<Cookies>();
> + sendReply(requestId, failedCookies);
> + }
> +
> +Q_SIGNALS:
> + void setCookiesResponse(int requestId, const QVariant& failedCookies);
> + void setNetworkCookiesCalled(int requestId, const QUrl& url,
> + const QList<QNetworkCookie>& cookies);
> +private:
> + int m_lastRequestId;
> +};
> +
> +class OxideCookieHelperTest : public QObject
> +{
> + Q_OBJECT
> +
> +private Q_SLOTS:
> + void testSetCookiesSanity();
> + void testSetCookies_data();
> + void testSetCookies();
> + void testSetCookiesSubDomain();
> +};
> +
> +void OxideCookieHelperTest::testSetCookiesSanity()
> +{
> + OxideCookieHelper helper;
> + QSignalSpy cookiesSet(&helper,
> + SIGNAL(cookiesSet(const QList<QNetworkCookie>&)));
> +
> + QVERIFY(helper.oxideStoreBackend() == 0);
> +
> + Cookies cookies = QNetworkCookie::parseCookies("a=2\nb=3");
> + QCOMPARE(cookies.count(), 2);
> +
> + helper.setCookies(cookies);
> + QTest::qWait(10);
> + QCOMPARE(cookiesSet.count(), 0);
> +
> + CookieBackend backend;
> + QSignalSpy setNetworkCookiesCalled(&backend,
> + SIGNAL(setNetworkCookiesCalled(int,const QUrl&,const QList<QNetworkCookie>&)));
> +
> + helper.setOxideStoreBackend(&backend);
> + QCOMPARE(helper.oxideStoreBackend(), &backend);
> + QCOMPARE(helper.property("oxideStoreBackend").value<QObject*>(),
> + &backend);
> +}
> +
> +void OxideCookieHelperTest::testSetCookies_data()
> +{
> + QTest::addColumn<QString>("domain1");
> + QTest::addColumn<QString>("cookies1");
> + QTest::addColumn<int>("timeout1");
> + QTest::addColumn<QString>("failedcookies1");
> +
> + QTest::addColumn<QString>("domain2");
> + QTest::addColumn<QString>("cookies2");
> + QTest::addColumn<int>("timeout2");
> + QTest::addColumn<QString>("failedcookies2");
> +
> + QTest::addColumn<QString>("domain3");
> + QTest::addColumn<QString>("cookies3");
> + QTest::addColumn<int>("timeout3");
> + QTest::addColumn<QString>("failedcookies3");
> +
> + QTest::newRow("empty") <<
> + QString() << QString() << 0 << QString() <<
> + QString() << QString() << 0 << QString() <<
> + QString() << QString() << 0 << QString();
> +
> + QTest::newRow("one domain, success") <<
> + "example.org" <<
> + "a=0; Domain=example.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT\n"
> + "b=2; Domain=example.org; HttpOnly\n"
> + "c=something; Domain=example.org; Secure" << 10 << QString() <<
> + QString() << QString() << 0 << QString() <<
> + QString() << QString() << 0 << QString();
> +
> + QTest::newRow("one domain, with one failure") <<
> + "example.org" <<
> + "a=0; Domain=example.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT\n"
> + "b=2; Domain=example.org; HttpOnly\n"
> + "c=something; Domain=example.org; Secure" << 10 <<
> + "b=2; Domain=example.org; HttpOnly" <<
> + QString() << QString() << 0 << QString() <<
> + QString() << QString() << 0 << QString();
> +
> + QTest::newRow("three domains, success") <<
> + "example.org" <<
> + "a=0; Domain=example.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT\n"
> + "m=2; Domain=example.org; HttpOnly\n"
> + "z=something; Domain=example.org; Secure" << 10 << QString() <<
> +
> + "domain.net" <<
> + "c=4; Domain=domain.net; HttpOnly\n"
> + "r=no; Domain=domain.net; Expires=Wed, 13 Jan 2021 22:23:01 GMT" << 20 << QString() <<
> +
> + "sub.site.org" <<
> + "d=yes; Domain=sub.site.org; Secure\n"
> + "e=3; Domain=sub.site.org; HttpOnly\n"
> + "z=last; Domain=sub.site.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT" << 40 << QString();
> +
> + QTest::newRow("three domains, some failures") <<
> + "example.org" <<
> + "a=0; Domain=example.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT\n"
> + "m=2; Domain=example.org; HttpOnly\n"
> + "z=something; Domain=example.org; Secure" << 10 << QString() <<
> +
> + "domain.net" <<
> + "c=4; Domain=domain.net; HttpOnly\n"
> + "r=no; Domain=domain.net; Expires=Wed, 13 Jan 2021 22:23:01 GMT" << 40 <<
> + "c=4; Domain=domain.net; HttpOnly" <<
> +
> + "sub.site.org" <<
> + "d=yes; Domain=sub.site.org; Secure\n"
> + "e=3; Domain=sub.site.org; HttpOnly\n"
> + "z=last; Domain=sub.site.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT" << 20 <<
> + "e=3; Domain=sub.site.org; HttpOnly\n"
> + "z=last; Domain=sub.site.org; Expires=Wed, 13 Jan 2021 22:23:01 GMT";
> +}
> +
> +struct DomainData {
> + DomainData(): timeout(0) {}
> + DomainData(const QString& rawCookies, int t, const QString& rawFailedCookies):
> + cookies(QNetworkCookie::parseCookies(rawCookies.toUtf8())),
> + timeout(t),
> + failedCookies(QNetworkCookie::parseCookies(rawFailedCookies.toUtf8()))
> + {}
> +
> + Cookies cookies;
> + int timeout;
> + Cookies failedCookies;
> +};
> +
> +static bool cookieCompare(const QNetworkCookie a, const QNetworkCookie b)
> +{
> + return a.name() < b.name();
> +}
> +
> +void OxideCookieHelperTest::testSetCookies()
> +{
> + QFETCH(QString, domain1);
> + QFETCH(QString, cookies1);
> + QFETCH(int, timeout1);
> + QFETCH(QString, failedcookies1);
> +
> + QFETCH(QString, domain2);
> + QFETCH(QString, cookies2);
> + QFETCH(int, timeout2);
> + QFETCH(QString, failedcookies2);
> +
> + QFETCH(QString, domain3);
> + QFETCH(QString, cookies3);
> + QFETCH(int, timeout3);
> + QFETCH(QString, failedcookies3);
> +
> + /* Build a data structure easier to handle */
> + QMap<QString,DomainData> domains;
> + if (!domain1.isEmpty()) domains[domain1] = DomainData(cookies1, timeout1, failedcookies1);
> + if (!domain2.isEmpty()) domains[domain2] = DomainData(cookies2, timeout2, failedcookies2);
> + if (!domain3.isEmpty()) domains[domain3] = DomainData(cookies3, timeout3, failedcookies3);
> +
> + OxideCookieHelper helper;
> + QSignalSpy cookiesSet(&helper,
> + SIGNAL(cookiesSet(const QList<QNetworkCookie>&)));
> +
> + CookieBackend backend;
> + QSignalSpy setNetworkCookiesCalled(&backend,
> + SIGNAL(setNetworkCookiesCalled(int,const QUrl&,const QList<QNetworkCookie>&)));
> + helper.setOxideStoreBackend(&backend);
> +
> + /* Build the list of cookies */
> + Cookies cookies;
> + Cookies expectedFailedCookies;
> + Q_FOREACH(const DomainData &domainData, domains) {
> + cookies.append(domainData.cookies);
> + expectedFailedCookies.append(domainData.failedCookies);
> + }
> + qSort(cookies.begin(), cookies.end(), cookieCompare);
> +
> + helper.setCookies(cookies);
> + QCOMPARE(setNetworkCookiesCalled.count(), domains.count());
> + QList<QVariantList> setNetworkCookiesCalls = setNetworkCookiesCalled;
> + Q_FOREACH(const QVariantList &args, setNetworkCookiesCalls) {
> + int requestId = args.at(0).toInt();
> + QUrl url = args.at(1).toUrl();
> + Cookies domainCookies = args.at(2).value<Cookies>();
> +
> + QVERIFY(domains.contains(url.host()));
> + /* Compare the cookies lists; we don't care about the order, so let's
> + * sort them before comparing */
> + const DomainData &domainData = domains[url.host()];
> + qSort(domainCookies.begin(), domainCookies.end(), cookieCompare);
> + Cookies expectedCookies = domainData.cookies;
> + qSort(expectedCookies.begin(), expectedCookies.end(), cookieCompare);
> + QCOMPARE(domainCookies, expectedCookies);
> +
> + QTimer* timer = new QTimer(&backend);
> + timer->setSingleShot(true);
> + timer->setInterval(domainData.timeout);
> + timer->setProperty("requestId", requestId);
> + timer->setProperty("failedCookies", QVariant::fromValue(domainData.failedCookies));
> + QObject::connect(timer, SIGNAL(timeout()),
> + &backend, SLOT(onTimerTimeout()));
> + timer->start();
> + }
> +
> + QVERIFY(cookiesSet.wait());
> + QCOMPARE(cookiesSet.count(), 1);
> +
> + /* Compare the failed cookies */
> + qSort(expectedFailedCookies.begin(), expectedFailedCookies.end(), cookieCompare);
> + Cookies failedCookies = cookiesSet.at(0).at(0).value<Cookies>();
> + qSort(failedCookies.begin(), failedCookies.end(), cookieCompare);
> + QCOMPARE(failedCookies, expectedFailedCookies);
> +}
> +
> +void OxideCookieHelperTest::testSetCookiesSubDomain()
> +{
> + OxideCookieHelper helper;
> + QSignalSpy cookiesSet(&helper,
> + SIGNAL(cookiesSet(const QList<QNetworkCookie>&)));
> +
> + Cookies cookies = QNetworkCookie::parseCookies("a=2; Domain=.example.org");
> + QCOMPARE(cookies.count(), 1);
> +
> + CookieBackend backend;
> + QSignalSpy setNetworkCookiesCalled(&backend,
> + SIGNAL(setNetworkCookiesCalled(int,const QUrl&,const QList<QNetworkCookie>&)));
> + helper.setOxideStoreBackend(&backend);
> +
> + helper.setCookies(cookies);
> + QCOMPARE(setNetworkCookiesCalled.count(), 1);
> + QUrl url = setNetworkCookiesCalled.at(0).at(1).toUrl();
> +
> + QCOMPARE(url.host(), QString("example.org"));
> +}
> +
> +QTEST_MAIN(OxideCookieHelperTest)
> +#include "tst_OxideCookieHelper.moc"
>
--
https://code.launchpad.net/~mardy/webbrowser-app/cookie-domain/+merge/235144
Your team Ubuntu Phablet Team is subscribed to branch lp:webbrowser-app.
More information about the Ubuntu-reviews
mailing list