[Qt] [WK2] Implement a persistent cookie storage.
authoralexis.menard@openbossa.org <alexis.menard@openbossa.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Sep 2011 21:01:12 +0000 (21:01 +0000)
committeralexis.menard@openbossa.org <alexis.menard@openbossa.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Sep 2011 21:01:12 +0000 (21:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=65309

Reviewed by Chang Shu.

Source/WebCore:

Implement a cookie storage for the Qt port on WebKit2.
The implementation is using a SQLite database to store the cookies
and restore them. It uses a static object as CookieJar is not an
object but a set of global functions. The actual saving/restoring is on
the WebProcess side where our network stack lives.

Existing tests cover the new implementation. Unfortunately there is one
case that we can't easily simulate : login in a website, make sure that the webprocess
is not running and then going back to this website and see that we are logged.

* WebCore.pri:
* WebCore.pro:
* platform/qt/CookieJarQt.cpp:
(WebCore::getHostnamesWithCookies):
(WebCore::deleteCookiesForHostname):
(WebCore::deleteAllCookies):
(WebCore::SharedCookieJarQt::shared):
(WebCore::SharedCookieJarQt::create):
(WebCore::SharedCookieJarQt::destroy):
(WebCore::SharedCookieJarQt::getHostnamesWithCookies):
(WebCore::SharedCookieJarQt::deleteCookiesForHostname):
(WebCore::SharedCookieJarQt::deleteAllCookies):
(WebCore::SharedCookieJarQt::SharedCookieJarQt):
(WebCore::SharedCookieJarQt::~SharedCookieJarQt):
(WebCore::SharedCookieJarQt::setCookiesFromUrl):
(WebCore::SharedCookieJarQt::ensureDatabaseTable):
(WebCore::SharedCookieJarQt::loadCookies):
* platform/qt/CookieJarQt.h: Added.

Source/WebKit2:

Add parameter to the WebProcess creation to specify where cookies should be saved.
It also use the new cookie storage implementation and set it to our network stack
so cookies are used when using it.

* Shared/WebProcessCreationParameters.cpp:
(WebKit::WebProcessCreationParameters::encode):
(WebKit::WebProcessCreationParameters::decode):
* Shared/WebProcessCreationParameters.h:
* UIProcess/qt/WebContextQt.cpp:
(WebKit::WebContext::platformInitializeWebProcess):
* WebProcess/qt/WebProcessQt.cpp:
(WebKit::WebProcess::platformInitializeWebProcess):
(WebKit::WebProcess::platformTerminate):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95568 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/WebCore.pri
Source/WebCore/WebCore.pro
Source/WebCore/platform/qt/CookieJarQt.cpp
Source/WebCore/platform/qt/CookieJarQt.h [new file with mode: 0644]
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebProcessCreationParameters.cpp
Source/WebKit2/Shared/WebProcessCreationParameters.h
Source/WebKit2/UIProcess/qt/WebContextQt.cpp
Source/WebKit2/WebProcess/qt/WebProcessQt.cpp

index 4150376..255bac8 100644 (file)
@@ -1,3 +1,39 @@
+2011-09-20  Alexis Menard  <alexis.menard@openbossa.org>
+
+        [Qt] [WK2] Implement a persistent cookie storage.
+        https://bugs.webkit.org/show_bug.cgi?id=65309
+
+        Reviewed by Chang Shu.
+
+        Implement a cookie storage for the Qt port on WebKit2.
+        The implementation is using a SQLite database to store the cookies
+        and restore them. It uses a static object as CookieJar is not an
+        object but a set of global functions. The actual saving/restoring is on
+        the WebProcess side where our network stack lives.
+
+        Existing tests cover the new implementation. Unfortunately there is one
+        case that we can't easily simulate : login in a website, make sure that the webprocess
+        is not running and then going back to this website and see that we are logged.
+
+        * WebCore.pri:
+        * WebCore.pro:
+        * platform/qt/CookieJarQt.cpp:
+        (WebCore::getHostnamesWithCookies):
+        (WebCore::deleteCookiesForHostname):
+        (WebCore::deleteAllCookies):
+        (WebCore::SharedCookieJarQt::shared):
+        (WebCore::SharedCookieJarQt::create):
+        (WebCore::SharedCookieJarQt::destroy):
+        (WebCore::SharedCookieJarQt::getHostnamesWithCookies):
+        (WebCore::SharedCookieJarQt::deleteCookiesForHostname):
+        (WebCore::SharedCookieJarQt::deleteAllCookies):
+        (WebCore::SharedCookieJarQt::SharedCookieJarQt):
+        (WebCore::SharedCookieJarQt::~SharedCookieJarQt):
+        (WebCore::SharedCookieJarQt::setCookiesFromUrl):
+        (WebCore::SharedCookieJarQt::ensureDatabaseTable):
+        (WebCore::SharedCookieJarQt::loadCookies):
+        * platform/qt/CookieJarQt.h: Added.
+
 2011-09-20  David Hyatt  <hyatt@apple.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=68314
index f402711..85d4f5c 100644 (file)
@@ -5,7 +5,7 @@ include(features.pri)
 # We enable TextureMapper by default; remove this line to enable GraphicsLayerQt.
 CONFIG += texmap
 
-QT *= network
+QT *= network sql
 
 SOURCE_DIR = $$replace(PWD, /WebCore, "")
 
index 68d704f..7e991ce 100644 (file)
@@ -2096,6 +2096,7 @@ HEADERS += \
     platform/PlatformTouchPoint.h \
     platform/PopupMenu.h \
     platform/qt/ClipboardQt.h \
+    platform/qt/CookieJarQt.h \
     platform/qt/QWebPageClient.h \
     platform/qt/QtStyleOptionWebComboBox.h \
     platform/qt/RenderThemeQt.h \
index 6dcd66b..42258f6 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
  *
  * All rights reserved.
  *
@@ -26,6 +27,8 @@
  */
 
 #include "config.h"
+#include "CookieJarQt.h"
+
 #include "CookieJar.h"
 
 #include "Cookie.h"
 #include "qwebframe.h"
 #include "qwebpage.h"
 #include "qwebsettings.h"
+#include <QDateTime>
+#include <QDir>
 #include <QNetworkAccessManager>
 #include <QNetworkCookie>
+#include <QSqlQuery>
 #include <QStringList>
 
 namespace WebCore {
 
+static SharedCookieJarQt* s_sharedCookieJarQt = 0;
+
 static QNetworkCookieJar *cookieJar(const Document *document)
 {
     if (!document)
@@ -144,19 +152,137 @@ void deleteCookie(const Document*, const KURL&, const String&)
 
 void getHostnamesWithCookies(HashSet<String>& hostnames)
 {
-    // FIXME: Not yet implemented
+    SharedCookieJarQt* jar = SharedCookieJarQt::shared();
+    if (jar)
+        jar->getHostnamesWithCookies(hostnames);
 }
 
 void deleteCookiesForHostname(const String& hostname)
 {
-    // FIXME: Not yet implemented
+    SharedCookieJarQt* jar = SharedCookieJarQt::shared();
+    if (jar)
+        jar->deleteCookiesForHostname(hostname);
 }
 
 void deleteAllCookies()
 {
-    // FIXME: Not yet implemented
+    SharedCookieJarQt* jar = SharedCookieJarQt::shared();
+    if (jar)
+        jar->deleteAllCookies();
+}
+
+SharedCookieJarQt* SharedCookieJarQt::shared()
+{
+    return s_sharedCookieJarQt;
+}
+
+SharedCookieJarQt* SharedCookieJarQt::create(const String& cookieStorageDirectory)
+{
+    if (!s_sharedCookieJarQt)
+        s_sharedCookieJarQt = new SharedCookieJarQt(cookieStorageDirectory);
+
+    return s_sharedCookieJarQt;
+}
+
+void SharedCookieJarQt::destroy()
+{
+    delete s_sharedCookieJarQt;
+    s_sharedCookieJarQt = 0;
+}
+
+void SharedCookieJarQt::getHostnamesWithCookies(HashSet<String>& hostnames)
+{
+    QList<QNetworkCookie> cookies = allCookies();
+    foreach (const QNetworkCookie& networkCookie, cookies)
+        hostnames.add(networkCookie.domain());
+}
+
+void SharedCookieJarQt::deleteCookiesForHostname(const String& hostname)
+{
+    QList<QNetworkCookie> cookies = allCookies();
+    QList<QNetworkCookie>::Iterator it = cookies.begin();
+    QList<QNetworkCookie>::Iterator end = cookies.end();
+    QSqlQuery sqlQuery(m_database);
+    sqlQuery.prepare(QLatin1String("DELETE FROM cookies WHERE cookieId=:cookieIdvalue"));
+    while (it != end) {
+        if (it->domain() == QString(hostname)) {
+            sqlQuery.bindValue(QLatin1String(":cookieIdvalue"), it->domain().append(QLatin1String(it->name())));
+            sqlQuery.exec();
+            it = cookies.erase(it);
+        } else
+            it++;
+    }
+    setAllCookies(cookies);
 }
 
+void SharedCookieJarQt::deleteAllCookies()
+{
+    QSqlQuery sqlQuery(m_database);
+    sqlQuery.prepare(QLatin1String("DELETE * FROM cookies"));
+    sqlQuery.exec();
+    setAllCookies(QList<QNetworkCookie>());
+}
+
+SharedCookieJarQt::SharedCookieJarQt(const String& cookieStorageDirectory)
+{
+    m_database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"));
+    const QString cookieStoragePath = cookieStorageDirectory;
+    QDir().mkpath(cookieStoragePath + QLatin1String(".QtWebKit/"));
+    const QString dataBaseName = cookieStoragePath + QLatin1String(".QtWebKit/cookies.db");
+    m_database.setDatabaseName(dataBaseName);
+    ensureDatabaseTable();
+    loadCookies();
+}
+
+SharedCookieJarQt::~SharedCookieJarQt()
+{
+    m_database.close();
+}
+
+bool SharedCookieJarQt::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url)
+{
+    if (!QNetworkCookieJar::setCookiesFromUrl(cookieList, url))
+        return false;
+    QSqlQuery sqlQuery(m_database);
+    sqlQuery.prepare(QLatin1String("INSERT OR REPLACE INTO cookies (cookieId, cookie) VALUES (:cookieIdvalue, :cookievalue)"));
+    QVariantList cookiesIds;
+    QVariantList cookiesValues;
+    foreach (const QNetworkCookie &cookie, cookiesForUrl(url)) {
+        if (cookie.isSessionCookie())
+            continue;
+        cookiesIds.append(cookie.domain().append(QLatin1String(cookie.name())));
+        cookiesValues.append(cookie.toRawForm());
+    }
+    sqlQuery.bindValue(QLatin1String(":cookieIdvalue"), cookiesIds);
+    sqlQuery.bindValue(QLatin1String(":cookievalue"), cookiesValues);
+    sqlQuery.execBatch();
+    return true;
+}
+
+void SharedCookieJarQt::ensureDatabaseTable()
+{
+    if (!m_database.open()) {
+        qWarning("Can't open cookie database");
+        return;
+    }
+    QSqlQuery sqlQuery(m_database);
+    sqlQuery.prepare(QLatin1String("CREATE TABLE IF NOT EXISTS cookies (cookieId VARCHAR PRIMARY KEY, cookie BLOB);"));
+    sqlQuery.exec();
+}
+
+void SharedCookieJarQt::loadCookies()
+{
+    QList<QNetworkCookie> cookies;
+    QSqlQuery sqlQuery(m_database);
+    sqlQuery.prepare(QLatin1String("SELECT cookie FROM cookies"));
+    sqlQuery.exec();
+    while (sqlQuery.next())
+        cookies.append(QNetworkCookie::parseCookies(sqlQuery.value(0).toByteArray()));
+    setAllCookies(cookies);
+}
+
+#include "moc_CookieJarQt.cpp"
+
 }
 
 // vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/qt/CookieJarQt.h b/Source/WebCore/platform/qt/CookieJarQt.h
new file mode 100644 (file)
index 0000000..96ac71a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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 CookieJarQt_h
+#define CookieJarQt_h
+
+#include <QtCore/QObject>
+#include <QtNetwork/QNetworkCookieJar>
+#include <QtSql/QSqlDatabase>
+
+#include <wtf/HashSet.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class SharedCookieJarQt : public QNetworkCookieJar {
+    Q_OBJECT
+public:
+    static SharedCookieJarQt* shared();
+    static SharedCookieJarQt* create(const String&);
+    void destroy();
+
+    void getHostnamesWithCookies(HashSet<String>&);
+    void deleteCookiesForHostname(const String&);
+    void deleteAllCookies();
+    bool setCookiesFromUrl(const QList<QNetworkCookie>&, const QUrl&);
+    void loadCookies();
+
+private:
+    SharedCookieJarQt(const String&);
+    ~SharedCookieJarQt();
+    void ensureDatabaseTable();
+
+    QSqlDatabase m_database;
+};
+
+}
+
+#endif
index 15f6027..8e65e3e 100644 (file)
@@ -1,3 +1,24 @@
+2011-09-20  Alexis Menard  <alexis.menard@openbossa.org>
+
+        [Qt] [WK2] Implement a persistent cookie storage.
+        https://bugs.webkit.org/show_bug.cgi?id=65309
+
+        Reviewed by Chang Shu.
+
+        Add parameter to the WebProcess creation to specify where cookies should be saved.
+        It also use the new cookie storage implementation and set it to our network stack
+        so cookies are used when using it.
+
+        * Shared/WebProcessCreationParameters.cpp:
+        (WebKit::WebProcessCreationParameters::encode):
+        (WebKit::WebProcessCreationParameters::decode):
+        * Shared/WebProcessCreationParameters.h:
+        * UIProcess/qt/WebContextQt.cpp:
+        (WebKit::WebContext::platformInitializeWebProcess):
+        * WebProcess/qt/WebProcessQt.cpp:
+        (WebKit::WebProcess::platformInitializeWebProcess):
+        (WebKit::WebProcess::platformTerminate):
+
 2011-09-20  Nayan Kumar K  <nayankk@motorola.com>
 
         Added WKHitTestResult API's.
index de52716..30f2444 100644 (file)
@@ -91,6 +91,9 @@ void WebProcessCreationParameters::encode(CoreIPC::ArgumentEncoder* encoder) con
         CoreIPC::encode(encoder, storageSession);
 #endif // USE(CFURLSTORAGESESSIONS)
 #endif
+#if PLATFORM(QT)
+    encoder->encode(cookieStorageDirectory);
+#endif
 }
 
 bool WebProcessCreationParameters::decode(CoreIPC::ArgumentDecoder* decoder, WebProcessCreationParameters& parameters)
@@ -172,6 +175,11 @@ bool WebProcessCreationParameters::decode(CoreIPC::ArgumentDecoder* decoder, Web
 #endif // USE(CFURLSTORAGESESSIONS)
 #endif
 
+#if PLATFORM(QT)
+    if (!decoder->decode(parameters.cookieStorageDirectory))
+        return false;
+#endif
+
     return true;
 }
 
index 0396cfb..9ebfa41 100644 (file)
@@ -111,6 +111,9 @@ struct WebProcessCreationParameters {
     RetainPtr<CFDataRef> serializedDefaultStorageSession;
 #endif // USE(CFURLSTORAGESESSIONS)
 #endif // PLATFORM(WIN)
+#if PLATFORM(QT)
+    String cookieStorageDirectory;
+#endif
 };
 
 } // namespace WebKit
index b46587e..5c6bdad 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "ApplicationCacheStorage.h"
 #include "WebProcessCreationParameters.h"
+#include <QDesktopServices>
 #include <QProcess>
 
 namespace WebKit {
@@ -42,9 +43,10 @@ String WebContext::applicationCacheDirectory()
 #endif
 }
 
-void WebContext::platformInitializeWebProcess(WebProcessCreationParameters&)
+void WebContext::platformInitializeWebProcess(WebProcessCreationParameters& parameters)
 {
     qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
+    parameters.cookieStorageDirectory = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
 }
 
 void WebContext::platformInvalidateContext()
index 919044e..40fb702 100644 (file)
@@ -29,6 +29,8 @@
 #include "WebProcessCreationParameters.h"
 #include <WebCore/RuntimeEnabledFeatures.h>
 #include <QNetworkAccessManager>
+#include <QNetworkCookieJar>
+#include <WebCore/CookieJarQt.h>
 
 namespace WebKit {
 
@@ -44,6 +46,11 @@ void WebProcess::platformClearResourceCaches(ResourceCachesToClear)
 void WebProcess::platformInitializeWebProcess(const WebProcessCreationParameters& parameters, CoreIPC::ArgumentDecoder* arguments)
 {
     m_networkAccessManager = new QNetworkAccessManager;
+    ASSERT(!parameters.cookieStorageDirectory.isEmpty() && !parameters.cookieStorageDirectory.isNull());
+    WebCore::SharedCookieJarQt* jar = WebCore::SharedCookieJarQt::create(parameters.cookieStorageDirectory);
+    m_networkAccessManager->setCookieJar(jar);
+    // Do not let QNetworkAccessManager delete the jar.
+    jar->setParent(0);
 
     // Disable runtime enabled features that have no WebKit2 implementation yet.
 #if ENABLE(DEVICE_ORIENTATION)
@@ -59,6 +66,7 @@ void WebProcess::platformTerminate()
 {
     delete m_networkAccessManager;
     m_networkAccessManager = 0;
+    WebCore::SharedCookieJarQt::shared()->destroy();
 }
 
 } // namespace WebKit