Commit 4c113670 authored by commit-queue@webkit.org's avatar commit-queue@webkit.org
Browse files

[GTK] Allow passing extra data to web extensions

https://bugs.webkit.org/show_bug.cgi?id=125990

Patch by Adrian Perez de Castro <aperez@igalia.com> on 2014-01-21
Reviewed by Carlos Garcia Campos.

Allow passing additional information to the injected bundle. On top
of the string containing the path to the web extensions directory,
a GVariant can be set with additional data using
webkit_web_context_set_web_extensions_initialization_user_data().
Also, a new initialize-web-extensions signal is emitted before
launching a new WebProcess to allow setting different user data
for each process. The GVariant is serialized as a string, passed
to the injected bundle, and the injected bundle deserializes back
the data, which is passed to web extensions which define the
webkit_web_extension_initialize_with_user_data() function (for
backwards compatibility, webkit_web_extension_initialize() is
used as a fallback.)

Source/WebKit2:

* UIProcess/API/gtk/WebKitInjectedBundleClient.cpp:
(getInjectedBundleInitializationUserData): Define new callback
function which causes emission of the initialize-web-extensions
signal, and serializes the data to be passed to the web process.
(attachInjectedBundleClientToContext): Set the
getInjectedBundleInitializationUserData() callback.
* UIProcess/API/gtk/WebKitWebContext.cpp:
(webkit_web_context_class_init): Define the
initialize-web-extensions signal.
(webkit_web_context_set_web_extensions_directory):
Web extensions directory as now member of WebKitWebContextPrivate,
to be able to retrieve it later.
(webkit_web_context_set_web_extensions_initialization_user_data):
New API method to set the user data passed to the web extensions
when initialized.
(webkitWebContextInitializeWebExtensions): Private function used
to trigger emission of the initialize-web-extensions signal.
* UIProcess/API/gtk/WebKitWebContext.h:
Added prototype for new API method
webkit_web_context_set_web_extensions_initialization_user_data().
* UIProcess/API/gtk/WebKitWebContextPrivate.h:
Prototype of the new private function.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt:
Add new public API bits to the documentation.
* WebProcess/gtk/WebGtkExtensionManager.cpp:
(WebKit::WebGtkExtensionManager::initialize):
Deserialize the data received from the UI process and pass it to
webkit_web_extension_initialize_with_user_data() if available,
keeping webkit_web_extension_initialize() as fallback.

Tools:

* TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp:
(initializeWebExtensions): Handles the initialize-web-extensions
signal, and sets the web extensions directory and the initialization
user data.
(testWebExtensionInitializationUserData): New test case for checking
the user data passed on initialization to web extensions.
* TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp:
(methodCallCallback): Added implementation for the
GetInitializationUserData D-Bus method, used by
testWebExtensionInitializationUserData().
(webkit_web_extension_initialize_with_user_data): Define the
initialization function with the additional user data parameter.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@162441 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ab31fb6f
2014-01-21 Adrian Perez de Castro <aperez@igalia.com>
[GTK] Allow passing extra data to web extensions
https://bugs.webkit.org/show_bug.cgi?id=125990
Reviewed by Carlos Garcia Campos.
Allow passing additional information to the injected bundle. On top
of the string containing the path to the web extensions directory,
a GVariant can be set with additional data using
webkit_web_context_set_web_extensions_initialization_user_data().
Also, a new initialize-web-extensions signal is emitted before
launching a new WebProcess to allow setting different user data
for each process. The GVariant is serialized as a string, passed
to the injected bundle, and the injected bundle deserializes back
the data, which is passed to web extensions which define the
webkit_web_extension_initialize_with_user_data() function (for
backwards compatibility, webkit_web_extension_initialize() is
used as a fallback.)
* UIProcess/API/gtk/WebKitInjectedBundleClient.cpp:
(getInjectedBundleInitializationUserData): Define new callback
function which causes emission of the initialize-web-extensions
signal, and serializes the data to be passed to the web process.
(attachInjectedBundleClientToContext): Set the
getInjectedBundleInitializationUserData() callback.
* UIProcess/API/gtk/WebKitWebContext.cpp:
(webkit_web_context_class_init): Define the
initialize-web-extensions signal.
(webkit_web_context_set_web_extensions_directory):
Web extensions directory as now member of WebKitWebContextPrivate,
to be able to retrieve it later.
(webkit_web_context_set_web_extensions_initialization_user_data):
New API method to set the user data passed to the web extensions
when initialized.
(webkitWebContextInitializeWebExtensions): Private function used
to trigger emission of the initialize-web-extensions signal.
* UIProcess/API/gtk/WebKitWebContext.h:
Added prototype for new API method
webkit_web_context_set_web_extensions_initialization_user_data().
* UIProcess/API/gtk/WebKitWebContextPrivate.h:
Prototype of the new private function.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt:
Add new public API bits to the documentation.
* WebProcess/gtk/WebGtkExtensionManager.cpp:
(WebKit::WebGtkExtensionManager::initialize):
Deserialize the data received from the UI process and pass it to
webkit_web_extension_initialize_with_user_data() if available,
keeping webkit_web_extension_initialize() as fallback.
2014-01-20 Ryuan Choi <ryuan.choi@samsung.com>
 
[EFL][WK2] Move isEwkViewEvasObject back to ewk_view.cpp
......
......@@ -118,16 +118,23 @@ static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messag
ASSERT_NOT_REACHED();
}
static WKTypeRef getInjectedBundleInitializationUserData(WKContextRef, const void* clientInfo)
{
GRefPtr<GVariant> data = webkitWebContextInitializeWebExtensions(WEBKIT_WEB_CONTEXT(clientInfo));
GOwnPtr<gchar> dataString(g_variant_print(data.get(), TRUE));
return static_cast<WKTypeRef>(WKStringCreateWithUTF8CString(dataString.get()));
}
void attachInjectedBundleClientToContext(WebKitWebContext* webContext)
{
WKContextInjectedBundleClientV1 wkInjectedBundleClient = {
{
0, // version
1, // version
webContext, // clientInfo
},
didReceiveMessageFromInjectedBundle,
0, // didReceiveSynchronousMessageFromInjectedBundle
0 // getInjectedBundleInitializationUserData
getInjectedBundleInitializationUserData
};
WKContextSetInjectedBundleClient(toAPI(webkitWebContextGetContext(webContext)), &wkInjectedBundleClient.base);
}
......@@ -84,6 +84,7 @@ using namespace WebKit;
enum {
DOWNLOAD_STARTED,
INITIALIZE_WEB_EXTENSIONS,
LAST_SIGNAL
};
......@@ -153,6 +154,9 @@ struct _WebKitWebContextPrivate {
HashMap<uint64_t, WebKitWebView*> webViews;
GRefPtr<WebKitWebViewGroup> defaultWebViewGroup;
CString webExtensionsDirectory;
GRefPtr<GVariant> webExtensionsInitializationUserData;
};
static guint signals[LAST_SIGNAL] = { 0, };
......@@ -178,6 +182,25 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
WEBKIT_TYPE_DOWNLOAD);
/**
* WebKitWebContext::initialize-web-extensions:
* @context: the #WebKitWebContext
*
* This signal is emitted when a new web process is about to be
* launched. It signals the most appropriate moment to use
* webkit_web_context_set_web_extensions_initialization_user_data()
* and webkit_web_context_set_web_extensions_directory().
*
* Since: 2.4
*/
signals[INITIALIZE_WEB_EXTENSIONS] =
g_signal_new("initialize-web-extensions",
G_TYPE_FROM_CLASS(gObjectClass),
G_SIGNAL_RUN_LAST,
0, nullptr, nullptr,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static CString injectedBundleDirectory()
......@@ -775,16 +798,40 @@ WebKitTLSErrorsPolicy webkit_web_context_get_tls_errors_policy(WebKitWebContext*
* @directory: the directory to add
*
* Set the directory where WebKit will look for Web Extensions.
* This method must be called before loading anything in this context, otherwise
* it will not have any effect.
* This method must be called before loading anything in this context,
* otherwise it will not have any effect. You can connect to
* #WebKitWebContext::initialize-web-extensions to call this method
* before anything is loaded.
*/
void webkit_web_context_set_web_extensions_directory(WebKitWebContext* context, const char* directory)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(directory);
// We pass the additional web extensions directory to the injected bundle as initialization user data.
context->priv->context->setInjectedBundleInitializationUserData(API::String::create(WebCore::filenameToString(directory)));
context->priv->webExtensionsDirectory = directory;
}
/**
* webkit_web_context_set_web_extensions_initialization_user_data:
* @context: a #WebKitWebContext
* @user_data: a #GVariant
*
* Set user data to be passed to Web Extensions on initialization.
* The data will be passed to the
* #WebKitWebExtensionInitializeWithUserDataFunction.
* This method must be called before loading anything in this context,
* otherwise it will not have any effect. You can connect to
* #WebKitWebContext::initialize-web-extensions to call this method
* before anything is loaded.
*
* Since: 2.4
*/
void webkit_web_context_set_web_extensions_initialization_user_data(WebKitWebContext* context, GVariant* userData)
{
g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
g_return_if_fail(userData);
context->priv->webExtensionsInitializationUserData = userData;
}
/**
......@@ -872,6 +919,14 @@ void webkitWebContextDownloadStarted(WebKitWebContext* context, WebKitDownload*
g_signal_emit(context, signals[DOWNLOAD_STARTED], 0, download);
}
GVariant* webkitWebContextInitializeWebExtensions(WebKitWebContext* context)
{
g_signal_emit(context, signals[INITIALIZE_WEB_EXTENSIONS], 0);
return g_variant_new("(msmv)",
context->priv->webExtensionsDirectory.data(),
context->priv->webExtensionsInitializationUserData.get());
}
WebContext* webkitWebContextGetContext(WebKitWebContext* context)
{
g_assert(WEBKIT_IS_WEB_CONTEXT(context));
......
......@@ -195,6 +195,11 @@ WEBKIT_API void
webkit_web_context_set_web_extensions_directory (WebKitWebContext *context,
const gchar *directory);
WEBKIT_API void
webkit_web_context_set_web_extensions_initialization_user_data
(WebKitWebContext *context,
GVariant *user_data);
WEBKIT_API void
webkit_web_context_prefetch_dns (WebKitWebContext *context,
const gchar *hostname);
......
......@@ -47,5 +47,6 @@ void webkitWebContextCreatePageForWebView(WebKitWebContext*, WebKitWebView*, Web
void webkitWebContextWebViewDestroyed(WebKitWebContext*, WebKitWebView*);
WebKitWebView* webkitWebContextGetWebViewForPage(WebKitWebContext*, WebKit::WebPageProxy*);
WebKitWebViewGroup* webkitWebContextGetDefaultWebViewGroup(WebKitWebContext*);
GVariant* webkitWebContextInitializeWebExtensions(WebKitWebContext*);
#endif // WebKitWebContextPrivate_h
......@@ -46,6 +46,7 @@ webkit_web_context_set_preferred_languages
webkit_web_context_set_tls_errors_policy
webkit_web_context_get_tls_errors_policy
webkit_web_context_set_web_extensions_directory
webkit_web_context_set_web_extensions_initialization_user_data
webkit_web_context_prefetch_dns
webkit_web_context_set_disk_cache_directory
webkit_web_context_allow_tls_certificate_for_host
......@@ -1026,6 +1027,7 @@ webkit_web_view_group_get_type
<FILE>WebKitWebExtension</FILE>
WebKitWebExtension
WebKitWebExtensionInitializeFunction
WebKitWebExtensionInitializeWithUserDataFunction
webkit_web_extension_get_page
<SUBSECTION Standard>
......
......@@ -50,6 +50,21 @@ typedef struct _WebKitWebExtensionPrivate WebKitWebExtensionPrivate;
*/
typedef void (* WebKitWebExtensionInitializeFunction) (WebKitWebExtension *extension);
/**
* WebKitWebExtensionInitializeWithUserDataFunction:
* @extension: a #WebKitWebExtension
* @user_data: a #GVariant
*
* Type definition for a function that will be called to initialize
* the web extensions when the web process starts, and which receives
* as additional argument the user data set with
* webkit_web_context_set_web_extensions_initialization_user_data().
*
* Since: 2.4
*/
typedef void (* WebKitWebExtensionInitializeWithUserDataFunction) (WebKitWebExtension *extension,
const GVariant *user_data);
struct _WebKitWebExtension {
GObject parent;
......
......@@ -22,11 +22,13 @@
#include "InjectedBundle.h"
#include "WKBundleAPICast.h"
#include "WKDictionary.h"
#include "WKString.h"
#include "WKType.h"
#include "WebKitWebExtensionPrivate.h"
#include <WebCore/FileSystem.h>
#include <wtf/OwnPtr.h>
#include <wtf/text/CString.h>
namespace WebKit {
......@@ -49,19 +51,56 @@ void WebGtkExtensionManager::scanModules(const String& webExtensionsDirectory, V
}
}
void WebGtkExtensionManager::initialize(WKBundleRef bundle, WKTypeRef userData)
static void parseUserData(WKTypeRef userData, String& webExtensionsDirectory, GRefPtr<GVariant>& initializationUserData)
{
m_extension = adoptGRef(webkitWebExtensionCreate(toImpl(bundle)));
ASSERT(userData);
ASSERT(WKGetTypeID(userData) == WKStringGetTypeID());
String webExtensionsDirectory;
if (userData) {
ASSERT(WKGetTypeID(userData) == WKStringGetTypeID());
webExtensionsDirectory = toImpl(static_cast<WKStringRef>(userData))->string();
CString userDataString = toImpl(static_cast<WKStringRef>(userData))->string().utf8();
GRefPtr<GVariant> variant = g_variant_parse(nullptr, userDataString.data(),
userDataString.data() + userDataString.length(), nullptr, nullptr);
ASSERT(variant);
ASSERT(g_variant_check_format_string(variant.get(), "(m&smv)", FALSE));
const char* directory = nullptr;
GVariant* data = nullptr;
g_variant_get(variant.get(), "(m&smv)", &directory, &data);
webExtensionsDirectory = WebCore::filenameToString(directory);
initializationUserData = adoptGRef(data);
}
bool WebGtkExtensionManager::initializeWebExtension(Module* extensionModule, GVariant* userData)
{
WebKitWebExtensionInitializeWithUserDataFunction initializeWithUserDataFunction =
extensionModule->functionPointer<WebKitWebExtensionInitializeWithUserDataFunction>("webkit_web_extension_initialize_with_user_data");
if (initializeWithUserDataFunction) {
initializeWithUserDataFunction(m_extension.get(), userData);
return true;
}
WebKitWebExtensionInitializeFunction initializeFunction =
extensionModule->functionPointer<WebKitWebExtensionInitializeFunction>("webkit_web_extension_initialize");
if (initializeFunction) {
initializeFunction(m_extension.get());
return true;
}
return false;
}
void WebGtkExtensionManager::initialize(WKBundleRef bundle, WKTypeRef userDataString)
{
String webExtensionsDirectory;
GRefPtr<GVariant> userData;
parseUserData(userDataString, webExtensionsDirectory, userData);
if (webExtensionsDirectory.isNull())
return;
m_extension = adoptGRef(webkitWebExtensionCreate(toImpl(bundle)));
Vector<String> modulePaths;
scanModules(webExtensionsDirectory, modulePaths);
......@@ -69,14 +108,8 @@ void WebGtkExtensionManager::initialize(WKBundleRef bundle, WKTypeRef userData)
OwnPtr<Module> module = adoptPtr(new Module(modulePaths[i]));
if (!module->load())
continue;
WebKitWebExtensionInitializeFunction initializeFunction =
module->functionPointer<WebKitWebExtensionInitializeFunction>("webkit_web_extension_initialize");
if (!initializeFunction)
continue;
m_extensionModules.append(module.leakPtr());
initializeFunction(m_extension.get());
if (initializeWebExtension(module.get(), userData.get()))
m_extensionModules.append(module.leakPtr());
}
}
......
......@@ -46,6 +46,7 @@ private:
WebGtkExtensionManager();
void scanModules(const String&, Vector<String>&);
bool initializeWebExtension(Module* extensionModule, GVariant* userData);
Vector<Module*> m_extensionModules;
GRefPtr<WebKitWebExtension> m_extension;
......
2014-01-21 Adrian Perez de Castro <aperez@igalia.com>
[GTK] Allow passing extra data to web extensions
https://bugs.webkit.org/show_bug.cgi?id=125990
Reviewed by Carlos Garcia Campos.
Allow passing additional information to the injected bundle. On top
of the string containing the path to the web extensions directory,
a GVariant can be set with additional data using
webkit_web_context_set_web_extensions_initialization_user_data().
Also, a new initialize-web-extensions signal is emitted before
launching a new WebProcess to allow setting different user data
for each process. The GVariant is serialized as a string, passed
to the injected bundle, and the injected bundle deserializes back
the data, which is passed to web extensions which define the
webkit_web_extension_initialize_with_user_data() function (for
backwards compatibility, webkit_web_extension_initialize() is
used as a fallback.)
* TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp:
(initializeWebExtensions): Handles the initialize-web-extensions
signal, and sets the web extensions directory and the initialization
user data.
(testWebExtensionInitializationUserData): New test case for checking
the user data passed on initialization to web extensions.
* TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp:
(methodCallCallback): Added implementation for the
GetInitializationUserData D-Bus method, used by
testWebExtensionInitializationUserData().
(webkit_web_extension_initialize_with_user_data): Define the
initialization function with the additional user data parameter.
2014-01-21 Siddharth Mathur <s.mathur@ieee.org>
 
Change my email address in contributors.json.
......
......@@ -23,6 +23,7 @@
#include "WebViewTest.h"
#include <wtf/gobject/GRefPtr.h>
static const char* webExtensionsUserData = "Web Extensions user data";
static WebKitTestBus* bus;
static void testWebExtensionGetTitle(WebViewTest* test, gconstpointer)
......@@ -175,13 +176,44 @@ static void testWebExtensionIsolatedWorld(WebViewTest* test, gconstpointer)
g_signal_handler_disconnect(test->m_webView, scriptDialogID);
}
static void testWebExtensionInitializationUserData(WebViewTest* test, gconstpointer)
{
test->loadHtml("<html></html>", 0);
test->waitUntilLoadFinished();
GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
"/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(
proxy.get(),
"GetInitializationUserData",
nullptr,
G_DBUS_CALL_FLAGS_NONE,
-1, 0, 0));
g_assert(result);
const gchar* userData = nullptr;
g_variant_get(result.get(), "(&s)", &userData);
g_assert_cmpstr(userData, ==, webExtensionsUserData);
}
static void initializeWebExtensions(WebKitWebContext* context, gpointer)
{
webkit_web_context_set_web_extensions_directory(context, WEBKIT_TEST_WEB_EXTENSIONS_DIR);
webkit_web_context_set_web_extensions_initialization_user_data(context,
g_variant_new("&s", webExtensionsUserData));
}
void beforeAll()
{
webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
g_signal_connect(webkit_web_context_get_default(),
"initialize-web-extensions", G_CALLBACK(initializeWebExtensions), nullptr);
bus = new WebKitTestBus();
if (!bus->run())
return;
WebViewTest::add("WebKitWebContext", "initialization-user-data", testWebExtensionInitializationUserData);
WebViewTest::add("WebKitWebExtension", "dom-document-title", testWebExtensionGetTitle);
WebViewTest::add("WebKitWebExtension", "document-loaded-signal", testDocumentLoadedSignal);
WebViewTest::add("WebKitWebView", "web-process-crashed", testWebKitWebViewProcessCrashed);
......
......@@ -45,6 +45,9 @@ static const char introspectionXML[] =
" <arg type='t' name='pageID' direction='in'/>"
" <arg type='s' name='script' direction='in'/>"
" </method>"
" <method name='GetInitializationUserData'>"
" <arg type='s' name='userData' direction='out'/>"
" </method>"
" <signal name='DocumentLoaded'/>"
" <signal name='URIChanged'>"
" <arg type='s' name='uri' direction='out'/>"
......@@ -52,6 +55,9 @@ static const char introspectionXML[] =
" </interface>"
"</node>";
static GRefPtr<GVariant> initializationUserData;
typedef enum {
DocumentLoadedSignal,
URIChangedSignal,
......@@ -210,8 +216,14 @@ static void methodCallCallback(GDBusConnection* connection, const char* sender,
JSRetainPtr<JSStringRef> jsScript(Adopt, JSStringCreateWithUTF8CString(script));
JSEvaluateScript(jsContext, jsScript.get(), 0, 0, 0, 0);
g_dbus_method_invocation_return_value(invocation, 0);
} else if (!g_strcmp0(methodName, "AbortProcess"))
} else if (!g_strcmp0(methodName, "AbortProcess")) {
abort();
} else if (!g_strcmp0(methodName, "GetInitializationUserData")) {
g_assert(initializationUserData);
g_assert(g_variant_is_of_type(initializationUserData.get(), G_VARIANT_TYPE_STRING));
g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)",
g_variant_get_string(initializationUserData.get(), nullptr)));
}
}
static const GDBusInterfaceVTable interfaceVirtualTable = {
......@@ -250,8 +262,10 @@ static void busAcquiredCallback(GDBusConnection* connection, const char* name, g
}
}
extern "C" void webkit_web_extension_initialize(WebKitWebExtension* extension)
extern "C" void webkit_web_extension_initialize_with_user_data(WebKitWebExtension* extension, GVariant* userData)
{
initializationUserData = userData;
g_signal_connect(extension, "page-created", G_CALLBACK(pageCreatedCallback), extension);
g_signal_connect(webkit_script_world_get_default(), "window-object-cleared", G_CALLBACK(windowObjectCleared), 0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment