summaryrefslogtreecommitdiff
path: root/src/webextension
diff options
context:
space:
mode:
authorDaniel Carl <danielcarl@gmx.de>2016-10-22 23:30:24 +0200
committerDaniel Carl <danielcarl@gmx.de>2017-01-28 01:17:16 +0100
commit3cb9d54c96219ba68837a6da68c57f6b7c03bbf5 (patch)
treeb6d8d38a8161d0fcc3bfeb4a6b70d798554ee545 /src/webextension
parentf1e576ef069ddcccf4913d68b7ca390688d6a91d (diff)
Attempt to start dbus server from ui.
Diffstat (limited to 'src/webextension')
-rw-r--r--src/webextension/ext-main.c317
1 files changed, 182 insertions, 135 deletions
diff --git a/src/webextension/ext-main.c b/src/webextension/ext-main.c
index a3a8a83..cfc8e01 100644
--- a/src/webextension/ext-main.c
+++ b/src/webextension/ext-main.c
@@ -27,19 +27,26 @@
#include "ext-dom.h"
#include "ext-util.h"
-static void add_onload_event_observers(WebKitDOMDocument *doc);
-static void dbus_emit_signal(const char *name, GVariant *data);
+static gboolean on_authorize_authenticated_peer(GDBusAuthObserver *observer,
+ GIOStream *stream, GCredentials *credentials, gpointer extension);
+static void on_dbus_connection_created(GObject *source_object,
+ GAsyncResult *result, gpointer data);
+static void add_onload_event_observers(WebKitDOMDocument *doc,
+ WebKitWebExtension *extension);
+static void emit_page_created(GDBusConnection *connection, guint64 pageid);
+static void emit_page_created_pending(GDBusConnection *connection);
+static void queue_page_created_signal(guint64 pageid);
+static void dbus_emit_signal(const char *name, WebKitWebExtension* extension,
+ GVariant *data);
static void dbus_handle_method_call(GDBusConnection *conn, const char *sender,
const char *object_path, const char *interface_name, const char *method,
GVariant *parameters, GDBusMethodInvocation *invocation, gpointer data);
-static gboolean dbus_own_name_sync(GDBusConnection *connection, const char *name,
- GBusNameOwnerFlags flags);
-static void on_dbus_name_acquire(GDBusConnection *connection, const char *name, gpointer data);
-static void on_editable_change_focus(WebKitDOMEventTarget *target, WebKitDOMEvent *event);
-static void on_page_created(WebKitWebExtension *ext, WebKitWebPage *page, gpointer data);
-static void on_web_page_document_loaded(WebKitWebPage *page, gpointer data);
-static gboolean on_web_page_send_request(WebKitWebPage *page, WebKitURIRequest *request,
- WebKitURIResponse *response, gpointer data);
+static void on_editable_change_focus(WebKitDOMEventTarget *target,
+ WebKitDOMEvent *event, WebKitWebExtension *extension);
+static void on_page_created(WebKitWebExtension *ext, WebKitWebPage *webpage, gpointer data);
+static void on_web_page_document_loaded(WebKitWebPage *webpage, gpointer extension);
+static gboolean on_web_page_send_request(WebKitWebPage *webpage, WebKitURIRequest *request,
+ WebKitURIResponse *response, gpointer extension);
static const GDBusInterfaceVTable interface_vtable = {
dbus_handle_method_call,
@@ -73,6 +80,7 @@ struct Ext {
GHashTable *headers;
GHashTable *documents;
gboolean input_focus;
+ GArray *page_created_signals;
};
struct Ext ext = {0};
@@ -83,32 +91,79 @@ struct Ext ext = {0};
G_MODULE_EXPORT
void webkit_web_extension_initialize_with_user_data(WebKitWebExtension *extension, GVariant *data)
{
- char *extid, *service_name;
- g_variant_get(data, "(s)", &extid);
+ char *server_address;
+ GDBusAuthObserver *observer;
- /* Get the DBus connection for the bus type. It would be a better to use
- * the async g_bus_own_name for this, but this leads to cases where pages
- * are created and documents are loaded before we get a name and are able
- * to call to the UI process. */
- ext.connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
+ g_variant_get(data, "(ms)", &server_address);
+ if (!server_address) {
+ g_warning("UI process did not start D-Bus server");
+ return;
+ }
+
+ g_signal_connect(extension, "page-created", G_CALLBACK(on_page_created), NULL);
+
+ observer = g_dbus_auth_observer_new();
+ g_signal_connect(observer, "authorize-authenticated-peer",
+ G_CALLBACK(on_authorize_authenticated_peer), extension);
+
+ g_dbus_connection_new_for_address(server_address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, observer, NULL,
+ (GAsyncReadyCallback)on_dbus_connection_created, extension);
+ g_object_unref(observer);
+}
+
+static gboolean on_authorize_authenticated_peer(GDBusAuthObserver *observer,
+ GIOStream *stream, GCredentials *credentials, gpointer extension)
+{
+ /* FIXME require authentication logic */
+ return TRUE;
+}
- service_name = g_strdup_printf("%s-%s", VB_WEBEXTENSION_SERVICE_NAME, extid);
+static void on_dbus_connection_created(GObject *source_object,
+ GAsyncResult *result, gpointer data)
+{
+ static GDBusNodeInfo *node_info = NULL;
+ GDBusConnection *connection;
+ GError *error = NULL;
- /* Try to own name synchronously. */
- if (ext.connection && dbus_own_name_sync(ext.connection, service_name, G_BUS_NAME_OWNER_FLAGS_NONE)) {
- on_dbus_name_acquire(ext.connection, service_name, extension);
+ if (!node_info) {
+ node_info = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
}
- g_free(service_name);
+ connection = g_dbus_connection_new_for_address_finish(result, &error);
+ if (error) {
+ g_warning("Failed to connect to UI process: %s", error->message);
+ g_error_free(error);
+ return;
+ }
- g_signal_connect(extension, "page-created", G_CALLBACK(on_page_created), NULL);
+ /* register the webextension object */
+ ext.regid = g_dbus_connection_register_object(
+ connection,
+ VB_WEBEXTENSION_OBJECT_PATH,
+ node_info->interfaces[0],
+ &interface_vtable,
+ WEBKIT_WEB_EXTENSION(data),
+ NULL,
+ &error);
+
+ if (!ext.regid) {
+ g_warning("Failed to register web extension object: %s", error->message);
+ g_error_free(error);
+ g_object_unref(connection);
+ return;
+ }
+
+ emit_page_created_pending(connection);
+ ext.connection = connection;
}
/**
* Add observers to doc event for given document and all the contained iframes
* too.
*/
-static void add_onload_event_observers(WebKitDOMDocument *doc)
+static void add_onload_event_observers(WebKitDOMDocument *doc,
+ WebKitWebExtension *extension)
{
WebKitDOMEventTarget *target;
@@ -117,20 +172,72 @@ static void add_onload_event_observers(WebKitDOMDocument *doc)
if (!g_hash_table_add(ext.documents, doc)) {
return;
}
-
+
/* We have to use default view instead of the document itself in case this
* function is called with content document of an iframe. Else the event
* observing does not work. */
- target = WEBKIT_DOM_EVENT_TARGET(webkit_dom_document_get_default_view(doc));
+ target = WEBKIT_DOM_EVENT_TARGET(webkit_dom_document_get_default_view(doc));
webkit_dom_event_target_add_event_listener(target, "focus",
- G_CALLBACK(on_editable_change_focus), TRUE, NULL);
+ G_CALLBACK(on_editable_change_focus), TRUE, extension);
webkit_dom_event_target_add_event_listener(target, "blur",
- G_CALLBACK(on_editable_change_focus), TRUE, NULL);
+ G_CALLBACK(on_editable_change_focus), TRUE, extension);
/* Check for focused editable elements also if they where focused before
* the event observer where set up. */
/* TODO this is not needed for strict-focus=on */
- on_editable_change_focus(target, NULL);
+ on_editable_change_focus(target, NULL, extension);
+}
+
+/**
+ * Emit the page created signal that is used in the ui process to finish the
+ * dbus proxy connection.
+ */
+static void emit_page_created(GDBusConnection *connection, guint64 pageid)
+{
+ GError *error = NULL;
+
+ /* propagate the signal over dbus */
+ g_dbus_connection_emit_signal(G_DBUS_CONNECTION(connection), NULL,
+ VB_WEBEXTENSION_OBJECT_PATH, VB_WEBEXTENSION_INTERFACE,
+ "PageCreated", g_variant_new("(t)", pageid), &error);
+
+ if (error) {
+ g_warning("Failed to emit signal PageCreated: %s", error->message);
+ g_error_free(error);
+ }
+}
+
+/**
+ * Emit queued page created signals.
+ */
+static void emit_page_created_pending(GDBusConnection *connection)
+{
+ int i;
+ guint64 pageid;
+
+ if (!ext.page_created_signals) {
+ return;
+ }
+
+ for (i = 0; i < ext.page_created_signals->len; i++) {
+ pageid = g_array_index(ext.page_created_signals, guint64, i);
+ emit_page_created(connection, pageid);
+ }
+
+ g_array_free(ext.page_created_signals, TRUE);
+ ext.page_created_signals = NULL;
+}
+
+/**
+ * Write the page id of the created page to a queue to send them to the ui
+ * process when the dbus connection is established.
+ */
+static void queue_page_created_signal(guint64 pageid)
+{
+ if (!ext.page_created_signals) {
+ ext.page_created_signals = g_array_new(FALSE, FALSE, sizeof(guint64));
+ }
+ ext.page_created_signals = g_array_append_val(ext.page_created_signals, pageid);
}
/**
@@ -139,11 +246,11 @@ static void add_onload_event_observers(WebKitDOMDocument *doc)
* @name: Signal name to emit.
* @data: GVariant value used as value for the signal or NULL.
*/
-static void dbus_emit_signal(const char *name, GVariant *data)
+static void dbus_emit_signal(const char *name, WebKitWebExtension* extension,
+ GVariant *data)
{
GError *error = NULL;
- /* Don't do anythings if the dbus connection was not established. */
if (!ext.connection) {
return;
}
@@ -152,8 +259,6 @@ static void dbus_emit_signal(const char *name, GVariant *data)
g_dbus_connection_emit_signal(ext.connection, NULL,
VB_WEBEXTENSION_OBJECT_PATH, VB_WEBEXTENSION_INTERFACE, name,
data, &error);
-
- /* check for error */
if (error) {
g_warning("Failed to emit signal '%s': %s", name, error->message);
g_error_free(error);
@@ -165,7 +270,7 @@ static void dbus_emit_signal(const char *name, GVariant *data)
*/
static void dbus_handle_method_call(GDBusConnection *conn, const char *sender,
const char *object_path, const char *interface_name, const char *method,
- GVariant *parameters, GDBusMethodInvocation *invocation, gpointer data)
+ GVariant *parameters, GDBusMethodInvocation *invocation, gpointer extension)
{
char *value;
@@ -185,83 +290,12 @@ static void dbus_handle_method_call(GDBusConnection *conn, const char *sender,
}
/**
- * The synchronous and blocking pendent to the g_bus_own_name().
- *
- * @bus_type: The type of bus to own a name on.
- * @name: The well-known name to own.
- * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
- */
-static gboolean dbus_own_name_sync(GDBusConnection *connection, const char *name,
- GBusNameOwnerFlags flags)
-{
- GError *error = NULL;
- guint32 request_name_reply = 0;
- GVariant *result;
-
- result = g_dbus_connection_call_sync(
- connection,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "RequestName",
- g_variant_new("(su)", name, flags),
- G_VARIANT_TYPE("(u)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
-
- if (result) {
- g_variant_get(result, "(u)", &request_name_reply);
- g_variant_unref(result);
-
- if (1 == request_name_reply) {
- return TRUE;
- }
- } else {
- g_warning("Failed to acquire DBus name: %s", error->message);
- g_error_free(error);
- }
- return FALSE;
-}
-
-/**
- * Called when the dbus name is aquired and registers our object.
- */
-static void on_dbus_name_acquire(GDBusConnection *connection, const char *name, gpointer data)
-{
- GError *error = NULL;
- static GDBusNodeInfo *node_info = NULL;
-
- g_return_if_fail(G_IS_DBUS_CONNECTION(connection));
-
- if (!node_info) {
- node_info = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
- }
-
- /* register the webextension object */
- ext.connection = connection;
- ext.regid = g_dbus_connection_register_object(
- connection,
- VB_WEBEXTENSION_OBJECT_PATH,
- node_info->interfaces[0],
- &interface_vtable,
- WEBKIT_WEB_EXTENSION(data),
- NULL,
- &error);
-
- if (!ext.regid) {
- g_warning("Failed to register web extension object: %s", error->message);
- g_error_free(error);
- }
-}
-
-/**
* Callback called if a editable element changes it focus state.
* Event target may be a WebKitDOMDocument (in case of iframe) or a
* WebKitDOMDOMWindow.
*/
-static void on_editable_change_focus(WebKitDOMEventTarget *target, WebKitDOMEvent *event)
+static void on_editable_change_focus(WebKitDOMEventTarget *target,
+ WebKitDOMEvent *event, WebKitWebExtension *extension)
{
gboolean input_focus;
WebKitDOMDocument *doc;
@@ -285,7 +319,7 @@ static void on_editable_change_focus(WebKitDOMEventTarget *target, WebKitDOMEven
iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT(active);
subdoc = webkit_dom_html_iframe_element_get_content_document(iframe);
- add_onload_event_observers(subdoc);
+ add_onload_event_observers(subdoc, extension);
return;
}
@@ -296,30 +330,36 @@ static void on_editable_change_focus(WebKitDOMEventTarget *target, WebKitDOMEven
if (input_focus != ext.input_focus) {
ext.input_focus = input_focus;
- dbus_emit_signal("EditableChangeFocus", g_variant_new("(b)", input_focus));
+ dbus_emit_signal("EditableChangeFocus", extension,
+ g_variant_new("(b)", input_focus));
}
}
/**
* Callback for web extensions page-created signal.
*/
-static void on_page_created(WebKitWebExtension *extension, WebKitWebPage *page, gpointer data)
+static void on_page_created(WebKitWebExtension *extension, WebKitWebPage *webpage, gpointer data)
{
+ guint64 pageid = webkit_web_page_get_id(webpage);
+
/* Save the new created page in the extension data for later use. */
- ext.webpage = page;
+ ext.webpage = webpage;
+ if (ext.connection) {
+ emit_page_created(ext.connection, pageid);
+ } else {
+ queue_page_created_signal(pageid);
+ }
- g_object_connect(page,
- "signal::send-request", G_CALLBACK(on_web_page_send_request), NULL,
- "signal::document-loaded", G_CALLBACK(on_web_page_document_loaded), NULL,
+ g_object_connect(webpage,
+ "signal::send-request", G_CALLBACK(on_web_page_send_request), extension,
+ "signal::document-loaded", G_CALLBACK(on_web_page_document_loaded), extension,
NULL);
-
- dbus_emit_signal("PageCreated", g_variant_new("(t)", webkit_web_page_get_id(page)));
}
/**
* Callback for web pages document-loaded signal.
*/
-static void on_web_page_document_loaded(WebKitWebPage *page, gpointer data)
+static void on_web_page_document_loaded(WebKitWebPage *webpage, gpointer extension)
{
/* If there is a hashtable of known document - detroy this and create a
* new hashtable. */
@@ -328,31 +368,38 @@ static void on_web_page_document_loaded(WebKitWebPage *page, gpointer data)
}
ext.documents = g_hash_table_new(g_direct_hash, g_direct_equal);
- add_onload_event_observers(webkit_web_page_get_dom_document(page));
+ add_onload_event_observers(webkit_web_page_get_dom_document(webpage),
+ WEBKIT_WEB_EXTENSION(extension));
}
/**
* Callback for web pages send-request signal.
*/
-static gboolean on_web_page_send_request(WebKitWebPage *page, WebKitURIRequest *request,
- WebKitURIResponse *response, gpointer data)
+static gboolean on_web_page_send_request(WebKitWebPage *webpage, WebKitURIRequest *request,
+ WebKitURIResponse *response, gpointer extension)
{
+ char *name, *value;
+ SoupMessageHeaders *headers;
+ GHashTableIter iter;
+
+ if (!ext.headers) {
+ return FALSE;
+ }
+
/* Change request headers according to the users preferences. */
- if (ext.headers) {
- char *name, *value;
- SoupMessageHeaders *headers;
- GHashTableIter iter;
-
- headers = webkit_uri_request_get_http_headers(request);
- g_hash_table_iter_init(&iter, ext.headers);
- while (g_hash_table_iter_next(&iter, (gpointer*)&name, (gpointer*)&value)) {
- /* Null value is used to indicate that the header should be
- * removed completely. */
- if (value == NULL) {
- soup_message_headers_remove(headers, name);
- } else {
- soup_message_headers_replace(headers, name, value);
- }
+ headers = webkit_uri_request_get_http_headers(request);
+ if (!headers) {
+ return FALSE;
+ }
+
+ g_hash_table_iter_init(&iter, ext.headers);
+ while (g_hash_table_iter_next(&iter, (gpointer*)&name, (gpointer*)&value)) {
+ /* Null value is used to indicate that the header should be
+ * removed completely. */
+ if (value == NULL) {
+ soup_message_headers_remove(headers, name);
+ } else {
+ soup_message_headers_replace(headers, name, value);
}
}