[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