diff options
author | Daniel Carl <danielcarl@gmx.de> | 2016-10-22 23:30:24 +0200 |
---|---|---|
committer | Daniel Carl <danielcarl@gmx.de> | 2017-01-28 01:17:16 +0100 |
commit | 3cb9d54c96219ba68837a6da68c57f6b7c03bbf5 (patch) | |
tree | b6d8d38a8161d0fcc3bfeb4a6b70d798554ee545 /src/webextension | |
parent | f1e576ef069ddcccf4913d68b7ca390688d6a91d (diff) |
Attempt to start dbus server from ui.
Diffstat (limited to 'src/webextension')
-rw-r--r-- | src/webextension/ext-main.c | 317 |
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); } } |