Commit b7381c71 authored by Carlos Garcia Campos's avatar Carlos Garcia Campos Committed by Carlos Garcia Campos

Use the new WebKit user messages API instead of DBus

It simplifies the code a lot and it's also a lot more efficient.
parent 00a63a01
This diff is collapsed.
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Copyright © 2014 Igalia S.L.
*
* This file is part of Epiphany.
*
* Epiphany 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, either version 3 of the License, or
* (at your option) any later version.
*
* Epiphany 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 Epiphany. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "ephy-web-process-extension-proxy.h"
#include "ephy-dbus-names.h"
#include "ephy-history-service.h"
struct _EphyWebProcessExtensionProxy {
GObject parent_instance;
GCancellable *cancellable;
GDBusProxy *proxy;
GDBusConnection *connection;
guint page_created_signal_id;
};
enum {
PAGE_CREATED,
CONNECTION_CLOSED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE (EphyWebProcessExtensionProxy, ephy_web_process_extension_proxy, G_TYPE_OBJECT)
static void
ephy_web_process_extension_proxy_dispose (GObject *object)
{
EphyWebProcessExtensionProxy *web_process_extension = EPHY_WEB_PROCESS_EXTENSION_PROXY (object);
if (web_process_extension->page_created_signal_id > 0) {
g_dbus_connection_signal_unsubscribe (web_process_extension->connection,
web_process_extension->page_created_signal_id);
web_process_extension->page_created_signal_id = 0;
}
if (web_process_extension->cancellable) {
g_cancellable_cancel (web_process_extension->cancellable);
g_clear_object (&web_process_extension->cancellable);
}
g_clear_object (&web_process_extension->proxy);
g_clear_object (&web_process_extension->connection);
G_OBJECT_CLASS (ephy_web_process_extension_proxy_parent_class)->dispose (object);
}
static void
ephy_web_process_extension_proxy_init (EphyWebProcessExtensionProxy *web_process_extension)
{
}
static void
ephy_web_process_extension_proxy_class_init (EphyWebProcessExtensionProxyClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = ephy_web_process_extension_proxy_dispose;
signals[PAGE_CREATED] =
g_signal_new ("page-created",
EPHY_TYPE_WEB_PROCESS_EXTENSION_PROXY,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_UINT64);
signals[CONNECTION_CLOSED] =
g_signal_new ("connection-closed",
EPHY_TYPE_WEB_PROCESS_EXTENSION_PROXY,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
web_process_extension_page_created (GDBusConnection *connection,
const char *sender_name,
const char *object_path,
const char *interface_name,
const char *signal_name,
GVariant *parameters,
EphyWebProcessExtensionProxy *web_process_extension)
{
guint64 page_id;
g_variant_get (parameters, "(t)", &page_id);
g_signal_emit (web_process_extension, signals[PAGE_CREATED], 0, page_id);
}
static void
web_process_extension_proxy_created_cb (GDBusProxy *proxy,
GAsyncResult *result,
EphyWebProcessExtensionProxy *web_process_extension)
{
g_autoptr (GError) error = NULL;
web_process_extension->proxy = g_dbus_proxy_new_finish (result, &error);
if (!web_process_extension->proxy) {
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Error creating web process extension proxy: %s", error->message);
/* Attempt to trigger connection_closed_cb, which will emit the
* connection-closed signal, ensuring that EphyEmbedShell will
* remove us from its extensions list.
*/
g_dbus_connection_close (web_process_extension->connection,
web_process_extension->cancellable,
NULL /* GAsyncReadyCallback */,
NULL);
g_object_unref (web_process_extension);
return;
}
web_process_extension->page_created_signal_id =
g_dbus_connection_signal_subscribe (web_process_extension->connection,
NULL,
EPHY_WEB_PROCESS_EXTENSION_INTERFACE,
"PageCreated",
EPHY_WEB_PROCESS_EXTENSION_OBJECT_PATH,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
(GDBusSignalCallback)web_process_extension_page_created,
web_process_extension,
NULL);
g_object_unref (web_process_extension);
}
static void
connection_closed_cb (GDBusConnection *connection,
gboolean remote_peer_vanished,
GError *error,
EphyWebProcessExtensionProxy *web_process_extension)
{
if (error && !remote_peer_vanished)
g_warning ("Unexpectedly lost connection to web process extension: %s", error->message);
g_signal_emit (web_process_extension, signals[CONNECTION_CLOSED], 0);
}
EphyWebProcessExtensionProxy *
ephy_web_process_extension_proxy_new (GDBusConnection *connection)
{
EphyWebProcessExtensionProxy *web_process_extension;
g_assert (G_IS_DBUS_CONNECTION (connection));
web_process_extension = g_object_new (EPHY_TYPE_WEB_PROCESS_EXTENSION_PROXY, NULL);
g_signal_connect (connection, "closed",
G_CALLBACK (connection_closed_cb), web_process_extension);
web_process_extension->cancellable = g_cancellable_new ();
web_process_extension->connection = g_object_ref (connection);
g_dbus_proxy_new (connection,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
NULL,
EPHY_WEB_PROCESS_EXTENSION_OBJECT_PATH,
EPHY_WEB_PROCESS_EXTENSION_INTERFACE,
web_process_extension->cancellable,
(GAsyncReadyCallback)web_process_extension_proxy_created_cb,
g_object_ref (web_process_extension));
return web_process_extension;
}
void
ephy_web_process_extension_proxy_history_set_urls (EphyWebProcessExtensionProxy *web_process_extension,
GList *urls)
{
GList *l;
GVariantBuilder builder;
if (!web_process_extension->proxy)
return;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)"));
for (l = urls; l; l = g_list_next (l)) {
EphyHistoryURL *url = (EphyHistoryURL *)l->data;
g_variant_builder_add (&builder, "(ss)", url->url, url->title);
}
g_dbus_proxy_call (web_process_extension->proxy,
"HistorySetURLs",
g_variant_new ("(@a(ss))", g_variant_builder_end (&builder)),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_history_set_url_thumbnail (EphyWebProcessExtensionProxy *web_process_extension,
const char *url,
const char *path)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"HistorySetURLThumbnail",
g_variant_new ("(ss)", url, path),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_history_set_url_title (EphyWebProcessExtensionProxy *web_process_extension,
const char *url,
const char *title)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"HistorySetURLTitle",
g_variant_new ("(ss)", url, title),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_history_delete_url (EphyWebProcessExtensionProxy *web_process_extension,
const char *url)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"HistoryDeleteURL",
g_variant_new ("(s)", url),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_history_delete_host (EphyWebProcessExtensionProxy *web_process_extension,
const char *host)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"HistoryDeleteHost",
g_variant_new ("(s)", host),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_history_clear (EphyWebProcessExtensionProxy *web_process_extension)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"HistoryClear",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_password_query_usernames_response (EphyWebProcessExtensionProxy *web_process_extension,
GList *users,
gint32 promise_id,
guint64 frame_id)
{
GList *l;
g_auto (GVariantBuilder) builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_STRING_ARRAY);
if (!web_process_extension->proxy)
return;
for (l = users; l != NULL; l = l->next)
g_variant_builder_add (&builder, "s", l->data);
g_dbus_proxy_call (web_process_extension->proxy,
"PasswordQueryUsernamesResponse",
g_variant_new ("(asit)", &builder, promise_id, frame_id),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_password_query_response (EphyWebProcessExtensionProxy *web_process_extension,
const char *username,
const char *password,
gint32 promise_id,
guint64 frame_id)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"PasswordQueryResponse",
g_variant_new ("(ssit)", username ? : "", password ? : "", promise_id, frame_id),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
void
ephy_web_process_extension_proxy_set_should_remember_passwords (EphyWebProcessExtensionProxy *web_process_extension,
gboolean should_remember_passwords)
{
if (!web_process_extension->proxy)
return;
g_dbus_proxy_call (web_process_extension->proxy,
"SetShouldRememberPasswords",
g_variant_new ("(b)", should_remember_passwords),
G_DBUS_CALL_FLAGS_NONE,
-1,
web_process_extension->cancellable,
NULL, NULL);
}
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Copyright © 2014 Igalia S.L.
*
* This file is part of Epiphany.
*
* Epiphany 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, either version 3 of the License, or
* (at your option) any later version.
*
* Epiphany 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 Epiphany. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gio/gio.h>
G_BEGIN_DECLS
#define EPHY_TYPE_WEB_PROCESS_EXTENSION_PROXY (ephy_web_process_extension_proxy_get_type ())
G_DECLARE_FINAL_TYPE (EphyWebProcessExtensionProxy, ephy_web_process_extension_proxy, EPHY, WEB_PROCESS_EXTENSION_PROXY, GObject)
EphyWebProcessExtensionProxy *ephy_web_process_extension_proxy_new (GDBusConnection *connection);
void ephy_web_process_extension_proxy_history_set_urls (EphyWebProcessExtensionProxy *web_process_extension,
GList *urls);
void ephy_web_process_extension_proxy_history_set_url_thumbnail (EphyWebProcessExtensionProxy *web_process_extension,
const char *url,
const char *path);
void ephy_web_process_extension_proxy_history_set_url_title (EphyWebProcessExtensionProxy *web_process_extension,
const char *url,
const char *title);
void ephy_web_process_extension_proxy_history_delete_url (EphyWebProcessExtensionProxy *web_process_extension,
const char *url);
void ephy_web_process_extension_proxy_history_delete_host (EphyWebProcessExtensionProxy *web_process_extension,
const char *host);
void ephy_web_process_extension_proxy_history_clear (EphyWebProcessExtensionProxy *web_process_extension);
void ephy_web_process_extension_proxy_password_query_usernames_response (EphyWebProcessExtensionProxy *web_process_extension,
GList *users,
gint32 promise_id,
guint64 frame_id);
void ephy_web_process_extension_proxy_password_query_response (EphyWebProcessExtensionProxy *web_process_extension,
const char *username,
const char *password,
gint32 promise_id,
guint64 frame_id);
void ephy_web_process_extension_proxy_set_should_remember_passwords (EphyWebProcessExtensionProxy *web_process_extension,
gboolean should_remember_passwords);
G_END_DECLS
......@@ -128,9 +128,6 @@ struct _EphyWebView {
char *tls_error_failing_uri;
EphyWebViewErrorPage error_page;
/* Web Process Extension */
EphyWebProcessExtensionProxy *web_process_extension;
};
typedef struct {
......@@ -899,22 +896,6 @@ allow_unsafe_browsing_cb (EphyEmbedShell *shell,
ephy_web_view_load_url (view, ephy_web_view_get_address (view));
}
static void
page_created_cb (EphyEmbedShell *shell,
guint64 page_id,
EphyWebProcessExtensionProxy *web_process_extension,
EphyWebView *view)
{
if (webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view)) != page_id)
return;
if (view->web_process_extension)
g_object_remove_weak_pointer (G_OBJECT (view->web_process_extension), (gpointer *)&view->web_process_extension);
view->web_process_extension = web_process_extension;
g_object_add_weak_pointer (G_OBJECT (view->web_process_extension), (gpointer *)&view->web_process_extension);
}
static void
ephy_web_view_dispose (GObject *object)
{
......@@ -924,11 +905,6 @@ ephy_web_view_dispose (GObject *object)
ephy_embed_prefs_unregister_ucm (ucm);
ephy_embed_shell_unregister_ucm_handler (ephy_embed_shell_get_default (), ucm);
if (view->web_process_extension) {
g_object_remove_weak_pointer (G_OBJECT (view->web_process_extension), (gpointer *)&view->web_process_extension);
view->web_process_extension = NULL;
}
untrack_info_bar (&view->geolocation_info_bar);
untrack_info_bar (&view->notification_info_bar);
untrack_info_bar (&view->microphone_info_bar);
......@@ -2958,6 +2934,143 @@ authenticate_cb (WebKitWebView *web_view,
return FALSE;
}
typedef struct {
WebKitWebView *web_view;
char *origin;
WebKitUserMessage *message;
} PasswordManagerData;
static void
password_manager_data_free (PasswordManagerData *data)
{
g_object_unref (data->web_view);
g_object_unref (data->message);
g_free (data);
}
static void
password_manager_query_finished_cb (GList *records,
PasswordManagerData *data)
{
EphyPasswordRecord *record;
const char *origin;
const char *username = NULL;
const char *password = NULL;
g_autofree char *real_origin = NULL;
record = records && records->data ? EPHY_PASSWORD_RECORD (records->data) : NULL;
if (record) {
username = ephy_password_record_get_username (record);
password = ephy_password_record_get_password (record);
}
g_variant_get (webkit_user_message_get_parameters (data->message), "(&s@sm@sm@s@s)", &origin, NULL, NULL, NULL, NULL);
real_origin = ephy_uri_to_security_origin (webkit_web_view_get_uri (data->web_view));
if (g_strcmp0 (real_origin, origin) != 0) {
g_debug ("Extension's origin '%s' doesn't match real origin '%s'", origin, real_origin);
password_manager_data_free (data);
return;
}
webkit_user_message_send_reply (data->message,
webkit_user_message_new ("PasswordManager.QueryPasswordResponse",
g_variant_new ("(msms)", username, password)));
password_manager_data_free (data);
}
static gboolean
password_manager_handle_query_usernames_message (WebKitWebView *web_view,
WebKitUserMessage *message)
{
GVariant *parameters;
const char *origin;
EphyPasswordManager *password_manager;
GList *usernames, *l;
GVariantBuilder builder;
g_autofree char *real_origin = NULL;
parameters = webkit_user_message_get_parameters (message);
if (!parameters)
return FALSE;
g_variant_get (parameters, "&s", &origin);
real_origin = ephy_uri_to_security_origin (webkit_web_view_get_uri (web_view));
if (g_strcmp0 (real_origin, origin) != 0) {
g_debug ("Extension's origin '%s' doesn't match real origin '%s'", origin, real_origin);
return FALSE;
}
password_manager = ephy_embed_shell_get_password_manager (ephy_embed_shell_get_default ());
usernames = ephy_password_manager_get_usernames_for_origin (password_manager, origin);
g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
for (l = usernames; l != NULL; l = g_list_next (l))
g_variant_builder_add (&builder, "s", l->data);
webkit_user_message_send_reply (message, webkit_user_message_new ("PasswordManager.QueryUsernamesResponse",
g_variant_builder_end (&builder)));
return TRUE;
}
static gboolean
password_manager_handle_query_password_message (WebKitWebView *web_view,
WebKitUserMessage *message)
{
GVariant *parameters;
const char *origin;
const char *target_origin;
const char *username;
const char *username_field;
const char *password_field;
EphyPasswordManager *password_manager;
PasswordManagerData *data;
parameters = webkit_user_message_get_parameters (message);
if (!parameters)
return FALSE;
g_variant_get (parameters, "(&s&sm&sm&s&s)", &origin, &target_origin, &username, &username_field, &password_field);
/* Don't include username_field in queries unless we actually have a username
* to go along with it, or the query will fail because we don't save
* username_field without a corresponding username.
*/
if (!username && username_field)
username_field = NULL;
data = g_new (PasswordManagerData, 1);
data->web_view = g_object_ref (web_view);
data->message = g_object_ref (message);
password_manager = ephy_embed_shell_get_password_manager (ephy_embed_shell_get_default ());
ephy_password_manager_query (password_manager,
NULL,
origin,
target_origin,
username,
username_field,
password_field,
(EphyPasswordManagerQueryCallback)password_manager_query_finished_cb,
data);
return TRUE;
}
static gboolean
user_message_received_cb (WebKitWebView *web_view,
WebKitUserMessage *message)
{
const char *name;
name = webkit_user_message_get_name (message);
if (g_strcmp0 (name, "PasswordManager.QueryUsernames") == 0)
return password_manager_handle_query_usernames_message (web_view, message);
if (g_strcmp0 (name, "PasswordManager.QueryPassword") == 0)
return password_manager_handle_query_password_message (web_view, message);
return FALSE;
}
static void
ephy_web_view_init (EphyWebView *web_view)
{
......@@ -3042,9 +3155,9 @@ ephy_web_view_init (EphyWebView *web_view)
G_CALLBACK (authenticate_cb),
NULL);
g_signal_connect_object (shell, "page-created",
G_CALLBACK (page_created_cb),
web_view, 0);
g_signal_connect (web_view, "user-message-received",
G_CALLBACK (user_message_received_cb),
NULL);
g_signal_connect_object (shell, "password-form-focused",
G_CALLBACK (password_form_focused_cb),
......@@ -4028,12 +4141,6 @@ ephy_web_view_get_reader_mode_state (EphyWebView *view)
return view->reader_active;
}
EphyWebProcessExtensionProxy *
ephy_web_view_get_web_process_extension_proxy (EphyWebView *view)
{
return view->web_process_extension;
}
gboolean
ephy_web_view_is_in_auth_dialog (EphyWebView *view)
{
......
......@@ -26,7 +26,6 @@
#include "ephy-embed-shell.h"
#include "ephy-history-types.h"
#include "ephy-security-levels.h"
#include "ephy-web-process-extension-proxy.h"
G_BEGIN_DECLS
......@@ -166,8 +165,6 @@ gboolean ephy_web_view_get_reader_mode_state (EphyWebView
gboolean ephy_web_view_is_in_auth_dialog (EphyWebView *view);
EphyWebProcessExtensionProxy *ephy_web_view_get_web_process_extension_proxy (EphyWebView *view);
void ephy_web_view_show_auth_form_save_request (EphyWebView *web_view,
const char *origin,
const char *username,
......
......@@ -28,7 +28,6 @@ libephyembed_sources = [
'ephy-find-toolbar.c',
'ephy-view-source-handler.c',
'ephy-web-view.c',
'ephy-web-process-extension-proxy.c',
enums
]
......
......@@ -36,18 +36,12 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *webkit_exten
GVariant *user_data)
{
const char *guid;
const char *server_address;
const char *profile_dir;
gboolean private_profile;
gboolean should_remember_passwords;
g_autoptr (GError) error = NULL;
g_variant_get (user_data, "(&sm&sm&sbb)", &guid, &server_address, &profile_dir, &should_remember_passwords, &private_profile);
if (!server_address) {
g_warning ("UI process did not start D-Bus server, giving up.");
return;
}
g_variant_get (user_data, "(&sm&sbb)", &guid, &profile_dir, &should_remember_passwords, &private_profile);
if (!ephy_file_helpers_init (profile_dir, 0, &error))
g_warning ("Failed to initialize file helpers: %s", error->message);
......@@ -62,7 +56,6 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *webkit_exten
ephy_web_process_extension_initialize (extension,
webkit_extension,
guid,
server_address,
should_remember_passwords,
private_profile);
}
......
......@@ -33,7 +33,6 @@ EphyWebProcessExtension *ephy_web_process_extension_get (void);
void ephy_web_process_extension_initialize (EphyWebProcessExtension *extension,
WebKitWebExtension *wk_extension,
const char *guid,
const char *server_address,
gboolean should_remember_passwords,
gboolean is_private_profile);
......
......@@ -345,10 +345,7 @@ Ephy.PasswordManager = class PasswordManager
{
return new Promise((resolver, reject) => {
let promiseID = this._promiseCounter++;
window.webkit.messageHandlers.passwordManagerQuery.postMessage({
origin, targetOrigin, username, usernameField, passwordField, promiseID,
pageID: this._pageID, frameID: this._frameID
});
Ephy.queryPassword(origin, targetOrigin, username, usernameField, passwordField, promiseID, this._pageID, this._frameID);
this._pendingPromises.push({promiseID, resolver});
});
}
......@@ -381,9 +378,7 @@ Ephy.PasswordManager = class PasswordManager
{
return new Promise((resolver, reject) => {
let promiseID = this._promiseCounter++;
window.webkit.messageHandlers.passwordManagerQueryUsernames.postMessage({
origin, promiseID, pageID: this._pageID, frameID: this._frameID
});
Ephy.queryUsernames(origin, promiseID, this._pageID, this._frameID);
this._pendingPromises.push({promiseID, resolver});
});
}
......
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Copyright © 2014 Igalia S.L.
*